@remotion/renderer 3.3.19 → 3.3.26
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/README.md +47 -0
- package/dist/assets/download-map.d.ts +4 -0
- package/dist/assets/download-map.js +4 -0
- package/dist/compositor/compose.d.ts +13 -0
- package/dist/compositor/compose.js +47 -0
- package/dist/compositor/compositor.d.ts +9 -0
- package/dist/compositor/compositor.js +114 -0
- package/dist/compositor/get-executable-path.d.ts +1 -0
- package/dist/compositor/get-executable-path.js +47 -0
- package/dist/compositor/payloads.d.ts +41 -0
- package/dist/compositor/payloads.js +2 -0
- package/dist/extract-frame-from-video.d.ts +0 -1
- package/dist/ffmpeg-flags.js +3 -1
- package/dist/get-compositions-on-server.d.ts +3 -0
- package/dist/get-compositions-on-server.js +17 -0
- package/dist/get-extension-from-codec.d.ts +1 -1
- package/dist/get-frame-of-video-slow.d.ts +4 -2
- package/dist/get-frame-padded-index.d.ts +1 -1
- package/dist/get-frame-padded-index.js +3 -2
- package/dist/guess-extension-for-media.d.ts +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/last-frame-from-video-cache.d.ts +0 -1
- package/dist/provide-screenshot.d.ts +3 -2
- package/dist/provide-screenshot.js +2 -1
- package/dist/puppeteer-screenshot.d.ts +2 -1
- package/dist/puppeteer-screenshot.js +1 -0
- package/dist/render-frames.js +32 -48
- package/dist/render-media.d.ts +0 -1
- package/dist/render-on-server.d.ts +3 -0
- package/dist/render-on-server.js +119 -0
- package/dist/render-still.js +12 -10
- package/dist/screenshot-dom-element.d.ts +3 -2
- package/dist/screenshot-dom-element.js +2 -1
- package/dist/screenshot-task.d.ts +3 -2
- package/dist/screenshot-task.js +16 -8
- package/dist/take-frame-and-compose.d.ts +19 -0
- package/dist/take-frame-and-compose.js +96 -0
- package/dist/try-to-extract-frame-of-video-fast.d.ts +0 -1
- package/package.json +18 -8
- package/.prettierrc.js +0 -14
- package/tsconfig.json +0 -10
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Rust development
|
|
2
|
+
|
|
3
|
+
To participate in the development of the Rust parts of Remotion, you need to do additional steps. If you don't want to change the Rust code, you don't have to set anything up.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
These are instructions for macOS. Contributions for other platforms are appreciated.
|
|
8
|
+
|
|
9
|
+
First, install Cargo, if you don't have it, or upgrade to a version that supports `edition-2021`:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
curl https://sh.rustup.rs -sSf | sh
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Second, install components that allow for cross-compilation:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
sh install_platforms.sh
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Third, install linkers for cross compilation:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
brew install MaterializeInc/crosstools/x86_64-unknown-linux-gnu
|
|
25
|
+
brew install MaterializeInc/crosstools/aarch64-unknown-linux-gnu
|
|
26
|
+
brew install messense/macos-cross-toolchains/x86_64-unknown-linux-musl
|
|
27
|
+
brew install messense/macos-cross-toolchains/aarch64-unknown-linux-musl
|
|
28
|
+
brew install mingw-w64
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
> This will take a few minutes.
|
|
32
|
+
|
|
33
|
+
## Building
|
|
34
|
+
|
|
35
|
+
To build the Rust parts for your operating system, run:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
node build.mjs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To build the Rust binaries for all supported platforms, run:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
node build.mjs --all
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The resulting artifacts should be checked into Git.
|
|
@@ -53,6 +53,10 @@ export declare type DownloadMap = {
|
|
|
53
53
|
audioPreprocessing: string;
|
|
54
54
|
stitchFrames: string;
|
|
55
55
|
assetDir: string;
|
|
56
|
+
compositingDir: string;
|
|
57
|
+
compositorCache: {
|
|
58
|
+
[key: string]: string;
|
|
59
|
+
};
|
|
56
60
|
};
|
|
57
61
|
export declare type RenderAssetInfo = {
|
|
58
62
|
assets: TAsset[][];
|
|
@@ -62,12 +62,16 @@ const makeDownloadMap = () => {
|
|
|
62
62
|
audioMixing: makeAndReturn(dir, 'remotion-audio-mixing'),
|
|
63
63
|
audioPreprocessing: makeAndReturn(dir, 'remotion-audio-preprocessing'),
|
|
64
64
|
stitchFrames: makeAndReturn(dir, 'remotion-stitch-temp-dir'),
|
|
65
|
+
compositingDir: makeAndReturn(dir, 'remotion-compositing-temp-dir'),
|
|
66
|
+
compositorCache: {},
|
|
65
67
|
};
|
|
66
68
|
};
|
|
67
69
|
exports.makeDownloadMap = makeDownloadMap;
|
|
68
70
|
const cleanDownloadMap = async (downloadMap) => {
|
|
69
71
|
await (0, delete_directory_1.deleteDirectory)(downloadMap.downloadDir);
|
|
70
72
|
await (0, delete_directory_1.deleteDirectory)(downloadMap.complexFilter);
|
|
73
|
+
await (0, delete_directory_1.deleteDirectory)(downloadMap.compositingDir);
|
|
74
|
+
// Assets dir must be last since the others are contained
|
|
71
75
|
await (0, delete_directory_1.deleteDirectory)(downloadMap.assetDir);
|
|
72
76
|
};
|
|
73
77
|
exports.cleanDownloadMap = cleanDownloadMap;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DownloadMap } from '../assets/download-map';
|
|
2
|
+
import type { CompositorImageFormat, Layer } from './payloads';
|
|
3
|
+
declare type CompositorInput = {
|
|
4
|
+
height: number;
|
|
5
|
+
width: number;
|
|
6
|
+
layers: Layer[];
|
|
7
|
+
imageFormat: CompositorImageFormat;
|
|
8
|
+
};
|
|
9
|
+
export declare const compose: ({ height, width, layers, output, downloadMap, imageFormat, }: CompositorInput & {
|
|
10
|
+
downloadMap: DownloadMap;
|
|
11
|
+
output: string;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compose = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const crypto_1 = require("crypto");
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
7
|
+
const get_executable_path_1 = require("./get-executable-path");
|
|
8
|
+
const getCompositorHash = ({ ...input }) => {
|
|
9
|
+
return (0, crypto_1.createHash)('sha256').update(JSON.stringify(input)).digest('base64');
|
|
10
|
+
};
|
|
11
|
+
const compose = async ({ height, width, layers, output, downloadMap, imageFormat, }) => {
|
|
12
|
+
const bin = (0, get_executable_path_1.getExecutablePath)();
|
|
13
|
+
const hash = getCompositorHash({ height, width, layers, imageFormat });
|
|
14
|
+
if (downloadMap.compositorCache[hash]) {
|
|
15
|
+
await (0, promises_1.copyFile)(downloadMap.compositorCache[hash], output);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const payload = {
|
|
19
|
+
v: 1,
|
|
20
|
+
height,
|
|
21
|
+
width,
|
|
22
|
+
layers,
|
|
23
|
+
output,
|
|
24
|
+
output_format: imageFormat,
|
|
25
|
+
};
|
|
26
|
+
await new Promise((resolve, reject) => {
|
|
27
|
+
const child = (0, child_process_1.spawn)(bin);
|
|
28
|
+
child.stdin.write(JSON.stringify(payload));
|
|
29
|
+
child.stdin.end();
|
|
30
|
+
const stderrChunks = [];
|
|
31
|
+
child.stderr.on('data', (d) => stderrChunks.push(d));
|
|
32
|
+
child.on('close', (code) => {
|
|
33
|
+
if (code === 0) {
|
|
34
|
+
resolve();
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
const message = Buffer.concat(stderrChunks).toString('utf-8');
|
|
38
|
+
const parsed = JSON.parse(message);
|
|
39
|
+
const err = new Error(parsed.error);
|
|
40
|
+
err.stack = parsed.error + '\n' + parsed.backtrace;
|
|
41
|
+
reject(err);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
downloadMap.compositorCache[hash] = output;
|
|
46
|
+
};
|
|
47
|
+
exports.compose = compose;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { CliInput } from './payloads';
|
|
2
|
+
export declare type Compositor = {
|
|
3
|
+
finishCommands: () => void;
|
|
4
|
+
executeCommand: (payload: Omit<CliInput, 'nonce'>) => Promise<void>;
|
|
5
|
+
waitForDone: () => Promise<void>;
|
|
6
|
+
};
|
|
7
|
+
export declare const spawnCompositorOrReuse: (renderId: string) => Compositor;
|
|
8
|
+
export declare const releaseCompositorWithId: (renderId: string) => void;
|
|
9
|
+
export declare const waitForCompositorWithIdToQuit: (renderId: string) => Promise<void>;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.waitForCompositorWithIdToQuit = exports.releaseCompositorWithId = exports.spawnCompositorOrReuse = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const truthy_1 = require("../truthy");
|
|
6
|
+
const get_executable_path_1 = require("./get-executable-path");
|
|
7
|
+
const compositorMap = {};
|
|
8
|
+
const spawnCompositorOrReuse = (renderId) => {
|
|
9
|
+
if (!compositorMap[renderId]) {
|
|
10
|
+
compositorMap[renderId] = startCompositor();
|
|
11
|
+
}
|
|
12
|
+
return compositorMap[renderId];
|
|
13
|
+
};
|
|
14
|
+
exports.spawnCompositorOrReuse = spawnCompositorOrReuse;
|
|
15
|
+
const releaseCompositorWithId = (renderId) => {
|
|
16
|
+
if (compositorMap[renderId]) {
|
|
17
|
+
compositorMap[renderId].finishCommands();
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.releaseCompositorWithId = releaseCompositorWithId;
|
|
21
|
+
const waitForCompositorWithIdToQuit = (renderId) => {
|
|
22
|
+
if (!compositorMap[renderId]) {
|
|
23
|
+
throw new TypeError('No compositor with that id');
|
|
24
|
+
}
|
|
25
|
+
return compositorMap[renderId].waitForDone();
|
|
26
|
+
};
|
|
27
|
+
exports.waitForCompositorWithIdToQuit = waitForCompositorWithIdToQuit;
|
|
28
|
+
const startCompositor = () => {
|
|
29
|
+
const bin = (0, get_executable_path_1.getExecutablePath)();
|
|
30
|
+
const child = (0, child_process_1.spawn)(bin);
|
|
31
|
+
const _stderrChunks = [];
|
|
32
|
+
const stdoutChunks = [];
|
|
33
|
+
child.stderr.on('data', (d) => {
|
|
34
|
+
console.log(d.toString('utf-8'));
|
|
35
|
+
_stderrChunks.push(d);
|
|
36
|
+
});
|
|
37
|
+
child.stdout.on('data', (d) => {
|
|
38
|
+
console.log(d.toString('utf-8'));
|
|
39
|
+
stdoutChunks.push(d);
|
|
40
|
+
});
|
|
41
|
+
let nonce = 0;
|
|
42
|
+
return {
|
|
43
|
+
waitForDone: () => {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
child.on('exit', (code) => {
|
|
46
|
+
console.log({ code });
|
|
47
|
+
if (code === 0) {
|
|
48
|
+
resolve();
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
reject(Buffer.concat(_stderrChunks).toString('utf-8'));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
finishCommands: () => {
|
|
57
|
+
child.stdin.write('EOF\n');
|
|
58
|
+
},
|
|
59
|
+
executeCommand: (payload) => {
|
|
60
|
+
const actualPayload = {
|
|
61
|
+
...payload,
|
|
62
|
+
nonce,
|
|
63
|
+
};
|
|
64
|
+
nonce++;
|
|
65
|
+
return new Promise((resolve, reject) => {
|
|
66
|
+
child.stdin.write(JSON.stringify(actualPayload) + '\n');
|
|
67
|
+
const stderrChunks = [];
|
|
68
|
+
const onStderr = (d) => {
|
|
69
|
+
stderrChunks.push(d);
|
|
70
|
+
const message = Buffer.concat(stderrChunks).toString('utf-8');
|
|
71
|
+
let parsed = null;
|
|
72
|
+
try {
|
|
73
|
+
const content = JSON.parse(message);
|
|
74
|
+
if (content.msg_type === 'error') {
|
|
75
|
+
parsed = content;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// TODO: Obviously bad, does not handle panics
|
|
80
|
+
console.log('Rust debug err:', message);
|
|
81
|
+
}
|
|
82
|
+
if (parsed) {
|
|
83
|
+
const err = new Error(parsed.error);
|
|
84
|
+
err.stack = parsed.error + '\n' + parsed.backtrace;
|
|
85
|
+
reject(err);
|
|
86
|
+
child.stderr.off('data', onStderr);
|
|
87
|
+
child.stdout.off('data', onStdout);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const onStdout = (d) => {
|
|
91
|
+
const str = d.toString('utf-8');
|
|
92
|
+
const lineSplit = str.split('\n');
|
|
93
|
+
for (const line of lineSplit.filter(truthy_1.truthy)) {
|
|
94
|
+
let parsed = null;
|
|
95
|
+
try {
|
|
96
|
+
const p = JSON.parse(line);
|
|
97
|
+
if (p.msg_type === 'finish') {
|
|
98
|
+
parsed = p;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) { }
|
|
102
|
+
if (parsed && parsed.nonce === actualPayload.nonce) {
|
|
103
|
+
resolve();
|
|
104
|
+
child.stderr.off('data', onStderr);
|
|
105
|
+
child.stdout.off('data', onStdout);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
child.stderr.on('data', onStderr);
|
|
110
|
+
child.stdout.on('data', onStdout);
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getExecutablePath: () => any;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Adapted from @swc/core package
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getExecutablePath = void 0;
|
|
5
|
+
function isMusl() {
|
|
6
|
+
// @ts-expect-error no types
|
|
7
|
+
const { glibcVersionRuntime } = process.report.getReport().header;
|
|
8
|
+
return !glibcVersionRuntime;
|
|
9
|
+
}
|
|
10
|
+
const getExecutablePath = () => {
|
|
11
|
+
switch (process.platform) {
|
|
12
|
+
case 'win32':
|
|
13
|
+
switch (process.arch) {
|
|
14
|
+
case 'x64':
|
|
15
|
+
return require('@remotion/compositor-win32-x64-msvc').binaryPath;
|
|
16
|
+
default:
|
|
17
|
+
throw new Error(`Unsupported architecture on Windows: ${process.arch}`);
|
|
18
|
+
}
|
|
19
|
+
case 'darwin':
|
|
20
|
+
switch (process.arch) {
|
|
21
|
+
case 'x64':
|
|
22
|
+
return require('@remotion/compositor-darwin-x64').binaryPath;
|
|
23
|
+
case 'arm64':
|
|
24
|
+
return require('@remotion/compositor-darwin-arm64').binaryPath;
|
|
25
|
+
default:
|
|
26
|
+
throw new Error(`Unsupported architecture on macOS: ${process.arch}`);
|
|
27
|
+
}
|
|
28
|
+
case 'linux':
|
|
29
|
+
switch (process.arch) {
|
|
30
|
+
case 'x64':
|
|
31
|
+
if (isMusl()) {
|
|
32
|
+
return require('@remotion/compositor-linux-x64-musl').binaryPath;
|
|
33
|
+
}
|
|
34
|
+
return require('@remotion/compositor-linux-x64-gnu').binaryPath;
|
|
35
|
+
case 'arm64':
|
|
36
|
+
if (isMusl()) {
|
|
37
|
+
return require('@remotion/compositor-linux-arm64-musl').binaryPath;
|
|
38
|
+
}
|
|
39
|
+
return require('@remotion/compositor-linux-arm64-gnu').binaryPath;
|
|
40
|
+
default:
|
|
41
|
+
throw new Error(`Unsupported architecture on Linux: ${process.arch}`);
|
|
42
|
+
}
|
|
43
|
+
default:
|
|
44
|
+
throw new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
exports.getExecutablePath = getExecutablePath;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export declare type Layer = {
|
|
2
|
+
type: 'PngImage';
|
|
3
|
+
params: {
|
|
4
|
+
src: string;
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
};
|
|
10
|
+
} | {
|
|
11
|
+
type: 'JpgImage';
|
|
12
|
+
params: {
|
|
13
|
+
src: string;
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
};
|
|
19
|
+
} | {
|
|
20
|
+
type: 'Solid';
|
|
21
|
+
params: {
|
|
22
|
+
fill: [number, number, number, number];
|
|
23
|
+
x: number;
|
|
24
|
+
y: number;
|
|
25
|
+
width: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export declare type CompositorImageFormat = 'Png' | 'Jpeg';
|
|
30
|
+
export declare type CliInput = {
|
|
31
|
+
v: number;
|
|
32
|
+
output: string;
|
|
33
|
+
width: number;
|
|
34
|
+
height: number;
|
|
35
|
+
layers: Layer[];
|
|
36
|
+
output_format: CompositorImageFormat;
|
|
37
|
+
};
|
|
38
|
+
export declare type ErrorPayload = {
|
|
39
|
+
error: string;
|
|
40
|
+
backtrace: string;
|
|
41
|
+
};
|
package/dist/ffmpeg-flags.js
CHANGED
|
@@ -32,7 +32,9 @@ const randomFfmpegRuntimeId = String(Math.random()).replace('0.', '');
|
|
|
32
32
|
const ffmpegInNodeModules = (remotionRoot, binary) => {
|
|
33
33
|
const folderName = getFfmpegFolderName(remotionRoot);
|
|
34
34
|
if (!fs_1.default.existsSync(folderName)) {
|
|
35
|
-
fs_1.default.mkdirSync(folderName
|
|
35
|
+
fs_1.default.mkdirSync(folderName, {
|
|
36
|
+
recursive: true,
|
|
37
|
+
});
|
|
36
38
|
}
|
|
37
39
|
// Check if a version of FFMPEG is already installed.
|
|
38
40
|
// To qualify, it must have the expected file size
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCompositionsOnServer = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const server_1 = require("react-dom/server");
|
|
6
|
+
const getCompositionsOnServer = (Comp) => {
|
|
7
|
+
process.env.REMOTION_SERVER_RENDERING = 'true';
|
|
8
|
+
const str = (0, server_1.renderToString)((0, jsx_runtime_1.jsx)(Comp, {}));
|
|
9
|
+
const matches = str.matchAll(/<div>(.*?)<\/div>/g);
|
|
10
|
+
const metadata = [];
|
|
11
|
+
for (const match of matches) {
|
|
12
|
+
const json = JSON.parse(match[1]);
|
|
13
|
+
metadata.push(json);
|
|
14
|
+
}
|
|
15
|
+
return metadata;
|
|
16
|
+
};
|
|
17
|
+
exports.getCompositionsOnServer = getCompositionsOnServer;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Codec } from './codec';
|
|
2
|
-
export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "
|
|
2
|
+
export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "mp4" | "mkv" | "mov" | "webm";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import type { OffthreadVideoImageFormat } from 'remotion';
|
|
3
2
|
import type { SpecialVCodecForTransparency } from './assets/download-map';
|
|
4
3
|
import type { FfmpegExecutable } from './ffmpeg-executable';
|
|
@@ -8,7 +7,10 @@ export declare const getFrameOfVideoSlow: ({ src, duration, ffmpegExecutable, im
|
|
|
8
7
|
duration: number;
|
|
9
8
|
imageFormat: OffthreadVideoImageFormat;
|
|
10
9
|
specialVCodecForTransparency: SpecialVCodecForTransparency;
|
|
11
|
-
needsResize: [
|
|
10
|
+
needsResize: [
|
|
11
|
+
number,
|
|
12
|
+
number
|
|
13
|
+
] | null;
|
|
12
14
|
offset: number;
|
|
13
15
|
fps: number | null;
|
|
14
16
|
remotionRoot: string;
|
|
@@ -2,7 +2,7 @@ export declare type CountType = 'from-zero' | 'actual-frames';
|
|
|
2
2
|
export declare const getFrameOutputFileName: ({ index, frame, imageFormat, countType, lastFrame, totalFrames, }: {
|
|
3
3
|
index: number;
|
|
4
4
|
frame: number;
|
|
5
|
-
imageFormat: 'png' | 'jpeg';
|
|
5
|
+
imageFormat: 'png' | 'jpeg' | 'none';
|
|
6
6
|
countType: CountType;
|
|
7
7
|
lastFrame: number;
|
|
8
8
|
totalFrames: number;
|
|
@@ -10,13 +10,14 @@ const padIndex = ({ num, filePadLength, }) => {
|
|
|
10
10
|
};
|
|
11
11
|
const getFrameOutputFileName = ({ index, frame, imageFormat, countType, lastFrame, totalFrames, }) => {
|
|
12
12
|
const filePadLength = (0, exports.getFilePadLength)({ lastFrame, countType, totalFrames });
|
|
13
|
+
const prefix = 'element';
|
|
13
14
|
if (countType === 'actual-frames') {
|
|
14
15
|
const paddedIndex = padIndex({ filePadLength, num: frame });
|
|
15
|
-
return
|
|
16
|
+
return `${prefix}-${paddedIndex}.${imageFormat}`;
|
|
16
17
|
}
|
|
17
18
|
if (countType === 'from-zero') {
|
|
18
19
|
const paddedIndex = padIndex({ filePadLength, num: index });
|
|
19
|
-
return
|
|
20
|
+
return `${prefix}-${paddedIndex}.${imageFormat}`;
|
|
20
21
|
}
|
|
21
22
|
throw new TypeError('Unknown count type');
|
|
22
23
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export declare const RenderInternals: {
|
|
|
61
61
|
scale: number;
|
|
62
62
|
codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
|
|
63
63
|
}) => void;
|
|
64
|
-
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "
|
|
64
|
+
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "mp4" | "mkv" | "mov" | "webm";
|
|
65
65
|
tmpDir: (str: string) => string;
|
|
66
66
|
deleteDirectory: (directory: string) => Promise<void>;
|
|
67
67
|
isServeUrl: (potentialUrl: string) => boolean;
|
|
@@ -115,8 +115,8 @@ export declare const RenderInternals: {
|
|
|
115
115
|
validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
|
|
116
116
|
DEFAULT_BROWSER: import("./browser").Browser;
|
|
117
117
|
validateFrameRange: (frameRange: import("./frame-range").FrameRange | null) => void;
|
|
118
|
-
DEFAULT_OPENGL_RENDERER: "
|
|
119
|
-
validateOpenGlRenderer: (option: "
|
|
118
|
+
DEFAULT_OPENGL_RENDERER: "swangle" | "angle" | "egl" | "swiftshader" | null;
|
|
119
|
+
validateOpenGlRenderer: (option: "swangle" | "angle" | "egl" | "swiftshader" | null) => "swangle" | "angle" | "egl" | "swiftshader" | null;
|
|
120
120
|
validImageFormats: readonly ["png", "jpeg", "none"];
|
|
121
121
|
validCodecs: readonly ["h264", "h265", "vp8", "vp9", "mp3", "aac", "wav", "prores", "h264-mkv", "gif"];
|
|
122
122
|
DEFAULT_PIXEL_FORMAT: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le";
|
|
@@ -126,7 +126,7 @@ export declare const RenderInternals: {
|
|
|
126
126
|
DEFAULT_CODEC: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
|
|
127
127
|
isAudioCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif" | undefined) => boolean;
|
|
128
128
|
logLevels: readonly ["verbose", "info", "warn", "error"];
|
|
129
|
-
isEqualOrBelowLogLevel: (currentLevel: "
|
|
129
|
+
isEqualOrBelowLogLevel: (currentLevel: "verbose" | "error" | "info" | "warn", level: "verbose" | "error" | "info" | "warn") => boolean;
|
|
130
130
|
isValidLogLevel: (level: string) => boolean;
|
|
131
131
|
perf: typeof perf;
|
|
132
132
|
makeDownloadMap: () => import("./assets/download-map").DownloadMap;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ClipRegion } from 'remotion';
|
|
2
2
|
import type { Page } from './browser/BrowserPage';
|
|
3
3
|
import type { ImageFormat } from './image-format';
|
|
4
|
-
export declare const provideScreenshot: ({ page, imageFormat, options, quality, height, width, }: {
|
|
4
|
+
export declare const provideScreenshot: ({ page, imageFormat, options, quality, height, width, clipRegion, }: {
|
|
5
5
|
page: Page;
|
|
6
6
|
imageFormat: ImageFormat;
|
|
7
7
|
quality: number | undefined;
|
|
@@ -11,4 +11,5 @@ export declare const provideScreenshot: ({ page, imageFormat, options, quality,
|
|
|
11
11
|
};
|
|
12
12
|
height: number;
|
|
13
13
|
width: number;
|
|
14
|
+
clipRegion: ClipRegion | null;
|
|
14
15
|
}) => Promise<Buffer>;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.provideScreenshot = void 0;
|
|
4
4
|
const screenshot_dom_element_1 = require("./screenshot-dom-element");
|
|
5
|
-
const provideScreenshot = ({ page, imageFormat, options, quality, height, width, }) => {
|
|
5
|
+
const provideScreenshot = ({ page, imageFormat, options, quality, height, width, clipRegion, }) => {
|
|
6
6
|
return (0, screenshot_dom_element_1.screenshotDOMElement)({
|
|
7
7
|
page,
|
|
8
8
|
opts: {
|
|
@@ -12,6 +12,7 @@ const provideScreenshot = ({ page, imageFormat, options, quality, height, width,
|
|
|
12
12
|
quality,
|
|
13
13
|
height,
|
|
14
14
|
width,
|
|
15
|
+
clipRegion,
|
|
15
16
|
});
|
|
16
17
|
};
|
|
17
18
|
exports.provideScreenshot = provideScreenshot;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ClipRegion } from 'remotion';
|
|
2
2
|
import type { Page } from './browser/BrowserPage';
|
|
3
3
|
export declare const screenshot: (options: {
|
|
4
4
|
page: Page;
|
|
@@ -8,4 +8,5 @@ export declare const screenshot: (options: {
|
|
|
8
8
|
omitBackground: boolean;
|
|
9
9
|
width: number;
|
|
10
10
|
height: number;
|
|
11
|
+
clipRegion: ClipRegion | null;
|
|
11
12
|
}) => Promise<Buffer | string | void>;
|
package/dist/render-frames.js
CHANGED
|
@@ -25,12 +25,12 @@ const open_browser_1 = require("./open-browser");
|
|
|
25
25
|
const perf_1 = require("./perf");
|
|
26
26
|
const pool_1 = require("./pool");
|
|
27
27
|
const prepare_server_1 = require("./prepare-server");
|
|
28
|
-
const provide_screenshot_1 = require("./provide-screenshot");
|
|
29
28
|
const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
|
|
30
29
|
const quality_1 = require("./quality");
|
|
31
30
|
const replace_browser_1 = require("./replace-browser");
|
|
32
31
|
const seek_to_frame_1 = require("./seek-to-frame");
|
|
33
32
|
const set_props_and_env_1 = require("./set-props-and-env");
|
|
33
|
+
const take_frame_and_compose_1 = require("./take-frame-and-compose");
|
|
34
34
|
const truthy_1 = require("./truthy");
|
|
35
35
|
const validate_scale_1 = require("./validate-scale");
|
|
36
36
|
const MAX_RETRIES_PER_FRAME = 1;
|
|
@@ -163,56 +163,40 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
|
|
|
163
163
|
});
|
|
164
164
|
freePage.on('error', errorCallbackOnFrame);
|
|
165
165
|
await (0, seek_to_frame_1.seekToFrame)({ frame, page: freePage });
|
|
166
|
-
if (imageFormat !== 'none') {
|
|
167
|
-
|
|
168
|
-
const id = (0, perf_1.startPerfMeasure)('save');
|
|
169
|
-
const buffer = await (0, provide_screenshot_1.provideScreenshot)({
|
|
170
|
-
page: freePage,
|
|
171
|
-
imageFormat,
|
|
172
|
-
quality,
|
|
173
|
-
options: {
|
|
174
|
-
frame,
|
|
175
|
-
output: null,
|
|
176
|
-
},
|
|
177
|
-
height: composition.height,
|
|
178
|
-
width: composition.width,
|
|
179
|
-
});
|
|
180
|
-
(0, perf_1.stopPerfMeasure)(id);
|
|
181
|
-
onFrameBuffer(buffer, frame);
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
if (!outputDir) {
|
|
185
|
-
throw new Error('Called renderFrames() without specifying either `outputDir` or `onFrameBuffer`');
|
|
186
|
-
}
|
|
187
|
-
const output = path_1.default.join(outputDir, (0, get_frame_padded_index_1.getFrameOutputFileName)({
|
|
188
|
-
frame,
|
|
189
|
-
imageFormat,
|
|
190
|
-
index,
|
|
191
|
-
countType,
|
|
192
|
-
lastFrame,
|
|
193
|
-
totalFrames: framesToRender.length,
|
|
194
|
-
}));
|
|
195
|
-
await (0, provide_screenshot_1.provideScreenshot)({
|
|
196
|
-
page: freePage,
|
|
197
|
-
imageFormat,
|
|
198
|
-
quality,
|
|
199
|
-
options: {
|
|
200
|
-
frame,
|
|
201
|
-
output,
|
|
202
|
-
},
|
|
203
|
-
height,
|
|
204
|
-
width,
|
|
205
|
-
});
|
|
206
|
-
}
|
|
166
|
+
if (!outputDir && !onFrameBuffer && imageFormat !== 'none') {
|
|
167
|
+
throw new Error('Called renderFrames() without specifying either `outputDir` or `onFrameBuffer`');
|
|
207
168
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
169
|
+
if (outputDir && onFrameBuffer && imageFormat !== 'none') {
|
|
170
|
+
throw new Error('Pass either `outputDir` or `onFrameBuffer` to renderFrames(), not both.');
|
|
171
|
+
}
|
|
172
|
+
const id = (0, perf_1.startPerfMeasure)('save');
|
|
173
|
+
const frameDir = outputDir !== null && outputDir !== void 0 ? outputDir : downloadMap.compositingDir;
|
|
174
|
+
const { buffer, collectedAssets } = await (0, take_frame_and_compose_1.takeFrameAndCompose)({
|
|
213
175
|
frame,
|
|
214
|
-
|
|
176
|
+
freePage,
|
|
177
|
+
height,
|
|
178
|
+
imageFormat,
|
|
179
|
+
output: path_1.default.join(frameDir, (0, get_frame_padded_index_1.getFrameOutputFileName)({
|
|
180
|
+
frame,
|
|
181
|
+
imageFormat,
|
|
182
|
+
index,
|
|
183
|
+
countType,
|
|
184
|
+
lastFrame,
|
|
185
|
+
totalFrames: framesToRender.length,
|
|
186
|
+
})),
|
|
187
|
+
quality,
|
|
188
|
+
width,
|
|
189
|
+
scale,
|
|
190
|
+
downloadMap,
|
|
191
|
+
wantsBuffer: Boolean(onFrameBuffer),
|
|
215
192
|
});
|
|
193
|
+
if (onFrameBuffer) {
|
|
194
|
+
if (!buffer) {
|
|
195
|
+
throw new Error('unexpected null buffer');
|
|
196
|
+
}
|
|
197
|
+
onFrameBuffer(buffer, frame);
|
|
198
|
+
}
|
|
199
|
+
(0, perf_1.stopPerfMeasure)(id);
|
|
216
200
|
const compressedAssets = collectedAssets.map((asset) => (0, compress_assets_1.compressAsset)(assets.filter(truthy_1.truthy).flat(1), asset));
|
|
217
201
|
assets[index] = compressedAssets;
|
|
218
202
|
compressedAssets.forEach((asset) => {
|
package/dist/render-media.d.ts
CHANGED
|
@@ -0,0 +1,119 @@
|
|
|
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.renderOnServer = void 0;
|
|
7
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
+
const execa_1 = __importDefault(require("execa"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const server_1 = require("react-dom/server");
|
|
11
|
+
const remotion_1 = require("remotion");
|
|
12
|
+
const download_map_1 = require("./assets/download-map");
|
|
13
|
+
const compose_1 = require("./compositor/compose");
|
|
14
|
+
const compositor_1 = require("./compositor/compositor");
|
|
15
|
+
const get_frame_padded_index_1 = require("./get-frame-padded-index");
|
|
16
|
+
const pool_1 = require("./pool");
|
|
17
|
+
const renderOnServer = async (Comp, composition) => {
|
|
18
|
+
console.time('total');
|
|
19
|
+
console.time('frames');
|
|
20
|
+
process.env.REMOTION_SERVER_RENDERING = 'true';
|
|
21
|
+
process.env.SELECT_COMP_ID = composition.id;
|
|
22
|
+
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
23
|
+
const memo = {
|
|
24
|
+
assets: [],
|
|
25
|
+
compositions: [composition],
|
|
26
|
+
currentComposition: composition.id,
|
|
27
|
+
currentCompositionMetadata: composition,
|
|
28
|
+
folders: [],
|
|
29
|
+
registerAsset: () => {
|
|
30
|
+
throw new Error('Not implemented');
|
|
31
|
+
},
|
|
32
|
+
registerComposition: () => {
|
|
33
|
+
throw new Error('Not implemented');
|
|
34
|
+
},
|
|
35
|
+
registerFolder: () => {
|
|
36
|
+
throw new Error('Not implemented');
|
|
37
|
+
},
|
|
38
|
+
setCurrentComposition: () => {
|
|
39
|
+
throw new Error('Not implemented');
|
|
40
|
+
},
|
|
41
|
+
registerSequence() {
|
|
42
|
+
throw new Error('Not implemented');
|
|
43
|
+
},
|
|
44
|
+
sequences: [],
|
|
45
|
+
setCurrentCompositionMetadata: () => {
|
|
46
|
+
throw new Error('Not implemented');
|
|
47
|
+
},
|
|
48
|
+
unregisterAsset: () => {
|
|
49
|
+
throw new Error('Not implemented');
|
|
50
|
+
},
|
|
51
|
+
unregisterComposition: () => {
|
|
52
|
+
throw new Error('Not implemented');
|
|
53
|
+
},
|
|
54
|
+
unregisterFolder: () => {
|
|
55
|
+
throw new Error('Not implemented');
|
|
56
|
+
},
|
|
57
|
+
unregisterSequence: () => {
|
|
58
|
+
throw new Error('Not implemented');
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const pool = new pool_1.Pool(new Array(4).fill(true).map((_, i) => i));
|
|
62
|
+
const downloadMap = (0, download_map_1.makeDownloadMap)();
|
|
63
|
+
const renderId = 'abc';
|
|
64
|
+
await Promise.all(new Array(composition.durationInFrames).fill(true).map(async (_, i) => {
|
|
65
|
+
const frame = await pool.acquire();
|
|
66
|
+
// eslint-disable-next-line react/jsx-no-constructed-context-values
|
|
67
|
+
const value = {
|
|
68
|
+
audioAndVideoTags: { current: [] },
|
|
69
|
+
rootId: composition.id,
|
|
70
|
+
playing: false,
|
|
71
|
+
playbackRate: 1,
|
|
72
|
+
imperativePlaying: {
|
|
73
|
+
current: false,
|
|
74
|
+
},
|
|
75
|
+
frame: i,
|
|
76
|
+
setPlaybackRate: () => {
|
|
77
|
+
throw new Error('Not implemented');
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
const svg = (0, server_1.renderToStaticMarkup)((0, jsx_runtime_1.jsx)(remotion_1.Internals.Timeline.TimelineContext.Provider, { value: value, children: (0, jsx_runtime_1.jsx)(remotion_1.Internals.CompositionManager.Provider, { value: memo, children: (0, jsx_runtime_1.jsx)(Comp, {}) }) }));
|
|
81
|
+
const out = path_1.default.join(downloadMap.compositingDir, (0, get_frame_padded_index_1.getFrameOutputFileName)({
|
|
82
|
+
frame: i,
|
|
83
|
+
imageFormat: 'tiff',
|
|
84
|
+
index: i,
|
|
85
|
+
countType: 'from-zero',
|
|
86
|
+
lastFrame: composition.durationInFrames - 1,
|
|
87
|
+
totalFrames: composition.durationInFrames,
|
|
88
|
+
}));
|
|
89
|
+
await (0, compose_1.compose)({
|
|
90
|
+
height: composition.height,
|
|
91
|
+
width: composition.width,
|
|
92
|
+
downloadMap,
|
|
93
|
+
imageFormat: 'AddToH264',
|
|
94
|
+
layers: [
|
|
95
|
+
{
|
|
96
|
+
type: 'SvgImage',
|
|
97
|
+
params: {
|
|
98
|
+
height: composition.height,
|
|
99
|
+
width: composition.width,
|
|
100
|
+
markup: svg,
|
|
101
|
+
x: 0,
|
|
102
|
+
y: 0,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
output: out,
|
|
107
|
+
renderId,
|
|
108
|
+
});
|
|
109
|
+
pool.release(frame);
|
|
110
|
+
}));
|
|
111
|
+
(0, compositor_1.releaseCompositorWithId)(renderId);
|
|
112
|
+
console.timeEnd('frames');
|
|
113
|
+
await (0, compositor_1.waitForCompositorWithIdToQuit)(renderId);
|
|
114
|
+
console.time('convert');
|
|
115
|
+
await (0, execa_1.default)('ffmpeg', ['-i', 'fade.h264', '-c', 'copy', 'fade.mp4', '-y']);
|
|
116
|
+
console.timeEnd('convert');
|
|
117
|
+
console.timeEnd('total');
|
|
118
|
+
};
|
|
119
|
+
exports.renderOnServer = renderOnServer;
|
package/dist/render-still.js
CHANGED
|
@@ -40,15 +40,15 @@ const image_format_1 = require("./image-format");
|
|
|
40
40
|
const legacy_webpack_config_1 = require("./legacy-webpack-config");
|
|
41
41
|
const open_browser_1 = require("./open-browser");
|
|
42
42
|
const prepare_server_1 = require("./prepare-server");
|
|
43
|
-
const provide_screenshot_1 = require("./provide-screenshot");
|
|
44
43
|
const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
|
|
45
44
|
const quality_1 = require("./quality");
|
|
46
45
|
const seek_to_frame_1 = require("./seek-to-frame");
|
|
47
46
|
const set_props_and_env_1 = require("./set-props-and-env");
|
|
47
|
+
const take_frame_and_compose_1 = require("./take-frame-and-compose");
|
|
48
48
|
const validate_frame_1 = require("./validate-frame");
|
|
49
49
|
const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
|
|
50
50
|
const validate_scale_1 = require("./validate-scale");
|
|
51
|
-
const innerRenderStill = async ({ composition, quality, imageFormat = 'png', serveUrl, puppeteerInstance, dumpBrowserLogs = false, onError, inputProps, envVariables, output, frame = 0, overwrite = true, browserExecutable, timeoutInMilliseconds, chromiumOptions, scale = 1, proxyPort, cancelSignal, }) => {
|
|
51
|
+
const innerRenderStill = async ({ composition, quality, imageFormat = 'png', serveUrl, puppeteerInstance, dumpBrowserLogs = false, onError, inputProps, envVariables, output, frame = 0, overwrite = true, browserExecutable, timeoutInMilliseconds, chromiumOptions, scale = 1, proxyPort, cancelSignal, downloadMap, }) => {
|
|
52
52
|
remotion_1.Internals.validateDimension(composition.height, 'height', 'in the `config` object passed to `renderStill()`');
|
|
53
53
|
remotion_1.Internals.validateDimension(composition.width, 'width', 'in the `config` object passed to `renderStill()`');
|
|
54
54
|
remotion_1.Internals.validateFps(composition.fps, 'in the `config` object of `renderStill()`', false);
|
|
@@ -151,16 +151,17 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
|
|
|
151
151
|
page,
|
|
152
152
|
});
|
|
153
153
|
await (0, seek_to_frame_1.seekToFrame)({ frame: stillFrame, page });
|
|
154
|
-
const buffer = await (0,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
options: {
|
|
159
|
-
frame: stillFrame,
|
|
160
|
-
output,
|
|
161
|
-
},
|
|
154
|
+
const { buffer } = await (0, take_frame_and_compose_1.takeFrameAndCompose)({
|
|
155
|
+
downloadMap,
|
|
156
|
+
frame: stillFrame,
|
|
157
|
+
freePage: page,
|
|
162
158
|
height: composition.height,
|
|
163
159
|
width: composition.width,
|
|
160
|
+
imageFormat,
|
|
161
|
+
scale,
|
|
162
|
+
output,
|
|
163
|
+
quality,
|
|
164
|
+
wantsBuffer: !output,
|
|
164
165
|
});
|
|
165
166
|
await cleanup();
|
|
166
167
|
return { buffer: output ? null : buffer };
|
|
@@ -196,6 +197,7 @@ const renderStill = (options) => {
|
|
|
196
197
|
serveUrl,
|
|
197
198
|
onError: (err) => reject(err),
|
|
198
199
|
proxyPort: offthreadPort,
|
|
200
|
+
downloadMap,
|
|
199
201
|
});
|
|
200
202
|
})
|
|
201
203
|
.then((res) => resolve(res))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ClipRegion } from 'remotion';
|
|
2
2
|
import type { Page } from './browser/BrowserPage';
|
|
3
3
|
import type { ImageFormat } from './image-format';
|
|
4
|
-
export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts, height, width, }: {
|
|
4
|
+
export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts, height, width, clipRegion, }: {
|
|
5
5
|
page: Page;
|
|
6
6
|
imageFormat: ImageFormat;
|
|
7
7
|
quality: number | undefined;
|
|
@@ -10,4 +10,5 @@ export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts,
|
|
|
10
10
|
};
|
|
11
11
|
height: number;
|
|
12
12
|
width: number;
|
|
13
|
+
clipRegion: ClipRegion | null;
|
|
13
14
|
}) => Promise<Buffer>;
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.screenshotDOMElement = void 0;
|
|
4
4
|
const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
|
|
5
5
|
const puppeteer_screenshot_1 = require("./puppeteer-screenshot");
|
|
6
|
-
const screenshotDOMElement = async ({ page, imageFormat, quality, opts, height, width, }) => {
|
|
6
|
+
const screenshotDOMElement = async ({ page, imageFormat, quality, opts, height, width, clipRegion, }) => {
|
|
7
7
|
const { path } = opts;
|
|
8
8
|
if (imageFormat === 'png') {
|
|
9
9
|
await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
|
|
@@ -36,6 +36,7 @@ const screenshotDOMElement = async ({ page, imageFormat, quality, opts, height,
|
|
|
36
36
|
quality,
|
|
37
37
|
width,
|
|
38
38
|
height,
|
|
39
|
+
clipRegion,
|
|
39
40
|
});
|
|
40
41
|
};
|
|
41
42
|
exports.screenshotDOMElement = screenshotDOMElement;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { ClipRegion } from 'remotion';
|
|
2
2
|
import type { Page } from './browser/BrowserPage';
|
|
3
3
|
import type { StillImageFormat } from './image-format';
|
|
4
|
-
export declare const screenshotTask: ({ format, height, omitBackground, page, width, path, quality, }: {
|
|
4
|
+
export declare const screenshotTask: ({ format, height, omitBackground, page, width, path, quality, clipRegion, }: {
|
|
5
5
|
page: Page;
|
|
6
6
|
format: StillImageFormat;
|
|
7
7
|
path?: string | undefined;
|
|
@@ -9,4 +9,5 @@ export declare const screenshotTask: ({ format, height, omitBackground, page, wi
|
|
|
9
9
|
omitBackground: boolean;
|
|
10
10
|
width: number;
|
|
11
11
|
height: number;
|
|
12
|
+
clipRegion: ClipRegion | null;
|
|
12
13
|
}) => Promise<Buffer | string>;
|
package/dist/screenshot-task.js
CHANGED
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.screenshotTask = void 0;
|
|
7
7
|
const fs_1 = __importDefault(require("fs"));
|
|
8
8
|
const perf_1 = require("./perf");
|
|
9
|
-
const screenshotTask = async ({ format, height, omitBackground, page, width, path, quality, }) => {
|
|
9
|
+
const screenshotTask = async ({ format, height, omitBackground, page, width, path, quality, clipRegion, }) => {
|
|
10
10
|
var _a;
|
|
11
11
|
const client = page._client();
|
|
12
12
|
const target = page.target();
|
|
@@ -25,13 +25,21 @@ const screenshotTask = async ({ format, height, omitBackground, page, width, pat
|
|
|
25
25
|
const result = await client.send('Page.captureScreenshot', {
|
|
26
26
|
format,
|
|
27
27
|
quality,
|
|
28
|
-
clip:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
clip: clipRegion !== null && clipRegion !== 'hide'
|
|
29
|
+
? {
|
|
30
|
+
x: clipRegion.x,
|
|
31
|
+
y: clipRegion.y,
|
|
32
|
+
height: clipRegion.height,
|
|
33
|
+
scale: 1,
|
|
34
|
+
width: clipRegion.width,
|
|
35
|
+
}
|
|
36
|
+
: {
|
|
37
|
+
x: 0,
|
|
38
|
+
y: 0,
|
|
39
|
+
height,
|
|
40
|
+
scale: 1,
|
|
41
|
+
width,
|
|
42
|
+
},
|
|
35
43
|
captureBeyondViewport: true,
|
|
36
44
|
optimizeForSpeed: true,
|
|
37
45
|
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TAsset } from 'remotion';
|
|
2
|
+
import type { DownloadMap } from './assets/download-map';
|
|
3
|
+
import type { Page } from './browser/BrowserPage';
|
|
4
|
+
import type { ImageFormat } from './image-format';
|
|
5
|
+
export declare const takeFrameAndCompose: ({ freePage, imageFormat, quality, frame, width, height, output, scale, downloadMap, wantsBuffer, }: {
|
|
6
|
+
freePage: Page;
|
|
7
|
+
imageFormat: ImageFormat;
|
|
8
|
+
quality: number | undefined;
|
|
9
|
+
frame: number;
|
|
10
|
+
height: number;
|
|
11
|
+
width: number;
|
|
12
|
+
output: string | null;
|
|
13
|
+
scale: number;
|
|
14
|
+
downloadMap: DownloadMap;
|
|
15
|
+
wantsBuffer: boolean;
|
|
16
|
+
}) => Promise<{
|
|
17
|
+
buffer: Buffer | null;
|
|
18
|
+
collectedAssets: TAsset[];
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,96 @@
|
|
|
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.takeFrameAndCompose = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const compose_1 = require("./compositor/compose");
|
|
10
|
+
const provide_screenshot_1 = require("./provide-screenshot");
|
|
11
|
+
const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
|
|
12
|
+
const truthy_1 = require("./truthy");
|
|
13
|
+
const takeFrameAndCompose = async ({ freePage, imageFormat, quality, frame, width, height, output, scale, downloadMap, wantsBuffer, }) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const [clipRegion, collectedAssets] = await Promise.all([
|
|
16
|
+
(0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
|
|
17
|
+
pageFunction: () => {
|
|
18
|
+
if (typeof window.remotion_getClipRegion === 'undefined') {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return window.remotion_getClipRegion();
|
|
22
|
+
},
|
|
23
|
+
args: [],
|
|
24
|
+
frame,
|
|
25
|
+
page: freePage,
|
|
26
|
+
}),
|
|
27
|
+
(0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
|
|
28
|
+
pageFunction: () => {
|
|
29
|
+
return window.remotion_collectAssets();
|
|
30
|
+
},
|
|
31
|
+
args: [],
|
|
32
|
+
frame,
|
|
33
|
+
page: freePage,
|
|
34
|
+
}),
|
|
35
|
+
]);
|
|
36
|
+
if (imageFormat === 'none') {
|
|
37
|
+
return { buffer: null, collectedAssets };
|
|
38
|
+
}
|
|
39
|
+
const needsComposing = clipRegion === null
|
|
40
|
+
? null
|
|
41
|
+
: {
|
|
42
|
+
tmpFile: path_1.default.join(downloadMap.compositingDir, `${frame}.${imageFormat}`),
|
|
43
|
+
finalOutfie: output !== null && output !== void 0 ? output : path_1.default.join(downloadMap.compositingDir, `${frame}-final.${imageFormat}`),
|
|
44
|
+
clipRegion: clipRegion,
|
|
45
|
+
};
|
|
46
|
+
if (clipRegion !== 'hide') {
|
|
47
|
+
const shouldMakeBuffer = wantsBuffer && !needsComposing;
|
|
48
|
+
const buf = await (0, provide_screenshot_1.provideScreenshot)({
|
|
49
|
+
page: freePage,
|
|
50
|
+
imageFormat,
|
|
51
|
+
quality,
|
|
52
|
+
options: {
|
|
53
|
+
frame,
|
|
54
|
+
output: shouldMakeBuffer ? null : (_a = needsComposing === null || needsComposing === void 0 ? void 0 : needsComposing.tmpFile) !== null && _a !== void 0 ? _a : output,
|
|
55
|
+
},
|
|
56
|
+
height,
|
|
57
|
+
width,
|
|
58
|
+
clipRegion,
|
|
59
|
+
});
|
|
60
|
+
if (shouldMakeBuffer) {
|
|
61
|
+
return { buffer: buf, collectedAssets };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (needsComposing) {
|
|
65
|
+
await (0, compose_1.compose)({
|
|
66
|
+
height: height * scale,
|
|
67
|
+
width: width * scale,
|
|
68
|
+
layers: [
|
|
69
|
+
needsComposing.clipRegion === 'hide'
|
|
70
|
+
? null
|
|
71
|
+
: {
|
|
72
|
+
type: imageFormat === 'jpeg'
|
|
73
|
+
? 'JpgImage'
|
|
74
|
+
: 'PngImage',
|
|
75
|
+
params: {
|
|
76
|
+
height: needsComposing.clipRegion.height * scale,
|
|
77
|
+
width: needsComposing.clipRegion.width * scale,
|
|
78
|
+
src: needsComposing.tmpFile,
|
|
79
|
+
x: needsComposing.clipRegion.x * scale,
|
|
80
|
+
y: needsComposing.clipRegion.y * scale,
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
].filter(truthy_1.truthy),
|
|
84
|
+
output: needsComposing.finalOutfie,
|
|
85
|
+
downloadMap,
|
|
86
|
+
imageFormat: imageFormat === 'jpeg' ? 'Jpeg' : 'Png',
|
|
87
|
+
});
|
|
88
|
+
if (wantsBuffer) {
|
|
89
|
+
const buffer = await fs_1.default.promises.readFile(needsComposing.finalOutfie);
|
|
90
|
+
await fs_1.default.promises.unlink(needsComposing.finalOutfie);
|
|
91
|
+
return { buffer, collectedAssets };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { buffer: null, collectedAssets };
|
|
95
|
+
};
|
|
96
|
+
exports.takeFrameAndCompose = takeFrameAndCompose;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/renderer",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.26",
|
|
4
4
|
"description": "Renderer for Remotion",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,9 +9,11 @@
|
|
|
9
9
|
"lint": "eslint src --ext ts,tsx",
|
|
10
10
|
"test": "vitest --run",
|
|
11
11
|
"watch": "tsc -w",
|
|
12
|
-
"build": "tsc -d"
|
|
12
|
+
"build": "node build.mjs && tsc -d",
|
|
13
|
+
"build-all": "node build.mjs --all",
|
|
14
|
+
"prepublishOnly": "node build.mjs --all"
|
|
13
15
|
},
|
|
14
|
-
"author": "",
|
|
16
|
+
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
15
17
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
16
18
|
"repository": {
|
|
17
19
|
"url": "https://github.com/remotion-dev/remotion"
|
|
@@ -22,7 +24,7 @@
|
|
|
22
24
|
"dependencies": {
|
|
23
25
|
"execa": "5.1.1",
|
|
24
26
|
"extract-zip": "2.0.1",
|
|
25
|
-
"remotion": "3.3.
|
|
27
|
+
"remotion": "3.3.26",
|
|
26
28
|
"source-map": "^0.8.0-beta.0",
|
|
27
29
|
"ws": "8.7.0"
|
|
28
30
|
},
|
|
@@ -36,8 +38,8 @@
|
|
|
36
38
|
"@testing-library/react": "13.3.0",
|
|
37
39
|
"@types/node": "^16.7.5",
|
|
38
40
|
"@types/progress": "2.0.5",
|
|
39
|
-
"@types/react": "18.0.
|
|
40
|
-
"@types/react-dom": "18.0.
|
|
41
|
+
"@types/react": "18.0.26",
|
|
42
|
+
"@types/react-dom": "18.0.10",
|
|
41
43
|
"eslint": "8.25.0",
|
|
42
44
|
"prettier": "^2.7.1",
|
|
43
45
|
"prettier-plugin-organize-imports": "^2.3.4",
|
|
@@ -46,16 +48,24 @@
|
|
|
46
48
|
"typescript": "^4.7.0",
|
|
47
49
|
"vitest": "0.24.3"
|
|
48
50
|
},
|
|
51
|
+
"optionalDependencies": {
|
|
52
|
+
"@remotion/compositor-darwin-arm64": "3.3.26",
|
|
53
|
+
"@remotion/compositor-darwin-x64": "3.3.26",
|
|
54
|
+
"@remotion/compositor-linux-arm64-gnu": "3.3.26",
|
|
55
|
+
"@remotion/compositor-linux-arm64-musl": "3.3.26",
|
|
56
|
+
"@remotion/compositor-linux-x64-gnu": "3.3.26",
|
|
57
|
+
"@remotion/compositor-linux-x64-musl": "3.3.26",
|
|
58
|
+
"@remotion/compositor-win32-x64-msvc": "3.3.26"
|
|
59
|
+
},
|
|
49
60
|
"keywords": [
|
|
50
61
|
"remotion",
|
|
51
62
|
"ffmpeg",
|
|
52
63
|
"video",
|
|
53
64
|
"react",
|
|
54
|
-
"puppeteer",
|
|
55
65
|
"player"
|
|
56
66
|
],
|
|
57
67
|
"publishConfig": {
|
|
58
68
|
"access": "public"
|
|
59
69
|
},
|
|
60
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "8efe8771f7c2b1d22bd50e8c81cc37ae054dfae9"
|
|
61
71
|
}
|
package/.prettierrc.js
DELETED
package/tsconfig.json
DELETED