@remotion/renderer 4.0.214 → 4.0.216

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/Cargo.lock CHANGED
@@ -36,22 +36,20 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
36
36
 
37
37
  [[package]]
38
38
  name = "bindgen"
39
- version = "0.64.0"
39
+ version = "0.70.1"
40
40
  source = "registry+https://github.com/rust-lang/crates.io-index"
41
- checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
41
+ checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
42
42
  dependencies = [
43
- "bitflags",
43
+ "bitflags 2.6.0",
44
44
  "cexpr",
45
45
  "clang-sys",
46
- "lazy_static",
47
- "lazycell",
48
- "peeking_take_while",
46
+ "itertools",
49
47
  "proc-macro2",
50
48
  "quote",
51
49
  "regex",
52
50
  "rustc-hash",
53
51
  "shlex",
54
- "syn 1.0.109",
52
+ "syn",
55
53
  ]
56
54
 
57
55
  [[package]]
@@ -66,6 +64,12 @@ version = "1.3.2"
66
64
  source = "registry+https://github.com/rust-lang/crates.io-index"
67
65
  checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
68
66
 
67
+ [[package]]
68
+ name = "bitflags"
69
+ version = "2.6.0"
70
+ source = "registry+https://github.com/rust-lang/crates.io-index"
71
+ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
72
+
69
73
  [[package]]
70
74
  name = "block"
71
75
  version = "0.1.6"
@@ -92,9 +96,12 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
92
96
 
93
97
  [[package]]
94
98
  name = "cc"
95
- version = "1.0.79"
99
+ version = "1.1.24"
96
100
  source = "registry+https://github.com/rust-lang/crates.io-index"
97
- checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
101
+ checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
102
+ dependencies = [
103
+ "shlex",
104
+ ]
98
105
 
99
106
  [[package]]
100
107
  name = "cexpr"
@@ -161,7 +168,7 @@ version = "0.22.3"
161
168
  source = "registry+https://github.com/rust-lang/crates.io-index"
162
169
  checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
