@remotion/renderer 3.0.16 → 3.0.17
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/extract-frame-from-video.d.ts +4 -6
- 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/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 +13 -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/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.js +1 -1
- package/dist/render-frames.d.ts +1 -0
- package/dist/render-frames.js +6 -3
- 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/serve-static.d.ts +1 -0
- package/dist/serve-static.js +1 -0
- package/dist/stitch-frames-to-video.d.ts +1 -0
- package/dist/stitch-frames-to-video.js +12 -10
- package/package.json +3 -3
|
@@ -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 {
|
|
@@ -2,17 +2,15 @@
|
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { FfmpegExecutable } from 'remotion';
|
|
4
4
|
import { Readable } from 'stream';
|
|
5
|
+
import { LastFrameOptions } from './last-frame-from-video-cache';
|
|
5
6
|
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>;
|
|
7
|
+
export declare const getLastFrameOfVideo: (options: LastFrameOptions) => Promise<Buffer>;
|
|
11
8
|
declare type Options = {
|
|
12
9
|
time: number;
|
|
13
10
|
src: string;
|
|
14
11
|
ffmpegExecutable: FfmpegExecutable;
|
|
12
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
15
13
|
};
|
|
16
|
-
export declare const extractFrameFromVideoFn: ({ time, src, ffmpegExecutable, }: Options) => Promise<Buffer>;
|
|
14
|
+
export declare const extractFrameFromVideoFn: ({ time, src, ffmpegExecutable, ffprobeExecutable, }: Options) => Promise<Buffer>;
|
|
17
15
|
export declare const extractFrameFromVideo: (options: Options) => Promise<Buffer>;
|
|
18
16
|
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/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,13 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { FfmpegExecutable } from 'remotion';
|
|
3
|
+
export declare type LastFrameOptions = {
|
|
4
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
5
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
6
|
+
offset: number;
|
|
7
|
+
src: string;
|
|
8
|
+
};
|
|
9
|
+
export declare const setLastFrameInCache: (options: LastFrameOptions, data: Buffer) => void;
|
|
10
|
+
export declare const getLastFrameFromCache: (options: LastFrameOptions) => Buffer | null;
|
|
11
|
+
export declare const removedLastFrameFromCache: (key: string) => void;
|
|
12
|
+
export declare const ensureMaxSize: () => void;
|
|
13
|
+
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/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
|
])
|
package/dist/render-media.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ export declare type RenderMediaOptions = {
|
|
|
23
23
|
crf?: number | null;
|
|
24
24
|
imageFormat?: 'png' | 'jpeg' | 'none';
|
|
25
25
|
ffmpegExecutable?: FfmpegExecutable;
|
|
26
|
+
ffprobeExecutable?: FfmpegExecutable;
|
|
26
27
|
pixelFormat?: PixelFormat;
|
|
27
28
|
envVariables?: Record<string, string>;
|
|
28
29
|
quality?: number;
|
|
@@ -42,4 +43,4 @@ export declare type RenderMediaOptions = {
|
|
|
42
43
|
cancelSignal?: CancelSignal;
|
|
43
44
|
browserExecutable?: BrowserExecutable;
|
|
44
45
|
} & ServeUrlOrWebpackBundle;
|
|
45
|
-
export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<void>;
|
|
46
|
+
export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<void>;
|
package/dist/render-media.js
CHANGED
|
@@ -24,7 +24,7 @@ const tmp_dir_1 = require("./tmp-dir");
|
|
|
24
24
|
const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
|
|
25
25
|
const validate_output_filename_1 = require("./validate-output-filename");
|
|
26
26
|
const validate_scale_1 = require("./validate-scale");
|
|
27
|
-
const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }) => {
|
|
27
|
+
const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }) => {
|
|
28
28
|
remotion_1.Internals.validateQuality(quality);
|
|
29
29
|
if (typeof crf !== 'undefined' && crf !== null) {
|
|
30
30
|
remotion_1.Internals.validateSelectedCrfAndCodecCombination(crf, codec);
|
|
@@ -137,7 +137,9 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
137
137
|
if (cancelled) {
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
|
+
const id = remotion_1.Internals.perf.startPerfMeasure('piping');
|
|
140
141
|
(_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.write(buffer);
|
|
142
|
+
remotion_1.Internals.perf.stopPerfMeasure(id);
|
|
141
143
|
setFrameToStitch(frame + 1);
|
|
142
144
|
}
|
|
143
145
|
: undefined,
|
|
@@ -149,6 +151,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
149
151
|
chromiumOptions,
|
|
150
152
|
scale,
|
|
151
153
|
ffmpegExecutable,
|
|
154
|
+
ffprobeExecutable,
|
|
152
155
|
browserExecutable,
|
|
153
156
|
port,
|
|
154
157
|
cancelSignal: cancelRenderFrames.cancelSignal,
|
|
@@ -180,6 +183,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
180
183
|
crf,
|
|
181
184
|
assetsInfo,
|
|
182
185
|
ffmpegExecutable,
|
|
186
|
+
ffprobeExecutable,
|
|
183
187
|
onProgress: (frame) => {
|
|
184
188
|
stitchStage = 'muxing';
|
|
185
189
|
encodedFrames = frame;
|
package/dist/render-still.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ declare type InnerStillOptions = {
|
|
|
22
22
|
onDownload?: RenderMediaOnDownload;
|
|
23
23
|
cancelSignal?: CancelSignal;
|
|
24
24
|
ffmpegExecutable?: FfmpegExecutable;
|
|
25
|
+
ffprobeExecutable?: FfmpegExecutable;
|
|
25
26
|
};
|
|
26
27
|
declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle & {
|
|
27
28
|
port?: number | null;
|
package/dist/render-still.js
CHANGED
|
@@ -76,7 +76,7 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
|
|
|
76
76
|
forceDeviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
|
|
77
77
|
}));
|
|
78
78
|
const page = await browserInstance.newPage();
|
|
79
|
-
page.setViewport({
|
|
79
|
+
await page.setViewport({
|
|
80
80
|
width: composition.width,
|
|
81
81
|
height: composition.height,
|
|
82
82
|
deviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
|
|
@@ -146,7 +146,7 @@ const renderStill = (options) => {
|
|
|
146
146
|
const downloadDir = (0, make_assets_download_dir_1.makeAssetsDownloadTmpDir)();
|
|
147
147
|
const onDownload = (_a = options.onDownload) !== null && _a !== void 0 ? _a : (() => () => undefined);
|
|
148
148
|
const happyPath = new Promise((resolve, reject) => {
|
|
149
|
-
var _a, _b;
|
|
149
|
+
var _a, _b, _c;
|
|
150
150
|
const onError = (err) => reject(err);
|
|
151
151
|
let close = null;
|
|
152
152
|
(0, prepare_server_1.prepareServer)({
|
|
@@ -155,7 +155,8 @@ const renderStill = (options) => {
|
|
|
155
155
|
onDownload,
|
|
156
156
|
onError,
|
|
157
157
|
ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
|
|
158
|
-
|
|
158
|
+
ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
|
|
159
|
+
port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
|
|
159
160
|
})
|
|
160
161
|
.then(({ serveUrl, closeServer, offthreadPort }) => {
|
|
161
162
|
close = closeServer;
|
package/dist/serve-static.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file'
|
|
|
3
3
|
export declare const serveStatic: (path: string | null, options: {
|
|
4
4
|
port: number | null;
|
|
5
5
|
ffmpegExecutable: FfmpegExecutable;
|
|
6
|
+
ffprobeExecutable: FfmpegExecutable;
|
|
6
7
|
downloadDir: string;
|
|
7
8
|
onDownload: RenderMediaOnDownload;
|
|
8
9
|
onError: (err: Error) => void;
|
package/dist/serve-static.js
CHANGED
|
@@ -14,6 +14,7 @@ const serveStatic = async (path, options) => {
|
|
|
14
14
|
const port = await (0, get_port_1.getDesiredPort)((_b = (_a = options === null || options === void 0 ? void 0 : options.port) !== null && _a !== void 0 ? _a : remotion_1.Internals.getServerPort()) !== null && _b !== void 0 ? _b : undefined, 3000, 3100);
|
|
15
15
|
const offthreadRequest = (0, offthread_video_server_1.startOffthreadVideoServer)({
|
|
16
16
|
ffmpegExecutable: options.ffmpegExecutable,
|
|
17
|
+
ffprobeExecutable: options.ffprobeExecutable,
|
|
17
18
|
downloadDir: options.downloadDir,
|
|
18
19
|
onDownload: options.onDownload,
|
|
19
20
|
onError: options.onError,
|
|
@@ -25,7 +25,7 @@ const packageJsonPath = path_1.default.join(__dirname, '..', 'package.json');
|
|
|
25
25
|
const packageJson = fs_1.default.existsSync(packageJsonPath)
|
|
26
26
|
? JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'))
|
|
27
27
|
: null;
|
|
28
|
-
const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFrames, verbose, ffmpegExecutable, onProgress, }) => {
|
|
28
|
+
const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFrames, verbose, ffmpegExecutable, ffprobeExecutable, onProgress, }) => {
|
|
29
29
|
const fileUrlAssets = await (0, convert_assets_to_file_urls_1.convertAssetsToFileUrls)({
|
|
30
30
|
assets,
|
|
31
31
|
downloadDir,
|
|
@@ -45,6 +45,7 @@ const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFra
|
|
|
45
45
|
const filterFile = path_1.default.join(tempPath, `${index}.wav`);
|
|
46
46
|
const result = await (0, preprocess_audio_track_1.preprocessAudioTrack)({
|
|
47
47
|
ffmpegExecutable: ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null,
|
|
48
|
+
ffprobeExecutable: ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : null,
|
|
48
49
|
outName: filterFile,
|
|
49
50
|
asset,
|
|
50
51
|
expectedFrames,
|
|
@@ -68,7 +69,7 @@ const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFra
|
|
|
68
69
|
return outName;
|
|
69
70
|
};
|
|
70
71
|
const spawnFfmpeg = async (options) => {
|
|
71
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
72
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
72
73
|
remotion_1.Internals.validateDimension(options.height, 'height', 'passed to `stitchFramesToVideo()`');
|
|
73
74
|
remotion_1.Internals.validateDimension(options.width, 'width', 'passed to `stitchFramesToVideo()`');
|
|
74
75
|
remotion_1.Internals.validateFps(options.fps, 'passed to `stitchFramesToVideo()`');
|
|
@@ -115,6 +116,7 @@ const spawnFfmpeg = async (options) => {
|
|
|
115
116
|
expectedFrames,
|
|
116
117
|
verbose: (_f = options.verbose) !== null && _f !== void 0 ? _f : false,
|
|
117
118
|
ffmpegExecutable: (_g = options.ffmpegExecutable) !== null && _g !== void 0 ? _g : null,
|
|
119
|
+
ffprobeExecutable: (_h = options.ffprobeExecutable) !== null && _h !== void 0 ? _h : null,
|
|
118
120
|
onProgress: (prog) => updateProgress(prog, 0),
|
|
119
121
|
});
|
|
120
122
|
if (isAudioOnly) {
|
|
@@ -129,11 +131,11 @@ const spawnFfmpeg = async (options) => {
|
|
|
129
131
|
options.force ? '-y' : null,
|
|
130
132
|
options.outputLocation,
|
|
131
133
|
].filter(remotion_1.Internals.truthy));
|
|
132
|
-
(
|
|
134
|
+
(_j = options.cancelSignal) === null || _j === void 0 ? void 0 : _j.call(options, () => {
|
|
133
135
|
ffmpegTask.kill();
|
|
134
136
|
});
|
|
135
137
|
await ffmpegTask;
|
|
136
|
-
(
|
|
138
|
+
(_k = options.onProgress) === null || _k === void 0 ? void 0 : _k.call(options, expectedFrames);
|
|
137
139
|
return {
|
|
138
140
|
getLogs: () => '',
|
|
139
141
|
task: Promise.resolve(),
|
|
@@ -141,8 +143,8 @@ const spawnFfmpeg = async (options) => {
|
|
|
141
143
|
}
|
|
142
144
|
const ffmpegArgs = [
|
|
143
145
|
['-r', String(options.fps)],
|
|
144
|
-
...(((
|
|
145
|
-
? [['-i', (
|
|
146
|
+
...(((_l = options.internalOptions) === null || _l === void 0 ? void 0 : _l.preEncodedFileLocation)
|
|
147
|
+
? [['-i', (_m = options.internalOptions) === null || _m === void 0 ? void 0 : _m.preEncodedFileLocation]]
|
|
146
148
|
: [
|
|
147
149
|
['-f', 'image2'],
|
|
148
150
|
['-s', `${options.width}x${options.height}`],
|
|
@@ -153,7 +155,7 @@ const spawnFfmpeg = async (options) => {
|
|
|
153
155
|
// -c:v is the same as -vcodec as -codec:video
|
|
154
156
|
// and specified the video codec.
|
|
155
157
|
['-c:v', encoderName],
|
|
156
|
-
...(((
|
|
158
|
+
...(((_o = options.internalOptions) === null || _o === void 0 ? void 0 : _o.preEncodedFileLocation)
|
|
157
159
|
? []
|
|
158
160
|
: [
|
|
159
161
|
proResProfileName ? ['-profile:v', proResProfileName] : null,
|
|
@@ -181,15 +183,15 @@ const spawnFfmpeg = async (options) => {
|
|
|
181
183
|
console.log(ffmpegArgs);
|
|
182
184
|
}
|
|
183
185
|
const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
|
|
184
|
-
const task = (0, execa_1.default)((
|
|
186
|
+
const task = (0, execa_1.default)((_p = options.ffmpegExecutable) !== null && _p !== void 0 ? _p : 'ffmpeg', ffmpegString, {
|
|
185
187
|
cwd: options.dir,
|
|
186
188
|
});
|
|
187
|
-
(
|
|
189
|
+
(_q = options.cancelSignal) === null || _q === void 0 ? void 0 : _q.call(options, () => {
|
|
188
190
|
task.kill();
|
|
189
191
|
});
|
|
190
192
|
let ffmpegOutput = '';
|
|
191
193
|
let isFinished = false;
|
|
192
|
-
(
|
|
194
|
+
(_r = task.stderr) === null || _r === void 0 ? void 0 : _r.on('data', (data) => {
|
|
193
195
|
var _a;
|
|
194
196
|
const str = data.toString();
|
|
195
197
|
ffmpegOutput += str;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/renderer",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.17",
|
|
4
4
|
"description": "Renderer for Remotion",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"execa": "5.1.1",
|
|
24
24
|
"puppeteer-core": "13.5.1",
|
|
25
|
-
"remotion": "3.0.
|
|
25
|
+
"remotion": "3.0.17",
|
|
26
26
|
"serve-handler": "6.1.3",
|
|
27
27
|
"source-map": "^0.8.0-beta.0"
|
|
28
28
|
},
|
|
@@ -59,5 +59,5 @@
|
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"access": "public"
|
|
61
61
|
},
|
|
62
|
-
"gitHead": "
|
|
62
|
+
"gitHead": "c973653a9ced0d8793ce0cb03ce5f837b149d865"
|
|
63
63
|
}
|