@remotion/renderer 3.0.16 → 3.0.19
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/cleanup-assets.d.ts +2 -0
- package/dist/assets/cleanup-assets.js +2 -0
- package/dist/assets/get-audio-channels.d.ts +2 -1
- package/dist/assets/get-audio-channels.js +2 -2
- package/dist/calculate-ffmpeg-filters.js +2 -2
- package/dist/combine-videos.js +3 -0
- package/dist/ensure-faststart.d.ts +1 -0
- package/dist/ensure-faststart.js +14 -0
- package/dist/extract-frame-from-video.d.ts +4 -6
- package/dist/extract-frame-from-video.js +104 -31
- package/dist/faststart/atom.d.ts +35 -0
- package/dist/faststart/atom.js +138 -0
- package/dist/faststart/index.d.ts +0 -0
- package/dist/faststart/index.js +1 -0
- package/dist/faststart/options.d.ts +6 -0
- package/dist/faststart/options.js +2 -0
- package/dist/faststart/qt-faststart.d.ts +18 -0
- package/dist/faststart/qt-faststart.js +66 -0
- package/dist/faststart/update-chunk-offsets.d.ts +10 -0
- package/dist/faststart/update-chunk-offsets.js +114 -0
- package/dist/faststart/util.d.ts +9 -0
- package/dist/faststart/util.js +34 -0
- package/dist/get-compositions.d.ts +1 -0
- package/dist/get-compositions.js +3 -2
- package/dist/get-duration-of-asset.d.ts +7 -0
- package/dist/get-duration-of-asset.js +36 -0
- 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 +13 -0
- package/dist/last-frame-from-video-cache.js +52 -0
- package/dist/make-assets-download-dir.js +6 -1
- package/dist/offthread-video-server.d.ts +2 -1
- package/dist/offthread-video-server.js +3 -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-gif.d.ts +2 -0
- package/dist/render-gif.js +242 -0
- package/dist/render-media.d.ts +7 -1
- package/dist/render-media.js +10 -1
- package/dist/render-still.d.ts +4 -1
- package/dist/render-still.js +7 -4
- 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
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/* eslint-disable no-bitwise */
|
|
4
|
+
const atom_1 = require("./atom");
|
|
5
|
+
/**
|
|
6
|
+
* Adds the specified offset to each entry in stco/co64 atoms
|
|
7
|
+
*
|
|
8
|
+
* @param atoms QT atoms to traverse
|
|
9
|
+
* @param offset offset to add
|
|
10
|
+
* @param forceUpgrade always upgrade stco atoms to co64
|
|
11
|
+
*/
|
|
12
|
+
function updateChunkOffsets(moov, options) {
|
|
13
|
+
const atoms = moov.data;
|
|
14
|
+
const originalMoovSize = Number(moov.size);
|
|
15
|
+
let newChunksSize = 0;
|
|
16
|
+
let originalChunksSize = 0;
|
|
17
|
+
// First pass to count total entries, which is needed for co64 upgrades.
|
|
18
|
+
(0, atom_1.traverseAtoms)(atoms, (atom) => {
|
|
19
|
+
if (!['stco', 'co64'].includes(atom.kind) || !Buffer.isBuffer(atom.data)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const entries = atom.data.readUInt32BE(4);
|
|
23
|
+
const originalEntrySize = isCo64(atom.kind) ? 8 : 4;
|
|
24
|
+
originalChunksSize += entries * originalEntrySize;
|
|
25
|
+
const newEntrySize = isCo64(atom.kind) || options.forceUpgradeToCo64 ? 8 : 4;
|
|
26
|
+
newChunksSize += entries * newEntrySize;
|
|
27
|
+
});
|
|
28
|
+
// Calculate new mdat offsets to add to stco/co64 chunk offset values
|
|
29
|
+
const totalOffset = originalMoovSize - originalChunksSize + newChunksSize;
|
|
30
|
+
// Second pass to actually update offsets.
|
|
31
|
+
(0, atom_1.traverseAtoms)(atoms, (atom) => {
|
|
32
|
+
if (!['stco', 'co64'].includes(atom.kind) || !Buffer.isBuffer(atom.data)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const overflow = updateChunkAtom(atom, totalOffset, options);
|
|
36
|
+
if (!overflow) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
upgradeStcoToCo64(atom, totalOffset);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
exports.default = updateChunkOffsets;
|
|
43
|
+
/**
|
|
44
|
+
* Updates `stco` or `co64` atoms' chunk offsets.
|
|
45
|
+
*
|
|
46
|
+
* @param atom `stco` or `co64` to update chunk offsets of
|
|
47
|
+
* @param totalOffset the total offset value to add to the existing chunk offsets
|
|
48
|
+
* @param options
|
|
49
|
+
* @returns {boolean} `true` if overflowed (did not finish updating chunks), `false` if succeeded
|
|
50
|
+
*/
|
|
51
|
+
function updateChunkAtom(atom, totalOffset, options) {
|
|
52
|
+
if (!Buffer.isBuffer(atom.data)) {
|
|
53
|
+
throw new Error(`${atom.kind} data is not a Buffer!`);
|
|
54
|
+
}
|
|
55
|
+
let overflow = false;
|
|
56
|
+
const entrySize = isCo64(atom.kind) ? 8 : 4;
|
|
57
|
+
const entries = atom.data.readUInt32BE(4);
|
|
58
|
+
const newData = Buffer.alloc(8 + entries * entrySize); // 8 byte header
|
|
59
|
+
atom.data.copy(newData, 0, 0, 8); // copy header
|
|
60
|
+
for (let i = 0; i < entries; i++) {
|
|
61
|
+
const cur = 8 + i * entrySize; // 8 byte header
|
|
62
|
+
if (isCo64(atom.kind)) {
|
|
63
|
+
const newVal64 = Number((BigInt(atom.data.readUInt32BE(cur)) << BigInt(32)) |
|
|
64
|
+
BigInt(atom.data.readUInt32BE(cur + 4))) + totalOffset;
|
|
65
|
+
newData.writeUInt32BE(Number((BigInt(newVal64) >> BigInt(32)) & BigInt(0xffffffff)), cur);
|
|
66
|
+
newData.writeUInt32BE(Number(BigInt(newVal64) & BigInt(0xffffffff)), cur + 4);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (options.forceUpgradeToCo64) {
|
|
70
|
+
overflow = true;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
const newVal32 = atom.data.readUInt32BE(cur) + totalOffset;
|
|
74
|
+
if (newVal32 > 2 ** 32 - 1) {
|
|
75
|
+
overflow = true;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
newData.writeUInt32BE(newVal32, cur);
|
|
79
|
+
}
|
|
80
|
+
if (!overflow) {
|
|
81
|
+
atom.data = newData;
|
|
82
|
+
}
|
|
83
|
+
return overflow;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* **Upgrades** `stco` atom to a `co64` atom and also updates the chunk offsets.
|
|
87
|
+
*
|
|
88
|
+
* @param atom `stco` or `co64` to update chunk offsets of
|
|
89
|
+
* @param totalOffset the total offset value to add to the existing chunk offsets
|
|
90
|
+
*/
|
|
91
|
+
function upgradeStcoToCo64(atom, totalOffset) {
|
|
92
|
+
if (!Buffer.isBuffer(atom.data)) {
|
|
93
|
+
throw new Error(`${atom.kind} data is not a Buffer!`);
|
|
94
|
+
}
|
|
95
|
+
// Upgrade to stco atoms to co64 atoms
|
|
96
|
+
const entries = atom.data.readUInt32BE(4);
|
|
97
|
+
const upgradedData = Buffer.alloc(8 + entries * 8); // 8-byte header, 8-byte entry size
|
|
98
|
+
atom.data.copy(upgradedData, 0, 0, 8);
|
|
99
|
+
upgradedData.writeUInt32BE((entries >> 32) & 0xffffffff, 8); // MSB 64-bit size
|
|
100
|
+
upgradedData.writeUInt32BE(entries & 0xffffffff, 12); // LSB 64-bit size
|
|
101
|
+
for (let i = 0; i < entries; i++) {
|
|
102
|
+
const cur32 = 8 + i * 4; // 8-byte header, 4-byte entry size for READS (stco)
|
|
103
|
+
const newVal = atom.data.readUInt32BE(cur32) + totalOffset;
|
|
104
|
+
const cur64 = 8 + i * 8; // 8-byte header, 8-byte entry size for WRITES (co64)
|
|
105
|
+
upgradedData.writeUInt32BE(Number((BigInt(newVal) >> BigInt(32)) & BigInt(0xffffffff)), cur64);
|
|
106
|
+
upgradedData.writeUInt32BE(Number(BigInt(newVal) & BigInt(0xffffffff)), cur64 + 4);
|
|
107
|
+
}
|
|
108
|
+
atom.kind = 'co64';
|
|
109
|
+
atom.data = upgradedData;
|
|
110
|
+
atom.size = atom_1.ATOM_PREAMBLE_SIZE * BigInt(2) + BigInt(upgradedData.byteLength);
|
|
111
|
+
}
|
|
112
|
+
function isCo64(atomKind) {
|
|
113
|
+
return atomKind === 'co64';
|
|
114
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export interface Cursor {
|
|
3
|
+
pos: bigint;
|
|
4
|
+
}
|
|
5
|
+
export declare function numToHex(val: number): string;
|
|
6
|
+
export declare function asciiToU32Be(chars: string): number;
|
|
7
|
+
export declare function u32BeToAscii(u32: number): string;
|
|
8
|
+
export declare function readU32(cur: Cursor, buf: Buffer): number;
|
|
9
|
+
export declare function readU64(cur: Cursor, buf: Buffer): bigint;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.readU64 = exports.readU32 = exports.u32BeToAscii = exports.asciiToU32Be = exports.numToHex = void 0;
|
|
4
|
+
function numToHex(val) {
|
|
5
|
+
return val.toString(16);
|
|
6
|
+
}
|
|
7
|
+
exports.numToHex = numToHex;
|
|
8
|
+
function asciiToU32Be(chars) {
|
|
9
|
+
return Buffer.from(chars.split('').map((char) => char.charCodeAt(0))).readUInt32BE(0);
|
|
10
|
+
}
|
|
11
|
+
exports.asciiToU32Be = asciiToU32Be;
|
|
12
|
+
function u32BeToAscii(u32) {
|
|
13
|
+
const buf = Buffer.alloc(4);
|
|
14
|
+
buf.writeUInt32BE(u32, 0);
|
|
15
|
+
return buf.toString('ascii');
|
|
16
|
+
}
|
|
17
|
+
exports.u32BeToAscii = u32BeToAscii;
|
|
18
|
+
function readU32(cur, buf) {
|
|
19
|
+
const u32 = buf.readUInt32BE(Number(cur.pos));
|
|
20
|
+
cur.pos += BigInt(4);
|
|
21
|
+
return u32;
|
|
22
|
+
}
|
|
23
|
+
exports.readU32 = readU32;
|
|
24
|
+
function readU64(cur, buf) {
|
|
25
|
+
const long = buf.slice(Number(cur.pos), Number(cur.pos + BigInt(8)));
|
|
26
|
+
const u64 =
|
|
27
|
+
// eslint-disable-next-line no-bitwise
|
|
28
|
+
(BigInt(long.readUInt32BE(0)) << BigInt(32)) |
|
|
29
|
+
// eslint-disable-next-line no-bitwise
|
|
30
|
+
(BigInt(long.readUInt32BE(4)) & BigInt(0xffffffff));
|
|
31
|
+
cur.pos += BigInt(8);
|
|
32
|
+
return u64;
|
|
33
|
+
}
|
|
34
|
+
exports.readU64 = readU64;
|
|
@@ -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;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getDurationOfAsset = void 0;
|
|
7
|
+
const execa_1 = __importDefault(require("execa"));
|
|
8
|
+
const p_limit_1 = require("./p-limit");
|
|
9
|
+
const durationOfAssetCache = {};
|
|
10
|
+
const limit = (0, p_limit_1.pLimit)(1);
|
|
11
|
+
const getDurationOfAssetUnlimited = async ({ ffprobeExecutable, src, }) => {
|
|
12
|
+
if (durationOfAssetCache[src]) {
|
|
13
|
+
return durationOfAssetCache[src];
|
|
14
|
+
}
|
|
15
|
+
const durationCmd = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', [
|
|
16
|
+
'-v',
|
|
17
|
+
'error',
|
|
18
|
+
'-select_streams',
|
|
19
|
+
'v:0',
|
|
20
|
+
'-show_entries',
|
|
21
|
+
'stream=duration',
|
|
22
|
+
'-of',
|
|
23
|
+
'default=noprint_wrappers=1:nokey=1',
|
|
24
|
+
src,
|
|
25
|
+
]);
|
|
26
|
+
const duration = parseFloat(durationCmd.stdout);
|
|
27
|
+
if (Number.isNaN(duration)) {
|
|
28
|
+
throw new TypeError(`Could not get duration of ${src}: ${durationCmd.stdout}`);
|
|
29
|
+
}
|
|
30
|
+
durationOfAssetCache[src] = duration;
|
|
31
|
+
return duration;
|
|
32
|
+
};
|
|
33
|
+
const getDurationOfAsset = (options) => {
|
|
34
|
+
return limit(getDurationOfAssetUnlimited, options);
|
|
35
|
+
};
|
|
36
|
+
exports.getDurationOfAsset = getDurationOfAsset;
|
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,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;
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.makeAssetsDownloadTmpDir = void 0;
|
|
4
4
|
const tmp_dir_1 = require("./tmp-dir");
|
|
5
|
+
let dir = null;
|
|
5
6
|
const makeAssetsDownloadTmpDir = () => {
|
|
6
|
-
|
|
7
|
+
if (dir) {
|
|
8
|
+
return dir;
|
|
9
|
+
}
|
|
10
|
+
dir = (0, tmp_dir_1.tmpDir)('remotion-assets-dir');
|
|
11
|
+
return dir;
|
|
7
12
|
};
|
|
8
13
|
exports.makeAssetsDownloadTmpDir = makeAssetsDownloadTmpDir;
|
|
@@ -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) => {
|
|
@@ -58,6 +59,7 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, downloadDir, onDownload,
|
|
|
58
59
|
.catch((err) => {
|
|
59
60
|
res.writeHead(500);
|
|
60
61
|
res.end();
|
|
62
|
+
onError(err);
|
|
61
63
|
console.log('Error occurred', err);
|
|
62
64
|
});
|
|
63
65
|
};
|
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>;
|