163
170
  dependencies = [
164
- "bitflags",
171
+ "bitflags 1.3.2",
165
172
  "core-foundation",
166
173
  "core-graphics-types",
167
174
  "foreign-types",
@@ -174,7 +181,7 @@ version = "0.1.2"
174
181
  source = "registry+https://github.com/rust-lang/crates.io-index"
175
182
  checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33"
176
183
  dependencies = [
177
- "bitflags",
184
+ "bitflags 1.3.2",
178
185
  "core-foundation",
179
186
  "libc",
180
187
  ]
@@ -270,18 +277,18 @@ dependencies = [
270
277
 
271
278
  [[package]]
272
279
  name = "ffmpeg-next"
273
- version = "6.0.0"
274
- source = "git+https://github.com/remotion-dev/rust-ffmpeg?rev=4027d3764d54c6c71ab72ff076764ae7abe91428#4027d3764d54c6c71ab72ff076764ae7abe91428"
280
+ version = "7.1.0"
281
+ source = "git+https://github.com/remotion-dev/rust-ffmpeg?rev=7390be48beef9dc1e9433532abcac4d431ccc362#7390be48beef9dc1e9433532abcac4d431ccc362"
275
282
  dependencies = [
276
- "bitflags",
283
+ "bitflags 2.6.0",
277
284
  "ffmpeg-sys-next",
278
285
  "libc",
279
286
  ]
280
287
 
281
288
  [[package]]
282
289
  name = "ffmpeg-sys-next"
283
- version = "6.0.1"
284
- source = "git+https://github.com/remotion-dev/rust-ffmpeg-sys?rev=7da943df1ea7be22868b3f8e236b6a9f5b8c1559#7da943df1ea7be22868b3f8e236b6a9f5b8c1559"
290
+ version = "7.1.0"
291
+ source = "git+https://github.com/remotion-dev/rust-ffmpeg-sys?rev=6721c2055a15717f74d03685e7179cfdc6d677a8#6721c2055a15717f74d03685e7179cfdc6d677a8"
285
292
  dependencies = [
286
293
  "bindgen",
287
294
  "cc",
@@ -377,12 +384,9 @@ dependencies = [
377
384
 
378
385
  [[package]]
379
386
  name = "hermit-abi"
380
- version = "0.2.6"
387
+ version = "0.3.9"
381
388
  source = "registry+https://github.com/rust-lang/crates.io-index"
382
- checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
383
- dependencies = [
384
- "libc",
385
- ]
389
+ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
386
390
 
387
391
  [[package]]
388
392
  name = "image"
@@ -403,6 +407,15 @@ dependencies = [
403
407
  "tiff",
404
408
  ]
405
409
 
410
+ [[package]]
411
+ name = "itertools"
412
+ version = "0.13.0"
413
+ source = "registry+https://github.com/rust-lang/crates.io-index"
414
+ checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
415
+ dependencies = [
416
+ "either",
417
+ ]
418
+
406
419
  [[package]]
407
420
  name = "itoa"
408
421
  version = "1.0.6"
@@ -430,12 +443,6 @@ version = "1.4.0"
430
443
  source = "registry+https://github.com/rust-lang/crates.io-index"
431
444
  checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
432
445
 
433
- [[package]]
434
- name = "lazycell"
435
- version = "1.3.0"
436
- source = "registry+https://github.com/rust-lang/crates.io-index"
437
- checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
438
-
439
446
  [[package]]
440
447
  name = "lebe"
441
448
  version = "0.5.2"
@@ -551,7 +558,7 @@ version = "0.24.3"
551
558
  source = "registry+https://github.com/rust-lang/crates.io-index"
552
559
  checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
553
560
  dependencies = [
554
- "bitflags",
561
+ "bitflags 1.3.2",
555
562
  "cfg-if",
556
563
  "libc",
557
564
  "memoffset 0.6.5",
@@ -621,9 +628,9 @@ dependencies = [
621
628
 
622
629
  [[package]]
623
630
  name = "num_cpus"
624
- version = "1.15.0"
631
+ version = "1.16.0"
625
632
  source = "registry+https://github.com/rust-lang/crates.io-index"
626
- checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
633
+ checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
627
634
  dependencies = [
628
635
  "hermit-abi",
629
636
  "libc",
@@ -687,12 +694,6 @@ dependencies = [
687
694
  "windows-targets 0.48.0",
688
695
  ]
689
696
 
690
- [[package]]
691
- name = "peeking_take_while"
692
- version = "0.1.2"
693
- source = "registry+https://github.com/rust-lang/crates.io-index"
694
- checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
695
-
696
697
  [[package]]
697
698
  name = "pkg-config"
698
699
  version = "0.3.26"
@@ -705,7 +706,7 @@ version = "0.17.13"
705
706
  source = "registry+https://github.com/rust-lang/crates.io-index"
706
707
  checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1"
707
708
  dependencies = [
708
- "bitflags",
709
+ "bitflags 1.3.2",
709
710
  "crc32fast",
710
711
  "fdeflate",
711
712
  "flate2",
@@ -765,7 +766,7 @@ version = "0.2.16"
765
766
  source = "registry+https://github.com/rust-lang/crates.io-index"
766
767
  checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
767
768
  dependencies = [
768
- "bitflags",
769
+ "bitflags 1.3.2",
769
770
  ]
770
771
 
771
772
  [[package]]
@@ -774,7 +775,7 @@ version = "0.3.5"
774
775
  source = "registry+https://github.com/rust-lang/crates.io-index"
775
776
  checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
776
777
  dependencies = [
777
- "bitflags",
778
+ "bitflags 1.3.2",
778
779
  ]
779
780
 
780
781
  [[package]]
@@ -845,7 +846,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585"
845
846
  dependencies = [
846
847
  "proc-macro2",
847
848
  "quote",
848
- "syn 2.0.13",
849
+ "syn",
849
850
  ]
850
851
 
851
852
  [[package]]
@@ -892,17 +893,6 @@ version = "1.0.6"
892
893
  source = "registry+https://github.com/rust-lang/crates.io-index"
893
894
  checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
894
895
 
895
- [[package]]
896
- name = "syn"
897
- version = "1.0.109"
898
- source = "registry+https://github.com/rust-lang/crates.io-index"
899
- checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
900
- dependencies = [
901
- "proc-macro2",
902
- "quote",
903
- "unicode-ident",
904
- ]
905
-
906
896
  [[package]]
907
897
  name = "syn"
908
898
  version = "2.0.13"
@@ -957,7 +947,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
957
947
  dependencies = [
958
948
  "proc-macro2",
959
949
  "quote",
960
- "syn 2.0.13",
950
+ "syn",
961
951
  ]
962
952
 
963
953
  [[package]]
package/Cargo.toml CHANGED
@@ -19,7 +19,7 @@ image = "0.24.7"
19
19
  arboard = "3.2.0"
20
20
  sysinfo = "0.30.7"
21
21
  mp4 = {git = "https://github.com/jonnyburger/mp4-rust", rev = "92ba375738cc2f05a4d754e1f968cf2e97d06641"}
22
- ffmpeg-next = {git = "https://github.com/remotion-dev/rust-ffmpeg", rev ="4027d3764d54c6c71ab72ff076764ae7abe91428"}
22
+ ffmpeg-next = {git = "https://github.com/remotion-dev/rust-ffmpeg", rev ="7390be48beef9dc1e9433532abcac4d431ccc362"}
23
23
 
24
24
  [[bin]]
25
25
  name = "remotion"
package/build.ts ADDED
@@ -0,0 +1,311 @@
1
+ import {execSync} from 'node:child_process';
2
+ import {
3
+ copyFileSync,
4
+ existsSync,
5
+ lstatSync,
6
+ mkdirSync,
7
+ readdirSync,
8
+ renameSync,
9
+ rmdirSync,
10
+ rmSync,
11
+ statSync,
12
+ unlinkSync,
13
+ } from 'node:fs';
14
+ import os from 'node:os';
15
+ import path from 'node:path';
16
+ import {toolchains} from './toolchains.mjs';
17
+
18
+ const isWin = os.platform() === 'win32';
19
+ const where = isWin ? 'where' : 'which';
20
+
21
+ if (os.platform() === 'win32') {
22
+ console.log('Windows CI is broken - needs to be cross-compiled');
23
+ process.exit(0);
24
+ }
25
+
26
+ function isMusl() {
27
+ // @ts-expect-error
28
+ const {glibcVersionRuntime} = process.report.getReport().header;
29
+ return !glibcVersionRuntime;
30
+ }
31
+
32
+ const targets = [
33
+ 'x86_64-pc-windows-gnu',
34
+ 'x86_64-unknown-linux-musl',
35
+ 'aarch64-unknown-linux-gnu',
36
+ 'x86_64-unknown-linux-gnu',
37
+ 'aarch64-apple-darwin',
38
+ 'x86_64-apple-darwin',
39
+ 'aarch64-unknown-linux-musl',
40
+ ];
41
+
42
+ export const getTarget = () => {
43
+ switch (process.platform) {
44
+ case 'win32':
45
+ switch (process.arch) {
46
+ case 'x64':
47
+ return 'x86_64-pc-windows-gnu';
48
+ default:
49
+ throw new Error(
50
+ `Unsupported architecture on Windows: ${process.arch}`,
51
+ );
52
+ }
53
+
54
+ case 'darwin':
55
+ switch (process.arch) {
56
+ case 'x64':
57
+ return 'x86_64-apple-darwin';
58
+ case 'arm64':
59
+ return 'aarch64-apple-darwin';
60
+ default:
61
+ throw new Error(`Unsupported architecture on macOS: ${process.arch}`);
62
+ }
63
+
64
+ case 'linux':
65
+ switch (process.arch) {
66
+ case 'x64':
67
+ if (isMusl()) {
68
+ return 'x86_64-unknown-linux-musl';
69
+ }
70
+
71
+ return 'x86_64-unknown-linux-gnu';
72
+ case 'arm64':
73
+ if (isMusl()) {
74
+ return 'aarch64-unknown-linux-musl';
75
+ }
76
+
77
+ return 'aarch64-unknown-linux-gnu';
78
+
79
+ default:
80
+ throw new Error(`Unsupported architecture on Linux: ${process.arch}`);
81
+ }
82
+
83
+ default:
84
+ throw new Error(
85
+ `Unsupported OS: ${process.platform}, architecture: ${process.arch}`,
86
+ );
87
+ }
88
+ };
89
+
90
+ const hasCargo = () => {
91
+ try {
92
+ execSync(`${where} cargo`);
93
+ return true;
94
+ } catch (err) {
95
+ return false;
96
+ }
97
+ };
98
+
99
+ const debug = process.argv.includes('--debug');
100
+ const mode = debug ? 'debug' : 'release';
101
+
102
+ const copyDestinations = {
103
+ 'aarch64-unknown-linux-gnu': {
104
+ from: `target/aarch64-unknown-linux-gnu/${mode}/remotion`,
105
+ to: '../compositor-linux-arm64-gnu/remotion',
106
+ dir: '../compositor-linux-arm64-gnu',
107
+ },
108
+ 'aarch64-unknown-linux-musl': {
109
+ from: `target/aarch64-unknown-linux-musl/${mode}/remotion`,
110
+ to: '../compositor-linux-arm64-musl/remotion',
111
+ dir: '../compositor-linux-arm64-musl',
112
+ },
113
+ 'x86_64-unknown-linux-gnu': {
114
+ from: `target/x86_64-unknown-linux-gnu/${mode}/remotion`,
115
+ to: '../compositor-linux-x64-gnu/remotion',
116
+ dir: '../compositor-linux-x64-gnu',
117
+ },
118
+ 'x86_64-unknown-linux-musl': {
119
+ from: `target/x86_64-unknown-linux-musl/${mode}/remotion`,
120
+ to: '../compositor-linux-x64-musl/remotion',
121
+ dir: '../compositor-linux-x64-musl',
122
+ },
123
+ 'x86_64-apple-darwin': {
124
+ from: `target/x86_64-apple-darwin/${mode}/remotion`,
125
+ to: '../compositor-darwin-x64/remotion',
126
+ dir: '../compositor-darwin-x64',
127
+ },
128
+ 'aarch64-apple-darwin': {
129
+ from: `target/aarch64-apple-darwin/${mode}/remotion`,
130
+ to: '../compositor-darwin-arm64/remotion',
131
+ dir: '../compositor-darwin-arm64',
132
+ },
133
+ 'x86_64-pc-windows-gnu': {
134
+ from: `target/x86_64-pc-windows-gnu/${mode}/remotion.exe`,
135
+ to: '../compositor-win32-x64-msvc/remotion.exe',
136
+ dir: '../compositor-win32-x64-msvc',
137
+ },
138
+ };
139
+
140
+ if (!hasCargo()) {
141
+ console.log('Environment has no cargo. Skipping Rust builds.');
142
+ process.exit(0);
143
+ }
144
+
145
+ const nativeArch = getTarget();
146
+
147
+ const all = process.argv.includes('--all');
148
+ const cloudrun = process.argv.includes('--cloudrun');
149
+ const lambda = process.argv.includes('--lambda');
150
+ if (!existsSync('toolchains') && all) {
151
+ throw new Error(
152
+ 'Run "node install-toolchain.mjs" if you want to build all platforms',
153
+ );
154
+ }
155
+
156
+ for (const toolchain of toolchains) {
157
+ if (!existsSync(path.join('toolchains', toolchain)) && all) {
158
+ throw new Error(
159
+ `Toolchain for ${toolchain} not found. Run "node install-toolchain.mjs" if you want to build all platforms`,
160
+ );
161
+ }
162
+ }
163
+
164
+ const stdout = execSync('cargo metadata --format-version=1');
165
+ const {packages} = JSON.parse(stdout as unknown as string);
166
+
167
+ const rustFfmpegSys = packages.find((p) => p.name === 'ffmpeg-sys-next');
168
+
169
+ if (!rustFfmpegSys) {
170
+ console.error(
171
+ 'Could not find ffmpeg-sys-next when running cargo metadata --format-version=1',
172
+ );
173
+ process.exit(1);
174
+ }
175
+
176
+ const manifest = rustFfmpegSys.manifest_path;
177
+ const binariesDirectory = path.join(path.dirname(manifest), 'zips');
178
+ const archs = all
179
+ ? targets
180
+ : lambda
181
+ ? ['aarch64-unknown-linux-gnu']
182
+ : cloudrun
183
+ ? ['x86_64-unknown-linux-gnu']
184
+ : [nativeArch];
185
+
186
+ for (const arch of archs) {
187
+ const ffmpegFolder = path.join(copyDestinations[arch].dir, 'ffmpeg');
188
+ if (existsSync(ffmpegFolder)) {
189
+ rmSync(ffmpegFolder, {recursive: true});
190
+ }
191
+
192
+ mkdirSync(ffmpegFolder);
193
+
194
+ // strip-components: extract in a flat folder structure
195
+ execSync(
196
+ `tar xf ${binariesDirectory}/${arch}.gz -C ${ffmpegFolder} --strip-components 2`,
197
+ {
198
+ stdio: 'inherit',
199
+ },
200
+ );
201
+ const filesInFfmpegFolder = readdirSync(ffmpegFolder);
202
+ const filesToDelete = filesInFfmpegFolder.filter((file) => {
203
+ return (
204
+ file.endsWith('.h') ||
205
+ file.endsWith('.a') ||
206
+ file.endsWith('.la') ||
207
+ file.endsWith('.hpp') ||
208
+ statSync(path.join(ffmpegFolder, file)).isDirectory()
209
+ );
210
+ });
211
+ for (const file of filesToDelete) {
212
+ rmSync(path.join(ffmpegFolder, file), {recursive: true});
213
+ }
214
+
215
+ const filesInFfmpegFolder2 = readdirSync(ffmpegFolder);
216
+ for (const file of filesInFfmpegFolder2) {
217
+ if (file === 'ffmpeg') {
218
+ renameSync(
219
+ path.join(ffmpegFolder, file),
220
+ path.join(ffmpegFolder, '..', 'ffmpeg_'),
221
+ );
222
+ continue;
223
+ }
224
+
225
+ renameSync(
226
+ path.join(ffmpegFolder, file),
227
+ path.join(ffmpegFolder, '..', file),
228
+ );
229
+ }
230
+
231
+ rmdirSync(path.join(ffmpegFolder, '..', 'ffmpeg'));
232
+ if (existsSync(path.join(ffmpegFolder, '..', 'bin'))) {
233
+ rmSync(path.join(ffmpegFolder, '..', 'bin'), {recursive: true});
234
+ }
235
+
236
+ if (existsSync(path.join(ffmpegFolder, '..', 'ffmpeg_'))) {
237
+ renameSync(
238
+ path.join(ffmpegFolder, '..', 'ffmpeg_'),
239
+ path.join(ffmpegFolder, '..', 'ffmpeg'),
240
+ );
241
+ }
242
+
243
+ const command = `cargo build ${debug ? '' : '--release'} --target=${arch}`;
244
+ console.log(command);
245
+
246
+ // debuginfo will keep symbols, which are used for backtrace.
247
+ // symbols makes it a tiny bit smaller, but error messages will be hard to debug.
248
+
249
+ const rPathOrigin = arch.includes('linux')
250
+ ? `-C link-args=-Wl,-rpath,'$ORIGIN'`
251
+ : '';
252
+
253
+ const optimizations = all
254
+ ? `-C opt-level=3 -C lto=fat -C strip=debuginfo -C embed-bitcode=yes ${rPathOrigin}`
255
+ : '';
256
+
257
+ execSync(command, {
258
+ stdio: 'inherit',
259
+ env: {
260
+ ...process.env,
261
+ RUSTFLAGS: optimizations,
262
+ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER:
263
+ nativeArch === 'aarch64-unknown-linux-gnu'
264
+ ? undefined
265
+ : 'toolchains/aarch64_gnu_toolchain/bin/aarch64-unknown-linux-gnu-gcc',
266
+ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER:
267
+ nativeArch === 'aarch64-unknown-linux-musl'
268
+ ? undefined
269
+ : 'toolchains/aarch64_musl_toolchain/bin/aarch64-unknown-linux-musl-gcc',
270
+ CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER:
271
+ nativeArch === 'x86_64-unknown-linux-gnu'
272
+ ? undefined
273
+ : path.join(
274
+ process.cwd(),
275
+ 'toolchains/x86_64_gnu_toolchain/bin/x86_64-unknown-linux-gnu-gcc',
276
+ ),
277
+ CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER:
278
+ nativeArch === 'x86_64-unknown-linux-musl'
279
+ ? undefined
280
+ : 'toolchains/x86_64_musl_toolchain/bin/x86_64-unknown-linux-musl-gcc',
281
+ },
282
+ });
283
+ const copyInstructions = copyDestinations[arch];
284
+
285
+ copyFileSync(copyInstructions.from, copyInstructions.to);
286
+
287
+ const output = execSync('npm pack --json', {
288
+ cwd: copyDestinations[arch].dir,
289
+ stdio: 'pipe',
290
+ });
291
+
292
+ const filename = JSON.parse(output.toString('utf-8'))[0].filename.replace(
293
+ /^@remotion\//,
294
+ 'remotion-',
295
+ );
296
+ const tgzPath = path.join(
297
+ process.cwd(),
298
+ copyDestinations[arch].dir,
299
+ filename,
300
+ );
301
+
302
+ if (arch.includes('linux')) {
303
+ execSync(
304
+ `patchelf --force-rpath --set-rpath '$ORIGIN' ${copyDestinations[arch].dir}/remotion`,
305
+ );
306
+ }
307
+
308
+ const filesize = lstatSync(tgzPath).size;
309
+ console.log('Zipped size:', (filesize / 1000000).toFixed(2) + 'MB');
310
+ unlinkSync(tgzPath);
311
+ }
@@ -0,0 +1 @@
1
+ export declare const isTargetClosedErr: (error: Error | undefined) => boolean | undefined;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isTargetClosedErr = void 0;
4
+ const isTargetClosedErr = (error) => {
5
+ var _a, _b;
6
+ return (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('Target closed')) ||
7
+ ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('Session closed')));
8
+ };
9
+ exports.isTargetClosedErr = isTargetClosedErr;
package/dist/client.d.ts CHANGED
@@ -393,7 +393,7 @@ export declare const BrowserSafeApis: {
393
393
  webhookCustomDataOption: {
394
394
  name: string;
395
395
  cliFlag: "webhook-custom-data";
396
- description: (type: "cli" | "ssr") => import("react/jsx-runtime").JSX.Element;
396
+ description: (type: "ssr" | "cli") => import("react/jsx-runtime").JSX.Element;
397
397
  ssrName: "customData";
398
398
  docLink: string;
399
399
  type: Record<string, unknown> | null;
@@ -803,6 +803,23 @@ export declare const BrowserSafeApis: {
803
803
  ssrName: string;
804
804
  type: boolean;
805
805
  };
806
+ metadataOption: {
807
+ name: string;
808
+ cliFlag: "metadata";
809
+ description: (mode: "ssr" | "cli") => import("react/jsx-runtime").JSX.Element;
810
+ docLink: string;
811
+ type: import("./options/metadata").Metadata;
812
+ getValue: ({ commandLine }: {
813
+ commandLine: Record<string, unknown>;
814
+ }) => {
815
+ source: string;
816
+ value: {
817
+ [k: string]: string;
818
+ };
819
+ };
820
+ setConfig: (newMetadata: import("./options/metadata").Metadata) => void;
821
+ ssrName: string;
822
+ };
806
823
  };
807
824
  validColorSpaces: readonly ["default", "bt709", "bt2020-ncl"];
808
825
  optionsMap: {
@@ -21,6 +21,7 @@ type Options = {
21
21
  seamlessAudio: boolean;
22
22
  seamlessVideo: boolean;
23
23
  muted: boolean;
24
+ metadata: Record<string, string> | null;
24
25
  };
25
- export declare const combineChunks: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, muted, }: Options) => Promise<void>;
26
+ export declare const combineChunks: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, muted, metadata, }: Options) => Promise<void>;
26
27
  export {};
@@ -25,7 +25,7 @@ const codecSupportsFastStart = {
25
25
  vp9: false,
26
26
  wav: false,
27
27
  };
28
- const combineChunks = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, muted, }) => {
28
+ const combineChunks = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, muted, metadata, }) => {
29
29
  const shouldCreateAudio = resolvedAudioCodec !== null && !muted;
30
30
  const shouldCreateVideo = !(0, audio_codec_1.isAudioCodec)(codec);
31
31
  const videoOutput = shouldCreateVideo
@@ -114,6 +114,7 @@ const combineChunks = async ({ files, filelistDir, output, onProgress, numberOfF
114
114
  fps,
115
115
  cancelSignal,
116
116
  addFaststart: codecSupportsFastStart[codec],
117
+ metadata,
117
118
  });
118
119
  onProgress(numberOfFrames);
119
120
  (0, node_fs_1.rmSync)(filelistDir, { recursive: true });
@@ -13,6 +13,6 @@ export declare const getPageAndCleanupFn: ({ passedInInstance, browserExecutable
13
13
  logLevel: LogLevel;
14
14
  onBrowserDownload: OnBrowserDownload;
15
15
  }) => Promise<{
16
- cleanup: () => Promise<void>;
16
+ cleanupPage: () => Promise<void>;
17
17
  page: Page;
18
18
  }>;
@@ -8,7 +8,7 @@ const getPageAndCleanupFn = async ({ passedInInstance, browserExecutable, chromi
8
8
  const page = await passedInInstance.newPage(() => null, logLevel, indent);
9
9
  return {
10
10
  page,
11
- cleanup: () => {
11
+ cleanupPage: () => {
12
12
  // Close puppeteer page and don't wait for it to finish.
13
13
  // Keep browser open.
14
14
  page.close().catch((err) => {
@@ -33,7 +33,7 @@ const getPageAndCleanupFn = async ({ passedInInstance, browserExecutable, chromi
33
33
  const browserPage = await browserInstance.newPage(() => null, logLevel, indent);
34
34
  return {
35
35
  page: browserPage,
36
- cleanup: () => {
36
+ cleanupPage: () => {
37
37
  // Close whole browser that was just created and don't wait for it to finish.
38
38
  browserInstance.close(true, logLevel, indent).catch((err) => {
39
39
  if (!err.message.includes('Target closed')) {
@@ -82,7 +82,7 @@ const innerGetCompositions = async ({ envVariables, serializedInputPropsWithCust
82
82
  });
83
83
  };
84
84
  const internalGetCompositionsRaw = async ({ browserExecutable, chromiumOptions, envVariables, indent, serializedInputPropsWithCustomSchema, onBrowserLog, port, puppeteerInstance, serveUrlOrWebpackUrl, server, timeoutInMilliseconds, logLevel, offthreadVideoCacheSizeInBytes, binariesDirectory, onBrowserDownload, }) => {
85
- const { page, cleanup: cleanupPage } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
85
+ const { page, cleanupPage } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
86
86
  passedInInstance: puppeteerInstance,
87
87
  browserExecutable,
88
88
  chromiumOptions,
package/dist/index.d.ts CHANGED
@@ -157,7 +157,7 @@ export declare const RenderInternals: {
157
157
  }) => number;
158
158
  findRemotionRoot: () => string;
159
159
  validateBitrate: (bitrate: unknown, name: string) => void;
160
- combineChunks: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, muted, }: {
160
+ combineChunks: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, resolvedAudioCodec, audioBitrate, indent, logLevel, chunkDurationInSeconds, binariesDirectory, cancelSignal, seamlessAudio, seamlessVideo, muted, metadata, }: {
161
161
  files: string[];
162
162
  filelistDir: string;
163
163
  output: string;
@@ -176,6 +176,7 @@ export declare const RenderInternals: {
176
176
  seamlessAudio: boolean;
177
177
  seamlessVideo: boolean;
178
178
  muted: boolean;
179
+ metadata: Record<string, string> | null;
179
180
  }) => Promise<void>;
180
181
  getMinConcurrency: () => number;
181
182
  getMaxConcurrency: () => number;
@@ -352,8 +353,8 @@ export declare const RenderInternals: {
352
353
  }) => execa.ExecaChildProcess<string>;
353
354
  validStillImageFormats: readonly ["png", "jpeg", "pdf", "webp"];
354
355
  validVideoImageFormats: readonly ["png", "jpeg", "none"];
355
- DEFAULT_STILL_IMAGE_FORMAT: "jpeg" | "png" | "webp" | "pdf";
356
- DEFAULT_VIDEO_IMAGE_FORMAT: "jpeg" | "png" | "none";
356
+ DEFAULT_STILL_IMAGE_FORMAT: "png" | "jpeg" | "pdf" | "webp";
357
+ DEFAULT_VIDEO_IMAGE_FORMAT: "png" | "jpeg" | "none";
357
358
  DEFAULT_JPEG_QUALITY: number;
358
359
  chalk: {
359
360
  enabled: () => boolean;
@@ -0,0 +1,2 @@
1
+ export declare const isDelayRenderErrorWithRetry: (error: Error | undefined) => boolean | undefined;
2
+ export declare const getRetriesLeftFromError: (error: Error | undefined) => number;
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getRetriesLeftFromError = exports.isDelayRenderErrorWithRetry = void 0;
4
+ const no_react_1 = require("remotion/no-react");
5
+ const isDelayRenderErrorWithRetry = (error) => {
6
+ var _a;
7
+ if (!error) {
8
+ return false;
9
+ }
10
+ const shouldRetryError = (_a = error.stack) === null || _a === void 0 ? void 0 : _a.includes(no_react_1.NoReactInternals.DELAY_RENDER_RETRY_TOKEN);
11
+ return shouldRetryError;
12
+ };
13
+ exports.isDelayRenderErrorWithRetry = isDelayRenderErrorWithRetry;
14
+ const getRetriesLeftFromError = (error) => {
15
+ if (!error) {
16
+ throw new Error('Expected stack');
17
+ }
18
+ const { stack } = error;
19
+ if (!stack) {
20
+ throw new Error('Expected stack: ' + JSON.stringify(error));
21
+ }
22
+ const beforeIndex = stack.indexOf(no_react_1.NoReactInternals.DELAY_RENDER_ATTEMPT_TOKEN);
23
+ if (beforeIndex === -1) {
24
+ throw new Error('Expected to find attempt token in stack');
25
+ }
26
+ const afterIndex = stack.indexOf(no_react_1.NoReactInternals.DELAY_RENDER_RETRY_TOKEN);
27
+ if (afterIndex === -1) {
28
+ throw new Error('Expected to find retry token in stack');
29
+ }
30
+ const inbetween = stack.substring(beforeIndex + no_react_1.NoReactInternals.DELAY_RENDER_ATTEMPT_TOKEN.length, afterIndex);
31
+ const parsed = Number(inbetween);
32
+ if (Number.isNaN(parsed)) {
33
+ throw new Error(`Expected to find a number in the stack ${stack}`);
34
+ }
35
+ return parsed;
36
+ };
37
+ exports.getRetriesLeftFromError = getRetriesLeftFromError;
@@ -0,0 +1,2 @@
1
+ import type { Metadata } from './options/metadata';
2
+ export declare const makeMetadataArgs: (metadata: Metadata) => string[];
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.makeMetadataArgs = void 0;
4
+ const version_1 = require("remotion/version");
5
+ const makeMetadataArgs = (metadata) => {
6
+ const defaultComment = `Made with Remotion ${version_1.VERSION}`;
7
+ const newMetadata = {
8
+ comment: defaultComment,
9
+ };
10
+ Object.keys(metadata).forEach((key) => {
11
+ const lowercaseKey = key.toLowerCase();
12
+ if (lowercaseKey === 'comment') {
13
+ newMetadata[lowercaseKey] = `${defaultComment}; ${metadata[key]}`;
14
+ }
15
+ else {
16
+ newMetadata[lowercaseKey] = metadata[key];
17
+ }
18
+ });
19
+ const metadataArgs = Object.entries(newMetadata).map(([key, value]) => ['-metadata', `${key}=${value}`]);
20
+ return metadataArgs.flat(1);
21
+ };
22
+ exports.makeMetadataArgs = makeMetadataArgs;
@@ -1,6 +1,6 @@
1
1
  import type { LogLevel } from './log-level';
2
2
  import type { CancelSignal } from './make-cancel-signal';
3
- export declare const muxVideoAndAudio: ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, addFaststart, }: {
3
+ export declare const muxVideoAndAudio: ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, addFaststart, metadata, }: {
4
4
  videoOutput: string | null;
5
5
  audioOutput: string | null;
6
6
  output: string;
@@ -11,4 +11,5 @@ export declare const muxVideoAndAudio: ({ videoOutput, audioOutput, output, inde
11
11
  onProgress: (p: number) => void;
12
12
  cancelSignal: CancelSignal | undefined;
13
13
  addFaststart: boolean;
14
+ metadata?: Record<string, string> | null;
14
15
  }) => Promise<void>;
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.muxVideoAndAudio = void 0;
4
- const version_1 = require("remotion/version");
5
4
  const call_ffmpeg_1 = require("./call-ffmpeg");
6
5
  const logger_1 = require("./logger");
6
+ const make_metadata_args_1 = require("./make-metadata-args");
7
7
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
8
8
  const truthy_1 = require("./truthy");
9
- const muxVideoAndAudio = async ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, addFaststart, }) => {
9
+ const muxVideoAndAudio = async ({ videoOutput, audioOutput, output, indent, logLevel, onProgress, binariesDirectory, fps, cancelSignal, addFaststart, metadata, }) => {
10
10
  var _a;
11
11
  const startTime = Date.now();
12
12
  logger_1.Log.verbose({ indent, logLevel }, 'Muxing video and audio together');
@@ -22,8 +22,7 @@ const muxVideoAndAudio = async ({ videoOutput, audioOutput, output, indent, logL
22
22
  audioOutput ? 'copy' : null,
23
23
  addFaststart ? '-movflags' : null,
24
24
  addFaststart ? 'faststart' : null,
25
- `-metadata`,
26
- `comment=Made with Remotion ${version_1.VERSION}`,
25
+ ...(0, make_metadata_args_1.makeMetadataArgs)(metadata !== null && metadata !== void 0 ? metadata : {}),
27
26
  '-y',
28
27
  output,
29
28
  ].filter(truthy_1.truthy);
@@ -171,7 +171,7 @@ export declare const allOptions: {
171
171
  webhookCustomDataOption: {
172
172
  name: string;
173
173
  cliFlag: "webhook-custom-data";
174
- description: (type: "cli" | "ssr") => import("react/jsx-runtime").JSX.Element;
174
+ description: (type: "ssr" | "cli") => import("react/jsx-runtime").JSX.Element;
175
175
  ssrName: "customData";
176
176
  docLink: string;
177
177
  type: Record<string, unknown> | null;
@@ -581,6 +581,23 @@ export declare const allOptions: {
581
581
  ssrName: string;
582
582
  type: boolean;
583
583
  };
584
+ metadataOption: {
585
+ name: string;
586
+ cliFlag: "metadata";
587
+ description: (mode: "ssr" | "cli") => import("react/jsx-runtime").JSX.Element;
588
+ docLink: string;
589
+ type: import("./metadata").Metadata;
590
+ getValue: ({ commandLine }: {
591
+ commandLine: Record<string, unknown>;
592
+ }) => {
593
+ source: string;
594
+ value: {
595
+ [k: string]: string;
596
+ };
597
+ };
598
+ setConfig: (newMetadata: import("./metadata").Metadata) => void;
599
+ ssrName: string;
600
+ };
584
601
  };
585
602
  export type AvailableOptions = keyof typeof allOptions;
586
603
  export type TypeOfOption<Type> = Type extends AnyRemotionOption<infer X> ? X : never;
@@ -20,6 +20,7 @@ const gl_1 = require("./gl");
20
20
  const headless_1 = require("./headless");
21
21
  const jpeg_quality_1 = require("./jpeg-quality");
22
22
  const log_level_1 = require("./log-level");
23
+ const metadata_1 = require("./metadata");
23
24
  const mute_1 = require("./mute");
24
25
  const number_of_gif_loops_1 = require("./number-of-gif-loops");
25
26
  const offthreadvideo_cache_size_1 = require("./offthreadvideo-cache-size");
@@ -74,4 +75,5 @@ exports.allOptions = {
74
75
  onBrowserDownloadOption: on_browser_download_1.onBrowserDownloadOption,
75
76
  throwIfSiteExistsOption: throw_if_site_exists_1.throwIfSiteExistsOption,
76
77
  disableGitSourceOption: disable_git_source_1.disableGitSourceOption,
78
+ metadataOption: metadata_1.metadataOption,
77
79
  };
@@ -0,0 +1,18 @@
1
+ export type Metadata = Record<string, string>;
2
+ export declare const metadataOption: {
3
+ name: string;
4
+ cliFlag: "metadata";
5
+ description: (mode: "ssr" | "cli") => import("react/jsx-runtime").JSX.Element;
6
+ docLink: string;
7
+ type: Metadata;
8
+ getValue: ({ commandLine }: {
9
+ commandLine: Record<string, unknown>;
10
+ }) => {
11
+ source: string;
12
+ value: {
13
+ [k: string]: string;
14
+ };
15
+ };
16
+ setConfig: (newMetadata: Metadata) => void;
17
+ ssrName: string;
18
+ };
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.metadataOption = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ let metadata = {};
6
+ const cliFlag = 'metadata';
7
+ exports.metadataOption = {
8
+ name: 'Metadata',
9
+ cliFlag,
10
+ description: (mode) => {
11
+ if (mode === 'ssr') {
12
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["An object containing metadata to be embedded in the video. See", ' ', (0, jsx_runtime_1.jsx)("a", { href: "/docs/metadata", children: "here" }), " for which metadata is accepted."] }));
13
+ }
14
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: ["Metadata to be embedded in the video. See", ' ', (0, jsx_runtime_1.jsx)("a", { href: "/docs/metadata", children: "here" }), " for which metadata is accepted.", (0, jsx_runtime_1.jsx)("br", {}), "The parameter must be in the format of ", (0, jsx_runtime_1.jsx)("code", { children: "--metadata key=value" }), ' ', "and can be passed multiple times."] }));
15
+ },
16
+ docLink: 'https://www.remotion.dev/docs/metadata',
17
+ type: {},
18
+ getValue: ({ commandLine }) => {
19
+ if (commandLine[cliFlag] !== undefined) {
20
+ const val = commandLine[cliFlag];
21
+ const array = typeof val === 'string' ? [] : val;
22
+ const keyValues = array.map((a) => {
23
+ if (!a.includes('=')) {
24
+ throw new Error(`"metadata" must be in the format of key=value, but got ${a}`);
25
+ }
26
+ const splitted = a.split('=');
27
+ if (splitted.length !== 2) {
28
+ throw new Error(`"metadata" must be in the format of key=value, but got ${a}`);
29
+ }
30
+ return [splitted[0], splitted[1]];
31
+ });
32
+ const value = Object.fromEntries(keyValues);
33
+ return {
34
+ source: 'config',
35
+ value,
36
+ };
37
+ }
38
+ return {
39
+ source: 'config',
40
+ value: metadata,
41
+ };
42
+ },
43
+ setConfig: (newMetadata) => {
44
+ metadata = newMetadata;
45
+ },
46
+ ssrName: 'metadata',
47
+ };
@@ -1,7 +1,7 @@
1
1
  export declare const webhookCustomDataOption: {
2
2
  name: string;
3
3
  cliFlag: "webhook-custom-data";
4
- description: (type: "cli" | "ssr") => import("react/jsx-runtime").JSX.Element;
4
+ description: (type: "ssr" | "cli") => import("react/jsx-runtime").JSX.Element;
5
5
  ssrName: "customData";
6
6
  docLink: string;
7
7
  type: Record<string, unknown> | null;
@@ -67,6 +67,7 @@ export type InternalRenderMediaOptions = {
67
67
  binariesDirectory: string | null;
68
68
  compositionStart: number;
69
69
  onArtifact: OnArtifact | null;
70
+ metadata: Record<string, string> | null;
70
71
  } & MoreRenderMediaOptions;
71
72
  type Prettify<T> = {
72
73
  [K in keyof T]: T[K];
@@ -120,6 +121,7 @@ export type RenderMediaOptions = Prettify<{
120
121
  repro?: boolean;
121
122
  binariesDirectory?: string | null;
122
123
  onArtifact?: OnArtifact;
124
+ metadata?: Record<string, string> | null;
123
125
  }> & Partial<MoreRenderMediaOptions>;
124
126
  type RenderMediaResult = {
125
127
  buffer: Buffer | null;
@@ -133,5 +135,5 @@ export declare const internalRenderMedia: (args_0: InternalRenderMediaOptions) =
133
135
  * @returns {Promise<RenderMediaResult>} A promise that resolves to the rendering result, including a buffer and information about the slowest frames.
134
136
  *
135
137
  */
136
- export declare const renderMedia: ({ proResProfile, x264Preset, crf, composition, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, }: RenderMediaOptions) => Promise<RenderMediaResult>;
138
+ export declare const renderMedia: ({ proResProfile, x264Preset, crf, composition, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, metadata, }: RenderMediaOptions) => Promise<RenderMediaResult>;
137
139
  export {};
@@ -50,7 +50,7 @@ const validate_scale_1 = require("./validate-scale");
50
50
  const validate_videobitrate_1 = require("./validate-videobitrate");
51
51
  const wrap_with_error_handling_1 = require("./wrap-with-error-handling");
52
52
  const SLOWEST_FRAME_COUNT = 10;
53
- const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, serializedInputPropsWithCustomSchema, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, concurrency, disallowParallelEncoding, everyNthFrame, imageFormat: provisionalImageFormat, indent, jpegQuality, numberOfGifLoops, onCtrlCExit, preferLossless, serveUrl, server: reusedServer, logLevel, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, onBrowserDownload, onArtifact, }) => {
53
+ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, serializedInputPropsWithCustomSchema, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, concurrency, disallowParallelEncoding, everyNthFrame, imageFormat: provisionalImageFormat, indent, jpegQuality, numberOfGifLoops, onCtrlCExit, preferLossless, serveUrl, server: reusedServer, logLevel, serializedResolvedPropsWithCustomSchema, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, compositionStart, onBrowserDownload, onArtifact, metadata, }) => {
54
54
  if (repro) {
55
55
  (0, repro_1.enableRepro)({
56
56
  serveUrl,
@@ -421,6 +421,7 @@ const internalRenderMediaRaw = ({ proResProfile, x264Preset, crf, composition, s
421
421
  colorSpace,
422
422
  binariesDirectory,
423
423
  separateAudioTo,
424
+ metadata,
424
425
  });
425
426
  })
426
427
  .then((buffer) => {
@@ -504,7 +505,7 @@ exports.internalRenderMedia = (0, wrap_with_error_handling_1.wrapWithErrorHandli
504
505
  * @returns {Promise<RenderMediaResult>} A promise that resolves to the rendering result, including a buffer and information about the slowest frames.
505
506
  *
506
507
  */
507
- const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, }) => {
508
+ const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ffmpegOverride, audioBitrate, videoBitrate, encodingMaxRate, encodingBufferSize, audioCodec, jpegQuality, concurrency, serveUrl, disallowParallelEncoding, everyNthFrame, imageFormat, numberOfGifLoops, dumpBrowserLogs, preferLossless, verbose, quality, logLevel: passedLogLevel, offthreadVideoCacheSizeInBytes, colorSpace, repro, binariesDirectory, separateAudioTo, forSeamlessAacConcatenation, onBrowserDownload, onArtifact, metadata, }) => {
508
509
  var _a, _b;
509
510
  if (quality !== undefined) {
510
511
  console.warn(`The "quality" option has been renamed. Please use "jpegQuality" instead.`);
@@ -571,6 +572,7 @@ const renderMedia = ({ proResProfile, x264Preset, crf, composition, inputProps,
571
572
  forSeamlessAacConcatenation: forSeamlessAacConcatenation !== null && forSeamlessAacConcatenation !== void 0 ? forSeamlessAacConcatenation : false,
572
573
  onBrowserDownload: onBrowserDownload !== null && onBrowserDownload !== void 0 ? onBrowserDownload : (0, browser_download_progress_bar_1.defaultBrowserDownloadProgress)({ indent, logLevel, api: 'renderMedia()' }),
573
574
  onArtifact: onArtifact !== null && onArtifact !== void 0 ? onArtifact : null,
575
+ metadata: metadata !== null && metadata !== void 0 ? metadata : null,
574
576
  // TODO: In the future, introduce this as a public API when launching the distributed rendering API
575
577
  compositionStart: 0,
576
578
  });
@@ -97,23 +97,16 @@ const innerSelectComposition = async ({ page, onBrowserLog, serializedInputProps
97
97
  const internalSelectCompositionRaw = async (options) => {
98
98
  const cleanup = [];
99
99
  const { puppeteerInstance, browserExecutable, chromiumOptions, serveUrl: serveUrlOrWebpackUrl, logLevel, indent, port, envVariables, id, serializedInputPropsWithCustomSchema, onBrowserLog, server, timeoutInMilliseconds, offthreadVideoCacheSizeInBytes, binariesDirectory, onBrowserDownload, onServeUrlVisited, } = options;
100
- const { page, cleanup: cleanupPage } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
101
- passedInInstance: puppeteerInstance,
102
- browserExecutable,
103
- chromiumOptions,
104
- forceDeviceScaleFactor: undefined,
105
- indent,
106
- logLevel,
107
- onBrowserDownload,
108
- });
109
- cleanup.push(() => cleanupPage());
110
- return new Promise((resolve, reject) => {
111
- const onError = (err) => reject(err);
112
- cleanup.push((0, handle_javascript_exception_1.handleJavascriptException)({
113
- page,
114
- frame: null,
115
- onError,
116
- }));
100
+ const [{ page, cleanupPage }, serverUsed] = await Promise.all([
101
+ (0, get_browser_instance_1.getPageAndCleanupFn)({
102
+ passedInInstance: puppeteerInstance,
103
+ browserExecutable,
104
+ chromiumOptions,
105
+ forceDeviceScaleFactor: undefined,
106
+ indent,
107
+ logLevel,
108
+ onBrowserDownload,
109
+ }),
117
110
  (0, prepare_server_1.makeOrReuseServer)(options.server, {
118
111
  webpackConfigOrServeUrl: serveUrlOrWebpackUrl,
119
112
  port,
@@ -126,30 +119,39 @@ const internalSelectCompositionRaw = async (options) => {
126
119
  forceIPv4: false,
127
120
  }, {
128
121
  onDownload: () => undefined,
129
- })
130
- .then(({ server: { serveUrl, offthreadPort, sourceMap }, cleanupServer }) => {
131
- page.setBrowserSourceMapGetter(sourceMap);
132
- cleanup.push(() => cleanupServer(true));
133
- return innerSelectComposition({
134
- serveUrl,
135
- page,
136
- port: offthreadPort,
137
- browserExecutable,
138
- chromiumOptions,
139
- envVariables,
140
- id,
141
- serializedInputPropsWithCustomSchema,
142
- onBrowserLog,
143
- timeoutInMilliseconds,
144
- logLevel,
145
- indent,
146
- puppeteerInstance,
147
- server,
148
- offthreadVideoCacheSizeInBytes,
149
- binariesDirectory,
150
- onBrowserDownload,
151
- onServeUrlVisited,
152
- });
122
+ }).then((result) => {
123
+ cleanup.push(() => result.cleanupServer(true));
124
+ return result;
125
+ }),
126
+ ]);
127
+ cleanup.push(() => cleanupPage());
128
+ return new Promise((resolve, reject) => {
129
+ const onError = (err) => reject(err);
130
+ cleanup.push((0, handle_javascript_exception_1.handleJavascriptException)({
131
+ page,
132
+ frame: null,
133
+ onError,
134
+ }));
135
+ page.setBrowserSourceMapGetter(serverUsed.server.sourceMap);
136
+ innerSelectComposition({
137
+ serveUrl: serverUsed.server.serveUrl,
138
+ page,
139
+ port: serverUsed.server.offthreadPort,
140
+ browserExecutable,
141
+ chromiumOptions,
142
+ envVariables,
143
+ id,
144
+ serializedInputPropsWithCustomSchema,
145
+ onBrowserLog,
146
+ timeoutInMilliseconds,
147
+ logLevel,
148
+ indent,
149
+ puppeteerInstance,
150
+ server,
151
+ offthreadVideoCacheSizeInBytes,
152
+ binariesDirectory,
153
+ onBrowserDownload,
154
+ onServeUrlVisited,
153
155
  })
154
156
  .then((data) => {
155
157
  return resolve(data);
@@ -41,6 +41,7 @@ type InternalStitchFramesToVideoOptions = {
41
41
  ffmpegOverride: null | FfmpegOverrideFn;
42
42
  colorSpace: ColorSpace | null;
43
43
  binariesDirectory: string | null;
44
+ metadata?: Record<string, string> | null;
44
45
  } & ToOptions<typeof optionsMap.stitchFramesToVideo>;
45
46
  export type StitchFramesToVideoOptions = {
46
47
  fps: number;
@@ -69,6 +70,7 @@ export type StitchFramesToVideoOptions = {
69
70
  x264Preset?: X264Preset | null;
70
71
  colorSpace?: ColorSpace;
71
72
  binariesDirectory?: string | null;
73
+ metadata?: Record<string, string> | null;
72
74
  } & Partial<ToOptions<typeof optionsMap.stitchFramesToVideo>>;
73
75
  export declare const internalStitchFramesToVideo: (options: InternalStitchFramesToVideoOptions) => Promise<Buffer | null>;
74
76
  /**
@@ -77,5 +79,5 @@ export declare const internalStitchFramesToVideo: (options: InternalStitchFrames
77
79
  * @param {StitchFramesToVideoOptions} options The configuration options for stitching frames into a video
78
80
  * @returns {Promise<Buffer | null>} A promise that resolves with the video buffer or null if the output was written to a file
79
81
  */
80
- export declare const stitchFramesToVideo: ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, maxRate, bufferSize, x264Preset, colorSpace, binariesDirectory, separateAudioTo, }: StitchFramesToVideoOptions) => Promise<Buffer | null>;
82
+ export declare const stitchFramesToVideo: ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, maxRate, bufferSize, x264Preset, colorSpace, binariesDirectory, separateAudioTo, metadata, }: StitchFramesToVideoOptions) => Promise<Buffer | null>;
81
83
  export {};
@@ -6,7 +6,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.stitchFramesToVideo = exports.internalStitchFramesToVideo = void 0;
7
7
  const node_fs_1 = require("node:fs");
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
- const version_1 = require("remotion/version");
10
9
  const download_map_1 = require("./assets/download-map");
11
10
  const call_ffmpeg_1 = require("./call-ffmpeg");
12
11
  const codec_1 = require("./codec");
@@ -21,6 +20,7 @@ const get_extension_from_codec_1 = require("./get-extension-from-codec");
21
20
  const get_prores_profile_name_1 = require("./get-prores-profile-name");
22
21
  const logger_1 = require("./logger");
23
22
  const make_cancel_signal_1 = require("./make-cancel-signal");
23
+ const make_metadata_args_1 = require("./make-metadata-args");
24
24
  const audio_codec_1 = require("./options/audio-codec");
25
25
  const color_space_1 = require("./options/color-space");
26
26
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
@@ -30,7 +30,7 @@ const render_has_audio_1 = require("./render-has-audio");
30
30
  const validate_1 = require("./validate");
31
31
  const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
32
32
  const validate_videobitrate_1 = require("./validate-videobitrate");
33
- const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec: audioCodecSetting, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, force, fps, height, indent, muted, onDownload, outputLocation, pixelFormat, preEncodedFileLocation, preferLossless, proResProfile, logLevel, videoBitrate, maxRate, bufferSize, width, numberOfGifLoops, onProgress, x264Preset, colorSpace, binariesDirectory, separateAudioTo, }, remotionRoot) => {
33
+ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec: audioCodecSetting, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, force, fps, height, indent, muted, onDownload, outputLocation, pixelFormat, preEncodedFileLocation, preferLossless, proResProfile, logLevel, videoBitrate, maxRate, bufferSize, width, numberOfGifLoops, onProgress, x264Preset, colorSpace, binariesDirectory, separateAudioTo, metadata, }, remotionRoot) => {
34
34
  var _a;
35
35
  (0, validate_1.validateDimension)(height, 'height', 'passed to `stitchFramesToVideo()`');
36
36
  (0, validate_1.validateDimension)(width, 'width', 'passed to `stitchFramesToVideo()`');
@@ -201,7 +201,7 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec:
201
201
  codec === 'h264' ? ['-movflags', 'faststart'] : null,
202
202
  // Ignore metadata that may come from remote media
203
203
  ['-map_metadata', '-1'],
204
- ['-metadata', `comment=Made with Remotion ${version_1.VERSION}`],
204
+ ...(0, make_metadata_args_1.makeMetadataArgs)(metadata !== null && metadata !== void 0 ? metadata : {}),
205
205
  force ? '-y' : null,
206
206
  outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile,
207
207
  ];
@@ -305,7 +305,7 @@ exports.internalStitchFramesToVideo = internalStitchFramesToVideo;
305
305
  * @param {StitchFramesToVideoOptions} options The configuration options for stitching frames into a video
306
306
  * @returns {Promise<Buffer | null>} A promise that resolves with the video buffer or null if the output was written to a file
307
307
  */
308
- const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, maxRate, bufferSize, x264Preset, colorSpace, binariesDirectory, separateAudioTo, }) => {
308
+ const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitrate, audioCodec, cancelSignal, codec, crf, enforceAudioTrack, ffmpegOverride, muted, numberOfGifLoops, onDownload, onProgress, outputLocation, pixelFormat, proResProfile, verbose, videoBitrate, maxRate, bufferSize, x264Preset, colorSpace, binariesDirectory, separateAudioTo, metadata, }) => {
309
309
  return (0, exports.internalStitchFramesToVideo)({
310
310
  assetsInfo,
311
311
  audioBitrate: audioBitrate !== null && audioBitrate !== void 0 ? audioBitrate : null,
@@ -336,6 +336,7 @@ const stitchFramesToVideo = ({ assetsInfo, force, fps, height, width, audioBitra
336
336
  x264Preset: x264Preset !== null && x264Preset !== void 0 ? x264Preset : null,
337
337
  colorSpace: colorSpace !== null && colorSpace !== void 0 ? colorSpace : color_space_1.DEFAULT_COLOR_SPACE,
338
338
  binariesDirectory: binariesDirectory !== null && binariesDirectory !== void 0 ? binariesDirectory : null,
339
+ metadata: metadata !== null && metadata !== void 0 ? metadata : null,
339
340
  separateAudioTo: separateAudioTo !== null && separateAudioTo !== void 0 ? separateAudioTo : null,
340
341
  });
341
342
  };
package/dist/test-gpu.js CHANGED
@@ -4,7 +4,7 @@ exports.getChromiumGpuInformation = void 0;
4
4
  const get_browser_instance_1 = require("./get-browser-instance");
5
5
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
6
6
  const getChromiumGpuInformation = async ({ browserExecutable, indent, logLevel, chromiumOptions, timeoutInMilliseconds, onBrowserDownload, }) => {
7
- const { page, cleanup } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
7
+ const { page, cleanupPage: cleanup } = await (0, get_browser_instance_1.getPageAndCleanupFn)({
8
8
  passedInInstance: undefined,
9
9
  browserExecutable,
10
10
  chromiumOptions,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/renderer"
4
4
  },
5
5
  "name": "@remotion/renderer",
6
- "version": "4.0.214",
6
+ "version": "4.0.216",
7
7
  "description": "Render Remotion videos using Node.js or Bun",
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
@@ -18,8 +18,8 @@
18
18
  "extract-zip": "2.0.1",
19
19
  "source-map": "^0.8.0-beta.0",
20
20
  "ws": "8.17.1",
21
- "remotion": "4.0.214",
22
- "@remotion/streaming": "4.0.214"
21
+ "remotion": "4.0.216",
22
+ "@remotion/streaming": "4.0.216"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "react": ">=16.8.0",
@@ -34,13 +34,13 @@
34
34
  "@types/ws": "8.5.10"
35
35
  },
36
36
  "optionalDependencies": {
37
- "@remotion/compositor-darwin-x64": "4.0.214",
38
- "@remotion/compositor-linux-arm64-gnu": "4.0.214",
39
- "@remotion/compositor-linux-arm64-musl": "4.0.214",
40
- "@remotion/compositor-linux-x64-musl": "4.0.214",
41
- "@remotion/compositor-win32-x64-msvc": "4.0.214",
42
- "@remotion/compositor-darwin-arm64": "4.0.214",
43
- "@remotion/compositor-linux-x64-gnu": "4.0.214"
37
+ "@remotion/compositor-darwin-x64": "4.0.216",
38
+ "@remotion/compositor-linux-arm64-gnu": "4.0.216",
39
+ "@remotion/compositor-darwin-arm64": "4.0.216",
40
+ "@remotion/compositor-linux-arm64-musl": "4.0.216",
41
+ "@remotion/compositor-linux-x64-musl": "4.0.216",
42
+ "@remotion/compositor-win32-x64-msvc": "4.0.216",
43
+ "@remotion/compositor-linux-x64-gnu": "4.0.216"
44
44
  },
45
45
  "keywords": [
46
46
  "remotion",
@@ -57,7 +57,7 @@
57
57
  "formatting": "prettier src --check",
58
58
  "lint": "eslint src --ext ts,tsx",
59
59
  "test": "bun test src",
60
- "make": "node build.mjs --debug",
61
- "build-all": "node build.mjs --all"
60
+ "make": "bun build.ts --debug",
61
+ "build-all": "bun build.ts --all"
62
62
  }
63
63
  }