@remotion/renderer 4.0.0-offthread.42 → 4.0.0-offthread.7
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/download-and-map-assets-to-file.d.ts +1 -1
- package/dist/assets/download-and-map-assets-to-file.js +30 -13
- package/dist/combine-videos.d.ts +2 -1
- package/dist/combine-videos.js +3 -1
- package/dist/create-ffmpeg-complex-filter.d.ts +1 -4
- package/dist/cycle-browser-tabs.d.ts +2 -1
- package/dist/cycle-browser-tabs.js +9 -2
- package/dist/extract-frame-from-video.d.ts +0 -5
- package/dist/extract-frame-from-video.js +35 -8
- package/dist/get-compositions.d.ts +1 -1
- package/dist/get-compositions.js +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- 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 +11 -0
- package/dist/last-frame-from-video-cache.js +52 -0
- package/dist/make-cancel-signal.d.ts +7 -0
- package/dist/make-cancel-signal.js +25 -0
- package/dist/merge-audio-track.js +2 -2
- package/dist/offthread-video-server.d.ts +6 -1
- package/dist/offthread-video-server.js +5 -4
- package/dist/open-browser.d.ts +5 -5
- package/dist/open-browser.js +2 -1
- package/dist/prepare-server.js +1 -1
- package/dist/prespawn-ffmpeg.d.ts +2 -0
- package/dist/prespawn-ffmpeg.js +3 -0
- package/dist/provide-screenshot.d.ts +0 -1
- package/dist/provide-screenshot.js +1 -1
- package/dist/puppeteer-screenshot.js +5 -1
- package/dist/render-frames.d.ts +2 -0
- package/dist/render-frames.js +77 -37
- package/dist/render-media.d.ts +3 -1
- package/dist/render-media.js +117 -54
- package/dist/render-still.d.ts +4 -2
- package/dist/render-still.js +28 -11
- package/dist/serve-static.js +9 -1
- package/dist/set-props-and-env.d.ts +2 -1
- package/dist/set-props-and-env.js +22 -3
- package/dist/stitch-frames-to-video.d.ts +3 -1
- package/dist/stitch-frames-to-video.js +27 -14
- package/package.json +4 -4
|
@@ -2,7 +2,7 @@ import { TAsset } from 'remotion';
|
|
|
2
2
|
export declare type RenderMediaOnDownload = (src: string) => ((progress: {
|
|
3
3
|
percent: number;
|
|
4
4
|
}) => void) | undefined | void;
|
|
5
|
-
export declare const waitForAssetToBeDownloaded: (src: string) => Promise<
|
|
5
|
+
export declare const waitForAssetToBeDownloaded: (src: string, to: string) => Promise<void>;
|
|
6
6
|
export declare const markAllAssetsAsDownloaded: () => void;
|
|
7
7
|
export declare const getSanitizedFilenameForAssetUrl: ({ src, downloadDir, }: {
|
|
8
8
|
src: string;
|
|
@@ -13,25 +13,38 @@ const sanitize_filepath_1 = require("./sanitize-filepath");
|
|
|
13
13
|
const isDownloadingMap = {};
|
|
14
14
|
const hasBeenDownloadedMap = {};
|
|
15
15
|
const listeners = {};
|
|
16
|
-
const waitForAssetToBeDownloaded = (src) => {
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const waitForAssetToBeDownloaded = (src, to) => {
|
|
17
|
+
var _a;
|
|
18
|
+
if ((_a = hasBeenDownloadedMap[src]) === null || _a === void 0 ? void 0 : _a[to]) {
|
|
19
|
+
return Promise.resolve();
|
|
19
20
|
}
|
|
20
21
|
if (!listeners[src]) {
|
|
21
|
-
listeners[src] =
|
|
22
|
+
listeners[src] = {};
|
|
23
|
+
}
|
|
24
|
+
if (!listeners[src][to]) {
|
|
25
|
+
listeners[src][to] = [];
|
|
22
26
|
}
|
|
23
27
|
return new Promise((resolve) => {
|
|
24
|
-
listeners[src].push((
|
|
28
|
+
listeners[src][to].push(() => resolve());
|
|
25
29
|
});
|
|
26
30
|
};
|
|
27
31
|
exports.waitForAssetToBeDownloaded = waitForAssetToBeDownloaded;
|
|
28
32
|
const notifyAssetIsDownloaded = (src, to) => {
|
|
29
33
|
if (!listeners[src]) {
|
|
30
|
-
listeners[src] =
|
|
34
|
+
listeners[src] = {};
|
|
35
|
+
}
|
|
36
|
+
if (!listeners[src][to]) {
|
|
37
|
+
listeners[src][to] = [];
|
|
38
|
+
}
|
|
39
|
+
listeners[src][to].forEach((fn) => fn());
|
|
40
|
+
if (!isDownloadingMap[src]) {
|
|
41
|
+
isDownloadingMap[src] = {};
|
|
31
42
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
43
|
+
isDownloadingMap[src][to] = false;
|
|
44
|
+
if (!hasBeenDownloadedMap[src]) {
|
|
45
|
+
hasBeenDownloadedMap[src] = {};
|
|
46
|
+
}
|
|
47
|
+
hasBeenDownloadedMap[src][to] = true;
|
|
35
48
|
};
|
|
36
49
|
const validateMimeType = (mimeType, src) => {
|
|
37
50
|
if (!mimeType.includes('/')) {
|
|
@@ -73,13 +86,17 @@ function validateBufferEncoding(potentialEncoding, dataUrl) {
|
|
|
73
86
|
}
|
|
74
87
|
}
|
|
75
88
|
const downloadAsset = async (src, to, onDownload) => {
|
|
76
|
-
|
|
89
|
+
var _a, _b;
|
|
90
|
+
if ((_a = hasBeenDownloadedMap[src]) === null || _a === void 0 ? void 0 : _a[to]) {
|
|
77
91
|
return;
|
|
78
92
|
}
|
|
79
|
-
if (isDownloadingMap[src]) {
|
|
80
|
-
return (0, exports.waitForAssetToBeDownloaded)(src);
|
|
93
|
+
if ((_b = isDownloadingMap[src]) === null || _b === void 0 ? void 0 : _b[to]) {
|
|
94
|
+
return (0, exports.waitForAssetToBeDownloaded)(src, to);
|
|
95
|
+
}
|
|
96
|
+
if (!isDownloadingMap[src]) {
|
|
97
|
+
isDownloadingMap[src] = {};
|
|
81
98
|
}
|
|
82
|
-
isDownloadingMap[src] = true;
|
|
99
|
+
isDownloadingMap[src][to] = true;
|
|
83
100
|
const onProgress = onDownload(src);
|
|
84
101
|
(0, ensure_output_directory_1.ensureOutputDirectory)(to);
|
|
85
102
|
if (src.startsWith('data:')) {
|
package/dist/combine-videos.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Codec } from 'remotion';
|
|
2
|
-
export declare const combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, }: {
|
|
2
|
+
export declare const combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, }: {
|
|
3
3
|
files: string[];
|
|
4
4
|
filelistDir: string;
|
|
5
5
|
output: string;
|
|
6
6
|
onProgress: (p: number) => void;
|
|
7
7
|
numberOfFrames: number;
|
|
8
8
|
codec: Codec;
|
|
9
|
+
fps: number;
|
|
9
10
|
}) => Promise<void>;
|
package/dist/combine-videos.js
CHANGED
|
@@ -11,13 +11,15 @@ const path_1 = require("path");
|
|
|
11
11
|
const remotion_1 = require("remotion");
|
|
12
12
|
const get_audio_codec_name_1 = require("./get-audio-codec-name");
|
|
13
13
|
const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
|
|
14
|
-
const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, }) => {
|
|
14
|
+
const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, }) => {
|
|
15
15
|
var _a;
|
|
16
16
|
const fileList = files.map((p) => `file '${p}'`).join('\n');
|
|
17
17
|
const fileListTxt = (0, path_1.join)(filelistDir, 'files.txt');
|
|
18
18
|
(0, fs_1.writeFileSync)(fileListTxt, fileList);
|
|
19
19
|
try {
|
|
20
20
|
const task = (0, execa_1.default)('ffmpeg', [
|
|
21
|
+
remotion_1.Internals.isAudioCodec(codec) ? null : '-r',
|
|
22
|
+
remotion_1.Internals.isAudioCodec(codec) ? null : String(fps),
|
|
21
23
|
'-f',
|
|
22
24
|
'concat',
|
|
23
25
|
'-safe',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { openBrowser } from './open-browser';
|
|
2
2
|
declare type Await<T> = T extends PromiseLike<infer U> ? U : T;
|
|
3
|
-
|
|
3
|
+
declare type Browser = Await<ReturnType<typeof openBrowser>>;
|
|
4
|
+
export declare const cycleBrowserTabs: (puppeteerInstance: Browser, concurrency: number) => {
|
|
4
5
|
stopCycling: () => void;
|
|
5
6
|
};
|
|
6
7
|
export {};
|
|
@@ -9,15 +9,21 @@ const cycleBrowserTabs = (puppeteerInstance, concurrency) => {
|
|
|
9
9
|
}
|
|
10
10
|
let interval = null;
|
|
11
11
|
let i = 0;
|
|
12
|
+
let stopped = false;
|
|
12
13
|
const set = () => {
|
|
13
14
|
interval = setTimeout(() => {
|
|
14
15
|
puppeteerInstance
|
|
15
16
|
.pages()
|
|
16
17
|
.then((pages) => {
|
|
17
|
-
var _a
|
|
18
|
+
var _a;
|
|
19
|
+
if (pages.length === 0) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
18
22
|
const currentPage = pages[i % pages.length];
|
|
19
23
|
i++;
|
|
20
|
-
if (!((
|
|
24
|
+
if (!((_a = currentPage === null || currentPage === void 0 ? void 0 : currentPage.isClosed) === null || _a === void 0 ? void 0 : _a.call(currentPage)) &&
|
|
25
|
+
!stopped &&
|
|
26
|
+
(currentPage === null || currentPage === void 0 ? void 0 : currentPage.url()) !== 'about:blank') {
|
|
21
27
|
return currentPage.bringToFront();
|
|
22
28
|
}
|
|
23
29
|
})
|
|
@@ -33,6 +39,7 @@ const cycleBrowserTabs = (puppeteerInstance, concurrency) => {
|
|
|
33
39
|
if (!interval) {
|
|
34
40
|
return;
|
|
35
41
|
}
|
|
42
|
+
stopped = true;
|
|
36
43
|
return clearInterval(interval);
|
|
37
44
|
},
|
|
38
45
|
};
|
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
import { FfmpegExecutable } from 'remotion';
|
|
3
3
|
import { Readable } from 'stream';
|
|
4
4
|
export declare function streamToString(stream: Readable): Promise<string>;
|
|
5
|
-
export declare const getLastFrameOfVideo: ({ ffmpegExecutable, offset, src, }: {
|
|
6
|
-
ffmpegExecutable: FfmpegExecutable;
|
|
7
|
-
offset: number;
|
|
8
|
-
src: string;
|
|
9
|
-
}) => Promise<Buffer>;
|
|
10
5
|
declare type Options = {
|
|
11
6
|
time: number;
|
|
12
7
|
src: string;
|
|
@@ -3,9 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.extractFrameFromVideo = exports.extractFrameFromVideoFn = exports.
|
|
6
|
+
exports.extractFrameFromVideo = exports.extractFrameFromVideoFn = 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,7 +19,9 @@ 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, offset, src, }) => {
|
|
20
25
|
if (offset > 100) {
|
|
21
26
|
throw new Error('could not get last frame of ' +
|
|
22
27
|
src +
|
|
@@ -61,13 +66,31 @@ const getLastFrameOfVideo = async ({ ffmpegExecutable, offset, src, }) => {
|
|
|
61
66
|
const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
|
|
62
67
|
const isEmpty = stdErr.includes('Output file is empty');
|
|
63
68
|
if (isEmpty) {
|
|
64
|
-
return (
|
|
69
|
+
return getLastFrameOfVideoUnlimited({
|
|
70
|
+
ffmpegExecutable,
|
|
71
|
+
offset: offset + 10,
|
|
72
|
+
src,
|
|
73
|
+
});
|
|
65
74
|
}
|
|
66
75
|
return stdoutBuffer;
|
|
67
76
|
};
|
|
68
|
-
|
|
69
|
-
const
|
|
77
|
+
const getLastFrameOfVideo = async (options) => {
|
|
78
|
+
const fromCache = (0, last_frame_from_video_cache_1.getLastFrameFromCache)(options);
|
|
79
|
+
if (fromCache) {
|
|
80
|
+
return fromCache;
|
|
81
|
+
}
|
|
82
|
+
const result = await lastFrameLimit(getLastFrameOfVideoUnlimited, options);
|
|
83
|
+
(0, last_frame_from_video_cache_1.setLastFrameInCache)(options, result);
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
70
86
|
const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
|
|
87
|
+
if ((0, is_beyond_last_frame_1.isBeyondLastFrame)(src, time)) {
|
|
88
|
+
return getLastFrameOfVideo({
|
|
89
|
+
ffmpegExecutable,
|
|
90
|
+
offset: 0,
|
|
91
|
+
src,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
71
94
|
const ffmpegTimestamp = (0, frame_to_ffmpeg_timestamp_1.frameToFfmpegTimestamp)(time);
|
|
72
95
|
const { stdout, stderr } = (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', [
|
|
73
96
|
'-ss',
|
|
@@ -117,7 +140,8 @@ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
|
|
|
117
140
|
stdoutBuffer,
|
|
118
141
|
]);
|
|
119
142
|
if (stderrStr.includes('Output file is empty')) {
|
|
120
|
-
|
|
143
|
+
(0, is_beyond_last_frame_1.markAsBeyondLastFrame)(src, time);
|
|
144
|
+
return getLastFrameOfVideo({
|
|
121
145
|
ffmpegExecutable,
|
|
122
146
|
offset: 0,
|
|
123
147
|
src,
|
|
@@ -126,7 +150,10 @@ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
|
|
|
126
150
|
return stdOut;
|
|
127
151
|
};
|
|
128
152
|
exports.extractFrameFromVideoFn = extractFrameFromVideoFn;
|
|
129
|
-
const extractFrameFromVideo = (options) => {
|
|
130
|
-
|
|
153
|
+
const extractFrameFromVideo = async (options) => {
|
|
154
|
+
const perf = remotion_1.Internals.perf.startPerfMeasure('extract-frame');
|
|
155
|
+
const res = await mainLimit(exports.extractFrameFromVideoFn, options);
|
|
156
|
+
remotion_1.Internals.perf.stopPerfMeasure(perf);
|
|
157
|
+
return res;
|
|
131
158
|
};
|
|
132
159
|
exports.extractFrameFromVideo = extractFrameFromVideo;
|
|
@@ -13,5 +13,5 @@ declare type GetCompositionsConfig = {
|
|
|
13
13
|
ffmpegExecutable?: FfmpegExecutable;
|
|
14
14
|
port?: number | null;
|
|
15
15
|
};
|
|
16
|
-
export declare const getCompositions: (serveUrlOrWebpackUrl: string, config?: GetCompositionsConfig
|
|
16
|
+
export declare const getCompositions: (serveUrlOrWebpackUrl: string, config?: GetCompositionsConfig) => Promise<TCompMetadata[]>;
|
|
17
17
|
export {};
|
package/dist/get-compositions.js
CHANGED
|
@@ -28,6 +28,7 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
|
|
|
28
28
|
initialFrame: 0,
|
|
29
29
|
timeoutInMilliseconds: config === null || config === void 0 ? void 0 : config.timeoutInMilliseconds,
|
|
30
30
|
proxyPort,
|
|
31
|
+
retriesRemaining: 2,
|
|
31
32
|
});
|
|
32
33
|
await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
|
|
33
34
|
page,
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { combineVideos } from './combine-videos';
|
|
|
5
5
|
export { ErrorWithStackFrame } from './error-handling/handle-javascript-exception';
|
|
6
6
|
export { FfmpegVersion } from './ffmpeg-flags';
|
|
7
7
|
export { getCompositions } from './get-compositions';
|
|
8
|
+
export { CancelSignal, makeCancelSignal } from './make-cancel-signal';
|
|
8
9
|
export { openBrowser } from './open-browser';
|
|
9
10
|
export type { ChromiumOptions } from './open-browser';
|
|
10
11
|
export { renderFrames } from './render-frames';
|
|
@@ -47,11 +48,10 @@ export declare const RenderInternals: {
|
|
|
47
48
|
}) => void;
|
|
48
49
|
normalizeServeUrl: (unnormalized: string) => string;
|
|
49
50
|
spawnFfmpeg: (options: import("./stitch-frames-to-video").StitcherOptions) => Promise<{
|
|
50
|
-
task: Promise<
|
|
51
|
+
task: Promise<void>;
|
|
51
52
|
getLogs: () => string;
|
|
52
53
|
}>;
|
|
53
54
|
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "mp4" | "mkv" | "mov" | "webm";
|
|
54
|
-
makeAssetsDownloadTmpDir: () => string;
|
|
55
55
|
tmpDir: (str: string) => string;
|
|
56
56
|
deleteDirectory: (directory: string) => Promise<void>;
|
|
57
57
|
isServeUrl: (potentialUrl: string) => boolean;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RenderInternals = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.getCompositions = exports.ErrorWithStackFrame = exports.combineVideos = void 0;
|
|
3
|
+
exports.RenderInternals = exports.stitchFramesToVideo = exports.renderStill = exports.renderMedia = exports.renderFrames = exports.openBrowser = exports.makeCancelSignal = exports.getCompositions = exports.ErrorWithStackFrame = exports.combineVideos = void 0;
|
|
4
4
|
const download_file_1 = require("./assets/download-file");
|
|
5
5
|
const delete_directory_1 = require("./delete-directory");
|
|
6
6
|
const ensure_output_directory_1 = require("./ensure-output-directory");
|
|
@@ -14,7 +14,6 @@ const get_extension_of_filename_1 = require("./get-extension-of-filename");
|
|
|
14
14
|
const get_frame_to_render_1 = require("./get-frame-to-render");
|
|
15
15
|
const get_local_browser_executable_1 = require("./get-local-browser-executable");
|
|
16
16
|
const is_serve_url_1 = require("./is-serve-url");
|
|
17
|
-
const make_assets_download_dir_1 = require("./make-assets-download-dir");
|
|
18
17
|
const normalize_serve_url_1 = require("./normalize-serve-url");
|
|
19
18
|
const open_browser_1 = require("./open-browser");
|
|
20
19
|
const parse_browser_error_stack_1 = require("./parse-browser-error-stack");
|
|
@@ -31,6 +30,8 @@ var handle_javascript_exception_1 = require("./error-handling/handle-javascript-
|
|
|
31
30
|
Object.defineProperty(exports, "ErrorWithStackFrame", { enumerable: true, get: function () { return handle_javascript_exception_1.ErrorWithStackFrame; } });
|
|
32
31
|
var get_compositions_1 = require("./get-compositions");
|
|
33
32
|
Object.defineProperty(exports, "getCompositions", { enumerable: true, get: function () { return get_compositions_1.getCompositions; } });
|
|
33
|
+
var make_cancel_signal_1 = require("./make-cancel-signal");
|
|
34
|
+
Object.defineProperty(exports, "makeCancelSignal", { enumerable: true, get: function () { return make_cancel_signal_1.makeCancelSignal; } });
|
|
34
35
|
var open_browser_2 = require("./open-browser");
|
|
35
36
|
Object.defineProperty(exports, "openBrowser", { enumerable: true, get: function () { return open_browser_2.openBrowser; } });
|
|
36
37
|
var render_frames_1 = require("./render-frames");
|
|
@@ -54,7 +55,6 @@ exports.RenderInternals = {
|
|
|
54
55
|
normalizeServeUrl: normalize_serve_url_1.normalizeServeUrl,
|
|
55
56
|
spawnFfmpeg: stitch_frames_to_video_1.spawnFfmpeg,
|
|
56
57
|
getFileExtensionFromCodec: get_extension_from_codec_1.getFileExtensionFromCodec,
|
|
57
|
-
makeAssetsDownloadTmpDir: make_assets_download_dir_1.makeAssetsDownloadTmpDir,
|
|
58
58
|
tmpDir: tmp_dir_1.tmpDir,
|
|
59
59
|
deleteDirectory: delete_directory_1.deleteDirectory,
|
|
60
60
|
isServeUrl: is_serve_url_1.isServeUrl,
|
|
@@ -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,11 @@
|
|
|
1
|
+
import { FfmpegExecutable } from 'remotion';
|
|
2
|
+
export declare type LastFrameOptions = {
|
|
3
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
4
|
+
offset: number;
|
|
5
|
+
src: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const setLastFrameInCache: (options: LastFrameOptions, data: Buffer) => void;
|
|
8
|
+
export declare const getLastFrameFromCache: (options: LastFrameOptions) => Buffer | null;
|
|
9
|
+
export declare const removedLastFrameFromCache: (key: string) => void;
|
|
10
|
+
export declare const ensureMaxSize: () => void;
|
|
11
|
+
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;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeCancelSignal = void 0;
|
|
4
|
+
const makeCancelSignal = () => {
|
|
5
|
+
const callbacks = [];
|
|
6
|
+
let cancelled = false;
|
|
7
|
+
return {
|
|
8
|
+
cancelSignal: (callback) => {
|
|
9
|
+
callbacks.push(callback);
|
|
10
|
+
if (cancelled) {
|
|
11
|
+
callback();
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
cancel: () => {
|
|
15
|
+
if (cancelled) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
callbacks.forEach((cb) => {
|
|
19
|
+
cb();
|
|
20
|
+
});
|
|
21
|
+
cancelled = true;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
exports.makeCancelSignal = makeCancelSignal;
|
|
@@ -30,8 +30,8 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
|
|
|
30
30
|
});
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
// FFMPEG
|
|
34
|
-
if (files.length
|
|
33
|
+
// In FFMPEG, the total number of left and right tracks that can be merged at one time is limited to 64
|
|
34
|
+
if (files.length >= 32) {
|
|
35
35
|
const chunked = (0, chunk_1.chunk)(files, 10);
|
|
36
36
|
const tempPath = (0, tmp_dir_1.tmpDir)('remotion-large-audio-mixing');
|
|
37
37
|
const chunkNames = await Promise.all(chunked.map(async (chunkFiles, i) => {
|
|
@@ -5,4 +5,9 @@ export declare const extractUrlAndSourceFromUrl: (url: string) => {
|
|
|
5
5
|
src: string;
|
|
6
6
|
time: number;
|
|
7
7
|
};
|
|
8
|
-
export declare const startOffthreadVideoServer: (ffmpegExecutable
|
|
8
|
+
export declare const startOffthreadVideoServer: ({ ffmpegExecutable, downloadDir, onDownload, onError, }: {
|
|
9
|
+
ffmpegExecutable: FfmpegExecutable;
|
|
10
|
+
downloadDir: string;
|
|
11
|
+
onDownload: RenderMediaOnDownload;
|
|
12
|
+
onError: (err: Error) => void;
|
|
13
|
+
}) => RequestListener;
|
|
@@ -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, downloadDir, onDownload, onError, }) => {
|
|
26
26
|
return (req, res) => {
|
|
27
27
|
if (!req.url) {
|
|
28
28
|
throw new Error('Request came in without URL');
|
|
@@ -35,14 +35,15 @@ const startOffthreadVideoServer = (ffmpegExecutable, downloadDir, onDownload, on
|
|
|
35
35
|
res.setHeader('access-control-allow-origin', '*');
|
|
36
36
|
res.setHeader('content-type', 'image/jpg');
|
|
37
37
|
const { src, time } = (0, exports.extractUrlAndSourceFromUrl)(req.url);
|
|
38
|
+
const to = (0, download_and_map_assets_to_file_1.getSanitizedFilenameForAssetUrl)({ downloadDir, src });
|
|
38
39
|
(0, download_and_map_assets_to_file_1.startDownloadForSrc)({ src, downloadDir, onDownload }).catch((err) => {
|
|
39
40
|
onError(new Error(`Error while downloading asset: ${err.stack}`));
|
|
40
41
|
});
|
|
41
|
-
(0, download_and_map_assets_to_file_1.waitForAssetToBeDownloaded)(src)
|
|
42
|
-
.then((
|
|
42
|
+
(0, download_and_map_assets_to_file_1.waitForAssetToBeDownloaded)(src, to)
|
|
43
|
+
.then(() => {
|
|
43
44
|
return (0, extract_frame_from_video_1.extractFrameFromVideo)({
|
|
44
45
|
time,
|
|
45
|
-
src:
|
|
46
|
+
src: to,
|
|
46
47
|
ffmpegExecutable,
|
|
47
48
|
});
|
|
48
49
|
})
|
package/dist/open-browser.d.ts
CHANGED
|
@@ -10,9 +10,9 @@ export declare type ChromiumOptions = {
|
|
|
10
10
|
};
|
|
11
11
|
export declare const killAllBrowsers: () => Promise<void>;
|
|
12
12
|
export declare const openBrowser: (browser: Browser, options?: {
|
|
13
|
-
shouldDumpIo?: boolean
|
|
14
|
-
browserExecutable?: string | null
|
|
15
|
-
chromiumOptions?: ChromiumOptions
|
|
16
|
-
forceDeviceScaleFactor?: number
|
|
17
|
-
}
|
|
13
|
+
shouldDumpIo?: boolean;
|
|
14
|
+
browserExecutable?: string | null;
|
|
15
|
+
chromiumOptions?: ChromiumOptions;
|
|
16
|
+
forceDeviceScaleFactor?: number;
|
|
17
|
+
}) => Promise<puppeteer.Browser>;
|
|
18
18
|
export {};
|
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}`
|
|
@@ -115,7 +116,7 @@ const openBrowser = async (browser, options) => {
|
|
|
115
116
|
].filter(Boolean),
|
|
116
117
|
});
|
|
117
118
|
const pages = await browserInstance.pages();
|
|
118
|
-
pages.
|
|
119
|
+
await pages[0].close();
|
|
119
120
|
browserInstances.push(browserInstance);
|
|
120
121
|
return browserInstance;
|
|
121
122
|
};
|
package/dist/prepare-server.js
CHANGED
|
@@ -29,7 +29,7 @@ const prepareServer = async ({ downloadDir, ffmpegExecutable, onDownload, onErro
|
|
|
29
29
|
closeServer: () => {
|
|
30
30
|
return close();
|
|
31
31
|
},
|
|
32
|
-
serveUrl: `http://localhost:${
|
|
32
|
+
serveUrl: `http://localhost:${serverPort}`,
|
|
33
33
|
offthreadPort: serverPort,
|
|
34
34
|
});
|
|
35
35
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import execa from 'execa';
|
|
2
2
|
import { Codec, FfmpegExecutable, ImageFormat, PixelFormat, ProResProfile } from 'remotion';
|
|
3
|
+
import { CancelSignal } from './make-cancel-signal';
|
|
3
4
|
declare type PreSticherOptions = {
|
|
4
5
|
fps: number;
|
|
5
6
|
width: number;
|
|
@@ -13,6 +14,7 @@ declare type PreSticherOptions = {
|
|
|
13
14
|
verbose: boolean;
|
|
14
15
|
ffmpegExecutable: FfmpegExecutable | undefined;
|
|
15
16
|
imageFormat: ImageFormat;
|
|
17
|
+
signal: CancelSignal;
|
|
16
18
|
};
|
|
17
19
|
export declare const prespawnFfmpeg: (options: PreSticherOptions) => Promise<{
|
|
18
20
|
task: execa.ExecaChildProcess<string>;
|
package/dist/prespawn-ffmpeg.js
CHANGED
|
@@ -73,6 +73,9 @@ const prespawnFfmpeg = async (options) => {
|
|
|
73
73
|
}
|
|
74
74
|
const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
|
|
75
75
|
const task = (0, execa_1.default)((_f = options.ffmpegExecutable) !== null && _f !== void 0 ? _f : 'ffmpeg', ffmpegString);
|
|
76
|
+
options.signal(() => {
|
|
77
|
+
task.kill();
|
|
78
|
+
});
|
|
76
79
|
let ffmpegOutput = '';
|
|
77
80
|
(_g = task.stderr) === null || _g === void 0 ? void 0 : _g.on('data', (data) => {
|
|
78
81
|
const str = data.toString();
|
|
@@ -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: {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
package/dist/render-frames.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { BrowserExecutable, FfmpegExecutable, FrameRange, ImageFormat, SmallTCom
|
|
|
4
4
|
import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
|
|
5
5
|
import { BrowserLog } from './browser-log';
|
|
6
6
|
import { ServeUrlOrWebpackBundle } from './legacy-webpack-config';
|
|
7
|
+
import { CancelSignal } from './make-cancel-signal';
|
|
7
8
|
import { ChromiumOptions } from './open-browser';
|
|
8
9
|
import { OnStartData, RenderFramesOutput } from './types';
|
|
9
10
|
declare type ConfigOrComposition = {
|
|
@@ -35,6 +36,7 @@ declare type RenderFramesOptions = {
|
|
|
35
36
|
scale?: number;
|
|
36
37
|
ffmpegExecutable?: FfmpegExecutable;
|
|
37
38
|
port?: number | null;
|
|
39
|
+
cancelSignal?: CancelSignal;
|
|
38
40
|
} & ConfigOrComposition & ServeUrlOrWebpackBundle;
|
|
39
41
|
export declare const renderFrames: (options: RenderFramesOptions) => Promise<RenderFramesOutput>;
|
|
40
42
|
export {};
|