@remotion/renderer 3.0.15 → 3.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/get-audio-channels.d.ts +2 -1
- package/dist/assets/get-audio-channels.js +2 -2
- package/dist/combine-videos.js +3 -0
- package/dist/create-ffmpeg-complex-filter.d.ts +4 -1
- package/dist/extract-frame-from-video.d.ts +4 -7
- package/dist/extract-frame-from-video.js +54 -8
- package/dist/get-compositions.d.ts +1 -0
- package/dist/get-compositions.js +3 -2
- package/dist/get-port.js +26 -24
- package/dist/index.d.ts +1 -0
- package/dist/is-beyond-last-frame.d.ts +2 -0
- package/dist/is-beyond-last-frame.js +12 -0
- package/dist/last-frame-from-video-cache.d.ts +12 -0
- package/dist/last-frame-from-video-cache.js +52 -0
- package/dist/offthread-video-server.d.ts +2 -1
- package/dist/offthread-video-server.js +2 -1
- package/dist/open-browser.js +1 -0
- package/dist/prepare-server.d.ts +2 -1
- package/dist/prepare-server.js +3 -1
- package/dist/preprocess-audio-track.d.ts +1 -0
- package/dist/preprocess-audio-track.js +2 -2
- package/dist/provide-screenshot.d.ts +0 -1
- package/dist/provide-screenshot.js +1 -1
- package/dist/puppeteer-screenshot.d.ts +0 -1
- package/dist/render-frames.d.ts +1 -0
- package/dist/render-frames.js +6 -3
- package/dist/render-gif.d.ts +2 -0
- package/dist/render-gif.js +242 -0
- package/dist/render-media.d.ts +2 -1
- package/dist/render-media.js +5 -1
- package/dist/render-still.d.ts +1 -0
- package/dist/render-still.js +4 -3
- package/dist/screenshot-dom-element.d.ts +0 -1
- package/dist/screenshot-task.d.ts +0 -1
- package/dist/serve-handler/glob-slash.d.ts +1 -0
- package/dist/serve-handler/glob-slash.js +12 -0
- package/dist/serve-handler/index.d.ts +4 -0
- package/dist/serve-handler/index.js +212 -0
- package/dist/serve-handler/is-path-inside.d.ts +1 -0
- package/dist/serve-handler/is-path-inside.js +27 -0
- package/dist/serve-handler/range-parser.d.ts +13 -0
- package/dist/serve-handler/range-parser.js +57 -0
- package/dist/serve-static.d.ts +1 -0
- package/dist/serve-static.js +3 -4
- package/dist/stitch-frames-to-gif.d.ts +8 -0
- package/dist/stitch-frames-to-gif.js +128 -0
- package/dist/stitch-frames-to-video.d.ts +1 -0
- package/dist/stitch-frames-to-video.js +17 -10
- package/dist/validate-fps-for-gif.d.ts +2 -0
- package/dist/validate-fps-for-gif.js +9 -0
- package/package.json +5 -5
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { FfmpegExecutable } from 'remotion';
|
|
2
|
+
export declare function getAudioChannelsAndDuration(path: string, ffprobeExecutable: FfmpegExecutable): Promise<{
|
|
2
3
|
channels: number;
|
|
3
4
|
duration: number | null;
|
|
4
5
|
}>;
|
|
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getAudioChannelsAndDuration = void 0;
|
|
7
7
|
const execa_1 = __importDefault(require("execa"));
|
|
8
|
-
async function getAudioChannelsAndDuration(path) {
|
|
8
|
+
async function getAudioChannelsAndDuration(path, ffprobeExecutable) {
|
|
9
9
|
const args = [
|
|
10
10
|
['-v', 'error'],
|
|
11
11
|
['-show_entries', 'stream=channels:format=duration'],
|
|
@@ -14,7 +14,7 @@ async function getAudioChannelsAndDuration(path) {
|
|
|
14
14
|
]
|
|
15
15
|
.reduce((acc, val) => acc.concat(val), [])
|
|
16
16
|
.filter(Boolean);
|
|
17
|
-
const task = await (0, execa_1.default)('ffprobe', args);
|
|
17
|
+
const task = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', args);
|
|
18
18
|
const channels = task.stdout.match(/channels=([0-9]+)/);
|
|
19
19
|
const duration = task.stdout.match(/duration=([0-9.]+)/);
|
|
20
20
|
return {
|
package/dist/combine-videos.js
CHANGED
|
@@ -30,6 +30,9 @@ const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfF
|
|
|
30
30
|
remotion_1.Internals.isAudioCodec(codec) ? null : 'copy',
|
|
31
31
|
'-c:a',
|
|
32
32
|
(0, get_audio_codec_name_1.getAudioCodecName)(codec),
|
|
33
|
+
// Set max bitrate up to 1024kbps, will choose lower if that's too much
|
|
34
|
+
'-b:a',
|
|
35
|
+
'512K',
|
|
33
36
|
codec === 'h264' ? '-movflags' : null,
|
|
34
37
|
codec === 'h264' ? 'faststart' : null,
|
|
35
38
|
'-shortest',
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
/// <reference types="node" />
|
|
3
2
|
import { FfmpegExecutable } from 'remotion';
|
|
4
3
|
import { Readable } from 'stream';
|
|
4
|
+
import { LastFrameOptions } from './last-frame-from-video-cache';
|
|
5
5
|
export declare function streamToString(stream: Readable): Promise<string>;
|
|
6
|
-
export declare const getLastFrameOfVideo: (
|
|
7
|
-
ffmpegExecutable: FfmpegExecutable;
|
|
8
|
-
offset: number;
|
|
9
|
-
src: string;
|
|
10
|
-
}) => Promise<Buffer>;
|
|
6
|
+
export declare const getLastFrameOfVideo: (options: LastFrameOptions) => Promise<Buffer>;
|
|
11
7
|
declare type Options = {
|
|
12
8
|
time: number;
|
|
13
9
|
src: string;
|
|
14
10
|
ffmpegExecutable: FfmpegExecutable;
|
|
11
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
15
12
|
};
|
|
16
|
-
export declare const extractFrameFromVideoFn: ({ time, src, ffmpegExecutable, }: Options) => Promise<Buffer>;
|
|
13
|
+
export declare const extractFrameFromVideoFn: ({ time, src, ffmpegExecutable, ffprobeExecutable, }: Options) => Promise<Buffer>;
|
|
17
14
|
export declare const extractFrameFromVideo: (options: Options) => Promise<Buffer>;
|
|
18
15
|
export {};
|
|
@@ -5,7 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.extractFrameFromVideo = exports.extractFrameFromVideoFn = exports.getLastFrameOfVideo = exports.streamToString = void 0;
|
|
7
7
|
const execa_1 = __importDefault(require("execa"));
|
|
8
|
+
const remotion_1 = require("remotion");
|
|
8
9
|
const frame_to_ffmpeg_timestamp_1 = require("./frame-to-ffmpeg-timestamp");
|
|
10
|
+
const is_beyond_last_frame_1 = require("./is-beyond-last-frame");
|
|
11
|
+
const last_frame_from_video_cache_1 = require("./last-frame-from-video-cache");
|
|
9
12
|
const p_limit_1 = require("./p-limit");
|
|
10
13
|
function streamToString(stream) {
|
|
11
14
|
const chunks = [];
|
|
@@ -16,15 +19,32 @@ function streamToString(stream) {
|
|
|
16
19
|
});
|
|
17
20
|
}
|
|
18
21
|
exports.streamToString = streamToString;
|
|
19
|
-
const
|
|
22
|
+
const lastFrameLimit = (0, p_limit_1.pLimit)(5);
|
|
23
|
+
const mainLimit = (0, p_limit_1.pLimit)(5);
|
|
24
|
+
const getLastFrameOfVideoUnlimited = async ({ ffmpegExecutable, ffprobeExecutable, offset, src, }) => {
|
|
20
25
|
if (offset > 100) {
|
|
21
26
|
throw new Error('could not get last frame of ' +
|
|
22
27
|
src +
|
|
23
28
|
'. Tried to seek 100ms before the end of the video and no frame was found. The video container has a duration that is longer than it contains video.');
|
|
24
29
|
}
|
|
25
|
-
const
|
|
30
|
+
const durationCmd = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', [
|
|
31
|
+
'-v',
|
|
32
|
+
'error',
|
|
33
|
+
'-select_streams',
|
|
34
|
+
'v:0',
|
|
35
|
+
'-show_entries',
|
|
36
|
+
'stream=duration',
|
|
37
|
+
'-of',
|
|
38
|
+
'default=noprint_wrappers=1:nokey=1',
|
|
39
|
+
src,
|
|
40
|
+
]);
|
|
41
|
+
const duration = parseFloat(durationCmd.stdout);
|
|
42
|
+
if (Number.isNaN(duration)) {
|
|
43
|
+
throw new TypeError(`Could not get duration of ${src}: ${durationCmd.stdout}`);
|
|
44
|
+
}
|
|
45
|
+
const actualOffset = `${duration * 1000 - offset - 10}ms`;
|
|
26
46
|
const { stdout, stderr } = (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', [
|
|
27
|
-
'-
|
|
47
|
+
'-ss',
|
|
28
48
|
actualOffset,
|
|
29
49
|
'-i',
|
|
30
50
|
src,
|
|
@@ -61,13 +81,34 @@ const getLastFrameOfVideo = async ({ ffmpegExecutable, offset, src, }) => {
|
|
|
61
81
|
const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
|
|
62
82
|
const isEmpty = stdErr.includes('Output file is empty');
|
|
63
83
|
if (isEmpty) {
|
|
64
|
-
return (
|
|
84
|
+
return getLastFrameOfVideoUnlimited({
|
|
85
|
+
ffmpegExecutable,
|
|
86
|
+
offset: offset + 10,
|
|
87
|
+
src,
|
|
88
|
+
ffprobeExecutable,
|
|
89
|
+
});
|
|
65
90
|
}
|
|
66
91
|
return stdoutBuffer;
|
|
67
92
|
};
|
|
93
|
+
const getLastFrameOfVideo = async (options) => {
|
|
94
|
+
const fromCache = (0, last_frame_from_video_cache_1.getLastFrameFromCache)(options);
|
|
95
|
+
if (fromCache) {
|
|
96
|
+
return fromCache;
|
|
97
|
+
}
|
|
98
|
+
const result = await lastFrameLimit(getLastFrameOfVideoUnlimited, options);
|
|
99
|
+
(0, last_frame_from_video_cache_1.setLastFrameInCache)(options, result);
|
|
100
|
+
return result;
|
|
101
|
+
};
|
|
68
102
|
exports.getLastFrameOfVideo = getLastFrameOfVideo;
|
|
69
|
-
const
|
|
70
|
-
|
|
103
|
+
const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, ffprobeExecutable, }) => {
|
|
104
|
+
if ((0, is_beyond_last_frame_1.isBeyondLastFrame)(src, time)) {
|
|
105
|
+
return (0, exports.getLastFrameOfVideo)({
|
|
106
|
+
ffmpegExecutable,
|
|
107
|
+
ffprobeExecutable,
|
|
108
|
+
offset: 0,
|
|
109
|
+
src,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
71
112
|
const ffmpegTimestamp = (0, frame_to_ffmpeg_timestamp_1.frameToFfmpegTimestamp)(time);
|
|
72
113
|
const { stdout, stderr } = (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', [
|
|
73
114
|
'-ss',
|
|
@@ -117,8 +158,10 @@ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
|
|
|
117
158
|
stdoutBuffer,
|
|
118
159
|
]);
|
|
119
160
|
if (stderrStr.includes('Output file is empty')) {
|
|
161
|
+
(0, is_beyond_last_frame_1.markAsBeyondLastFrame)(src, time);
|
|
120
162
|
return (0, exports.getLastFrameOfVideo)({
|
|
121
163
|
ffmpegExecutable,
|
|
164
|
+
ffprobeExecutable,
|
|
122
165
|
offset: 0,
|
|
123
166
|
src,
|
|
124
167
|
});
|
|
@@ -126,7 +169,10 @@ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
|
|
|
126
169
|
return stdOut;
|
|
127
170
|
};
|
|
128
171
|
exports.extractFrameFromVideoFn = extractFrameFromVideoFn;
|
|
129
|
-
const extractFrameFromVideo = (options) => {
|
|
130
|
-
|
|
172
|
+
const extractFrameFromVideo = async (options) => {
|
|
173
|
+
const perf = remotion_1.Internals.perf.startPerfMeasure('extract-frame');
|
|
174
|
+
const res = await mainLimit(exports.extractFrameFromVideoFn, options);
|
|
175
|
+
remotion_1.Internals.perf.stopPerfMeasure(perf);
|
|
176
|
+
return res;
|
|
131
177
|
};
|
|
132
178
|
exports.extractFrameFromVideo = extractFrameFromVideo;
|
|
@@ -11,6 +11,7 @@ declare type GetCompositionsConfig = {
|
|
|
11
11
|
timeoutInMilliseconds?: number;
|
|
12
12
|
chromiumOptions?: ChromiumOptions;
|
|
13
13
|
ffmpegExecutable?: FfmpegExecutable;
|
|
14
|
+
ffprobeExecutable?: FfmpegExecutable;
|
|
14
15
|
port?: number | null;
|
|
15
16
|
};
|
|
16
17
|
export declare const getCompositions: (serveUrlOrWebpackUrl: string, config?: GetCompositionsConfig) => Promise<TCompMetadata[]>;
|
package/dist/get-compositions.js
CHANGED
|
@@ -60,7 +60,7 @@ const getCompositions = async (serveUrlOrWebpackUrl, config) => {
|
|
|
60
60
|
chromiumOptions: (_b = config === null || config === void 0 ? void 0 : config.chromiumOptions) !== null && _b !== void 0 ? _b : {},
|
|
61
61
|
});
|
|
62
62
|
return new Promise((resolve, reject) => {
|
|
63
|
-
var _a, _b;
|
|
63
|
+
var _a, _b, _c;
|
|
64
64
|
const onError = (err) => reject(err);
|
|
65
65
|
const cleanupPageError = (0, handle_javascript_exception_1.handleJavascriptException)({
|
|
66
66
|
page,
|
|
@@ -74,7 +74,8 @@ const getCompositions = async (serveUrlOrWebpackUrl, config) => {
|
|
|
74
74
|
onDownload: () => undefined,
|
|
75
75
|
onError,
|
|
76
76
|
ffmpegExecutable: (_a = config === null || config === void 0 ? void 0 : config.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
|
|
77
|
-
|
|
77
|
+
ffprobeExecutable: (_b = config === null || config === void 0 ? void 0 : config.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
|
|
78
|
+
port: (_c = config === null || config === void 0 ? void 0 : config.port) !== null && _c !== void 0 ? _c : null,
|
|
78
79
|
})
|
|
79
80
|
.then(({ serveUrl, closeServer, offthreadPort }) => {
|
|
80
81
|
close = closeServer;
|
package/dist/get-port.js
CHANGED
|
@@ -5,16 +5,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.getDesiredPort = void 0;
|
|
7
7
|
const net_1 = __importDefault(require("net"));
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
});
|
|
8
|
+
const p_limit_1 = require("./p-limit");
|
|
9
|
+
const getAvailablePort = (portToTry) => new Promise((resolve) => {
|
|
10
|
+
let status = 'unavailable';
|
|
11
|
+
const host = '127.0.0.1';
|
|
12
|
+
const socket = new net_1.default.Socket();
|
|
13
|
+
socket.on('connect', () => {
|
|
14
|
+
status = 'unavailable';
|
|
15
|
+
socket.destroy();
|
|
17
16
|
});
|
|
17
|
+
socket.setTimeout(1000);
|
|
18
|
+
socket.on('timeout', () => {
|
|
19
|
+
status = 'unavailable';
|
|
20
|
+
socket.destroy();
|
|
21
|
+
resolve(status);
|
|
22
|
+
});
|
|
23
|
+
socket.on('error', () => {
|
|
24
|
+
status = 'available';
|
|
25
|
+
});
|
|
26
|
+
socket.on('close', () => resolve(status));
|
|
27
|
+
socket.connect(portToTry, host);
|
|
18
28
|
});
|
|
19
29
|
const portCheckSequence = function* (ports) {
|
|
20
30
|
if (ports) {
|
|
@@ -22,30 +32,18 @@ const portCheckSequence = function* (ports) {
|
|
|
22
32
|
}
|
|
23
33
|
yield 0; // Fall back to 0 if anything else failed
|
|
24
34
|
};
|
|
25
|
-
const isPortAvailable = async (port) => {
|
|
26
|
-
try {
|
|
27
|
-
await getAvailablePort(port);
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
if (!['EADDRINUSE', 'EACCES'].includes(error.code)) {
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
35
|
const getPort = async (from, to) => {
|
|
38
36
|
const ports = makeRange(from, to);
|
|
39
37
|
for (const port of portCheckSequence(ports)) {
|
|
40
|
-
if (await
|
|
38
|
+
if ((await getAvailablePort(port)) === 'available') {
|
|
41
39
|
return port;
|
|
42
40
|
}
|
|
43
41
|
}
|
|
44
42
|
throw new Error('No available ports found');
|
|
45
43
|
};
|
|
46
|
-
const
|
|
44
|
+
const getDesiredPortUnlimited = async (desiredPort, from, to) => {
|
|
47
45
|
if (typeof desiredPort !== 'undefined' &&
|
|
48
|
-
(await
|
|
46
|
+
(await getAvailablePort(desiredPort)) === 'available') {
|
|
49
47
|
return desiredPort;
|
|
50
48
|
}
|
|
51
49
|
const actualPort = await getPort(from, to);
|
|
@@ -55,6 +53,10 @@ const getDesiredPort = async (desiredPort, from, to) => {
|
|
|
55
53
|
}
|
|
56
54
|
return actualPort;
|
|
57
55
|
};
|
|
56
|
+
const limit = (0, p_limit_1.pLimit)(1);
|
|
57
|
+
const getDesiredPort = (desiredPort, from, to) => {
|
|
58
|
+
return limit(() => getDesiredPortUnlimited(desiredPort, from, to));
|
|
59
|
+
};
|
|
58
60
|
exports.getDesiredPort = getDesiredPort;
|
|
59
61
|
const makeRange = (from, to) => {
|
|
60
62
|
if (!Number.isInteger(from) || !Number.isInteger(to)) {
|
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,7 @@ export declare const RenderInternals: {
|
|
|
33
33
|
serveStatic: (path: string | null, options: {
|
|
34
34
|
port: number | null;
|
|
35
35
|
ffmpegExecutable: import("remotion").FfmpegExecutable;
|
|
36
|
+
ffprobeExecutable: import("remotion").FfmpegExecutable;
|
|
36
37
|
downloadDir: string;
|
|
37
38
|
onDownload: import("./assets/download-and-map-assets-to-file").RenderMediaOnDownload;
|
|
38
39
|
onError: (err: Error) => void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.markAsBeyondLastFrame = exports.isBeyondLastFrame = void 0;
|
|
4
|
+
const map = {};
|
|
5
|
+
const isBeyondLastFrame = (src, time) => {
|
|
6
|
+
return map[src] && time >= map[src];
|
|
7
|
+
};
|
|
8
|
+
exports.isBeyondLastFrame = isBeyondLastFrame;
|
|
9
|
+
const markAsBeyondLastFrame = (src, time) => {
|
|
10
|
+
map[src] = time;
|
|
11
|
+
};
|
|
12
|
+
exports.markAsBeyondLastFrame = markAsBeyondLastFrame;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FfmpegExecutable } from 'remotion';
|
|
2
|
+
export declare type LastFrameOptions = {
|
|
3
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
4
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
5
|
+
offset: number;
|
|
6
|
+
src: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const setLastFrameInCache: (options: LastFrameOptions, data: Buffer) => void;
|
|
9
|
+
export declare const getLastFrameFromCache: (options: LastFrameOptions) => Buffer | null;
|
|
10
|
+
export declare const removedLastFrameFromCache: (key: string) => void;
|
|
11
|
+
export declare const ensureMaxSize: () => void;
|
|
12
|
+
export declare const clearLastFileCache: () => void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// OffthreadVideo requires sometimes that the last frame of a video gets extracted, however, this can be slow. We allocate a cache for it but that can be garbage collected
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.clearLastFileCache = exports.ensureMaxSize = exports.removedLastFrameFromCache = exports.getLastFrameFromCache = exports.setLastFrameInCache = void 0;
|
|
5
|
+
let map = {};
|
|
6
|
+
const MAX_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
|
|
7
|
+
let bufferSize = 0;
|
|
8
|
+
const makeLastFrameCacheKey = (options) => {
|
|
9
|
+
return [options.ffmpegExecutable, options.offset, options.src].join('-');
|
|
10
|
+
};
|
|
11
|
+
const setLastFrameInCache = (options, data) => {
|
|
12
|
+
const key = makeLastFrameCacheKey(options);
|
|
13
|
+
if (map[key]) {
|
|
14
|
+
bufferSize -= map[key].data.byteLength;
|
|
15
|
+
}
|
|
16
|
+
map[key] = { data, lastAccessed: Date.now() };
|
|
17
|
+
bufferSize += data.byteLength;
|
|
18
|
+
(0, exports.ensureMaxSize)();
|
|
19
|
+
};
|
|
20
|
+
exports.setLastFrameInCache = setLastFrameInCache;
|
|
21
|
+
const getLastFrameFromCache = (options) => {
|
|
22
|
+
var _a;
|
|
23
|
+
const key = makeLastFrameCacheKey(options);
|
|
24
|
+
if (!map[key]) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
map[key].lastAccessed = Date.now();
|
|
28
|
+
return (_a = map[key].data) !== null && _a !== void 0 ? _a : null;
|
|
29
|
+
};
|
|
30
|
+
exports.getLastFrameFromCache = getLastFrameFromCache;
|
|
31
|
+
const removedLastFrameFromCache = (key) => {
|
|
32
|
+
if (!map[key]) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
bufferSize -= map[key].data.byteLength;
|
|
36
|
+
delete map[key];
|
|
37
|
+
};
|
|
38
|
+
exports.removedLastFrameFromCache = removedLastFrameFromCache;
|
|
39
|
+
const ensureMaxSize = () => {
|
|
40
|
+
// eslint-disable-next-line no-unmodified-loop-condition
|
|
41
|
+
while (bufferSize > MAX_CACHE_SIZE) {
|
|
42
|
+
const earliest = Object.entries(map).sort((a, b) => {
|
|
43
|
+
return a[1].lastAccessed - b[1].lastAccessed;
|
|
44
|
+
})[0];
|
|
45
|
+
(0, exports.removedLastFrameFromCache)(earliest[0]);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
exports.ensureMaxSize = ensureMaxSize;
|
|
49
|
+
const clearLastFileCache = () => {
|
|
50
|
+
map = {};
|
|
51
|
+
};
|
|
52
|
+
exports.clearLastFileCache = clearLastFileCache;
|
|
@@ -5,8 +5,9 @@ export declare const extractUrlAndSourceFromUrl: (url: string) => {
|
|
|
5
5
|
src: string;
|
|
6
6
|
time: number;
|
|
7
7
|
};
|
|
8
|
-
export declare const startOffthreadVideoServer: ({ ffmpegExecutable, downloadDir, onDownload, onError, }: {
|
|
8
|
+
export declare const startOffthreadVideoServer: ({ ffmpegExecutable, ffprobeExecutable, downloadDir, onDownload, onError, }: {
|
|
9
9
|
ffmpegExecutable: FfmpegExecutable;
|
|
10
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
10
11
|
downloadDir: string;
|
|
11
12
|
onDownload: RenderMediaOnDownload;
|
|
12
13
|
onError: (err: Error) => void;
|
|
@@ -22,7 +22,7 @@ const extractUrlAndSourceFromUrl = (url) => {
|
|
|
22
22
|
return { src, time: parseFloat(time) };
|
|
23
23
|
};
|
|
24
24
|
exports.extractUrlAndSourceFromUrl = extractUrlAndSourceFromUrl;
|
|
25
|
-
const startOffthreadVideoServer = ({ ffmpegExecutable, downloadDir, onDownload, onError, }) => {
|
|
25
|
+
const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, downloadDir, onDownload, onError, }) => {
|
|
26
26
|
return (req, res) => {
|
|
27
27
|
if (!req.url) {
|
|
28
28
|
throw new Error('Request came in without URL');
|
|
@@ -45,6 +45,7 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, downloadDir, onDownload,
|
|
|
45
45
|
time,
|
|
46
46
|
src: to,
|
|
47
47
|
ffmpegExecutable,
|
|
48
|
+
ffprobeExecutable,
|
|
48
49
|
});
|
|
49
50
|
})
|
|
50
51
|
.then((readable) => {
|
package/dist/open-browser.js
CHANGED
|
@@ -98,6 +98,7 @@ const openBrowser = async (browser, options) => {
|
|
|
98
98
|
'--hide-scrollbars',
|
|
99
99
|
'--no-default-browser-check',
|
|
100
100
|
'--no-pings',
|
|
101
|
+
'--font-render-hinting=none',
|
|
101
102
|
'--no-zygote',
|
|
102
103
|
(options === null || options === void 0 ? void 0 : options.forceDeviceScaleFactor)
|
|
103
104
|
? `--force-device-scale-factor=${options.forceDeviceScaleFactor}`
|
package/dist/prepare-server.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { FfmpegExecutable } from 'remotion';
|
|
2
2
|
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
3
|
-
export declare const prepareServer: ({ downloadDir, ffmpegExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }: {
|
|
3
|
+
export declare const prepareServer: ({ downloadDir, ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }: {
|
|
4
4
|
webpackConfigOrServeUrl: string;
|
|
5
5
|
downloadDir: string;
|
|
6
6
|
onDownload: RenderMediaOnDownload;
|
|
7
7
|
onError: (err: Error) => void;
|
|
8
8
|
ffmpegExecutable: FfmpegExecutable;
|
|
9
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
9
10
|
port: number | null;
|
|
10
11
|
}) => Promise<{
|
|
11
12
|
serveUrl: string;
|
package/dist/prepare-server.js
CHANGED
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.prepareServer = void 0;
|
|
4
4
|
const is_serve_url_1 = require("./is-serve-url");
|
|
5
5
|
const serve_static_1 = require("./serve-static");
|
|
6
|
-
const prepareServer = async ({ downloadDir, ffmpegExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }) => {
|
|
6
|
+
const prepareServer = async ({ downloadDir, ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }) => {
|
|
7
7
|
if ((0, is_serve_url_1.isServeUrl)(webpackConfigOrServeUrl)) {
|
|
8
8
|
const { port: offthreadPort, close: closeProxy } = await (0, serve_static_1.serveStatic)(null, {
|
|
9
9
|
downloadDir,
|
|
10
10
|
onDownload,
|
|
11
11
|
onError,
|
|
12
12
|
ffmpegExecutable,
|
|
13
|
+
ffprobeExecutable,
|
|
13
14
|
port,
|
|
14
15
|
});
|
|
15
16
|
return Promise.resolve({
|
|
@@ -23,6 +24,7 @@ const prepareServer = async ({ downloadDir, ffmpegExecutable, onDownload, onErro
|
|
|
23
24
|
onDownload,
|
|
24
25
|
onError,
|
|
25
26
|
ffmpegExecutable,
|
|
27
|
+
ffprobeExecutable,
|
|
26
28
|
port,
|
|
27
29
|
});
|
|
28
30
|
return Promise.resolve({
|
|
@@ -10,8 +10,8 @@ const calculate_ffmpeg_filters_1 = require("./calculate-ffmpeg-filters");
|
|
|
10
10
|
const ffmpeg_filter_file_1 = require("./ffmpeg-filter-file");
|
|
11
11
|
const p_limit_1 = require("./p-limit");
|
|
12
12
|
const resolve_asset_src_1 = require("./resolve-asset-src");
|
|
13
|
-
const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, outName, asset, expectedFrames, fps, }) => {
|
|
14
|
-
const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)((0, resolve_asset_src_1.resolveAssetSrc)(asset.src));
|
|
13
|
+
const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, ffprobeExecutable, outName, asset, expectedFrames, fps, }) => {
|
|
14
|
+
const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)((0, resolve_asset_src_1.resolveAssetSrc)(asset.src), ffprobeExecutable);
|
|
15
15
|
const filter = (0, calculate_ffmpeg_filters_1.calculateFfmpegFilter)({
|
|
16
16
|
asset,
|
|
17
17
|
durationInFrames: expectedFrames,
|
|
@@ -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 =
|
|
5
|
+
const provideScreenshot = ({ page, imageFormat, options, quality, }) => {
|
|
6
6
|
return (0, screenshot_dom_element_1.screenshotDOMElement)({
|
|
7
7
|
page,
|
|
8
8
|
opts: {
|
package/dist/render-frames.d.ts
CHANGED
|
@@ -35,6 +35,7 @@ declare type RenderFramesOptions = {
|
|
|
35
35
|
chromiumOptions?: ChromiumOptions;
|
|
36
36
|
scale?: number;
|
|
37
37
|
ffmpegExecutable?: FfmpegExecutable;
|
|
38
|
+
ffprobeExecutable?: FfmpegExecutable;
|
|
38
39
|
port?: number | null;
|
|
39
40
|
cancelSignal?: CancelSignal;
|
|
40
41
|
} & ConfigOrComposition & ServeUrlOrWebpackBundle;
|
package/dist/render-frames.js
CHANGED
|
@@ -54,7 +54,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
|
|
|
54
54
|
const pages = new Array(actualParallelism).fill(true).map(async () => {
|
|
55
55
|
const page = await puppeteerInstance.newPage();
|
|
56
56
|
pagesArray.push(page);
|
|
57
|
-
page.setViewport({
|
|
57
|
+
await page.setViewport({
|
|
58
58
|
width: composition.width,
|
|
59
59
|
height: composition.height,
|
|
60
60
|
deviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
|
|
@@ -135,6 +135,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
|
|
|
135
135
|
await (0, seek_to_frame_1.seekToFrame)({ frame, page: freePage });
|
|
136
136
|
if (imageFormat !== 'none') {
|
|
137
137
|
if (onFrameBuffer) {
|
|
138
|
+
const id = remotion_1.Internals.perf.startPerfMeasure('save');
|
|
138
139
|
const buffer = await (0, provide_screenshot_1.provideScreenshot)({
|
|
139
140
|
page: freePage,
|
|
140
141
|
imageFormat,
|
|
@@ -144,6 +145,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
|
|
|
144
145
|
output: undefined,
|
|
145
146
|
},
|
|
146
147
|
});
|
|
148
|
+
remotion_1.Internals.perf.stopPerfMeasure(id);
|
|
147
149
|
onFrameBuffer(buffer, frame);
|
|
148
150
|
}
|
|
149
151
|
else {
|
|
@@ -236,7 +238,7 @@ const renderFrames = (options) => {
|
|
|
236
238
|
const actualParallelism = (0, get_concurrency_1.getActualConcurrency)((_d = options.parallelism) !== null && _d !== void 0 ? _d : null);
|
|
237
239
|
const openedPages = [];
|
|
238
240
|
return new Promise((resolve, reject) => {
|
|
239
|
-
var _a, _b;
|
|
241
|
+
var _a, _b, _c;
|
|
240
242
|
const cleanup = [];
|
|
241
243
|
const onError = (err) => reject(err);
|
|
242
244
|
Promise.all([
|
|
@@ -246,7 +248,8 @@ const renderFrames = (options) => {
|
|
|
246
248
|
onDownload,
|
|
247
249
|
onError,
|
|
248
250
|
ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
|
|
249
|
-
|
|
251
|
+
ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
|
|
252
|
+
port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
|
|
250
253
|
}),
|
|
251
254
|
browserInstance,
|
|
252
255
|
])
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { RenderMediaOptions } from './render-media';
|
|
2
|
+
export declare const renderGif: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, loop, skipNFrames, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<void>;
|