@remotion/renderer 3.2.1 → 3.2.4
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-video-stream-duration.d.ts +1 -0
- package/dist/assets/get-video-stream-duration.js +34 -10
- package/dist/captions-to-ffmpeg-inputs.d.ts +10 -0
- package/dist/captions-to-ffmpeg-inputs.js +21 -0
- package/dist/extract-frame-from-video.d.ts +1 -0
- package/dist/get-extension-from-codec.d.ts +1 -1
- package/dist/guess-extension-for-media.d.ts +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/last-frame-from-video-cache.d.ts +1 -0
- package/dist/merge-audio-track.js +2 -1
- package/dist/render-media.d.ts +1 -1
- package/dist/render-media.js +11 -7
- package/dist/serve-static.js +13 -0
- package/package.json +3 -3
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { FfmpegExecutable } from '../ffmpeg-executable';
|
|
2
2
|
import type { DownloadMap, VideoDurationResult } from './download-map';
|
|
3
|
+
export declare const parseVideoStreamDuration: (stdout: string) => VideoDurationResult;
|
|
3
4
|
export declare const getVideoStreamDuration: (downloadMap: DownloadMap, src: string, ffprobeExecutable: FfmpegExecutable) => Promise<VideoDurationResult>;
|
|
@@ -3,10 +3,41 @@ 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.getVideoStreamDuration = void 0;
|
|
6
|
+
exports.getVideoStreamDuration = exports.parseVideoStreamDuration = void 0;
|
|
7
7
|
const execa_1 = __importDefault(require("execa"));
|
|
8
8
|
const p_limit_1 = require("../p-limit");
|
|
9
9
|
const limit = (0, p_limit_1.pLimit)(1);
|
|
10
|
+
const parseAlternativeDuration = (stdout) => {
|
|
11
|
+
const webmDuration = stdout.match(/TAG:DURATION=([0-9.]+):([0-9.]+):([0-9.]+)/);
|
|
12
|
+
if (!webmDuration) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const [, hours, minutes, seconds] = webmDuration;
|
|
16
|
+
const hoursAsNumber = Number(hours);
|
|
17
|
+
if (Number.isNaN(hoursAsNumber)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const minutesAsNumber = Number(minutes);
|
|
21
|
+
if (Number.isNaN(minutesAsNumber)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const secondsAsNumber = Number(seconds);
|
|
25
|
+
if (Number.isNaN(secondsAsNumber)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return secondsAsNumber + minutesAsNumber * 60 + hoursAsNumber * 3600;
|
|
29
|
+
};
|
|
30
|
+
const parseVideoStreamDuration = (stdout) => {
|
|
31
|
+
const duration = stdout.match(/duration=([0-9.]+)/);
|
|
32
|
+
const alternativeDuration = parseAlternativeDuration(stdout);
|
|
33
|
+
const fps = stdout.match(/r_frame_rate=([0-9.]+)\/([0-9.]+)/);
|
|
34
|
+
const result = {
|
|
35
|
+
duration: duration ? parseFloat(duration[1]) : alternativeDuration,
|
|
36
|
+
fps: fps ? parseInt(fps[1], 10) / parseInt(fps[2], 10) : null,
|
|
37
|
+
};
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
exports.parseVideoStreamDuration = parseVideoStreamDuration;
|
|
10
41
|
async function getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutable) {
|
|
11
42
|
if (downloadMap.videoDurationResultCache[src]) {
|
|
12
43
|
return downloadMap.videoDurationResultCache[src];
|
|
@@ -14,20 +45,13 @@ async function getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutab
|
|
|
14
45
|
const args = [
|
|
15
46
|
['-v', 'error'],
|
|
16
47
|
['-select_streams', 'v:0'],
|
|
17
|
-
['-show_entries', 'stream
|
|
48
|
+
['-show_entries', 'stream'],
|
|
18
49
|
[src],
|
|
19
50
|
]
|
|
20
51
|
.reduce((acc, val) => acc.concat(val), [])
|
|
21
52
|
.filter(Boolean);
|
|
22
53
|
const task = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', args);
|
|
23
|
-
|
|
24
|
-
const fps = task.stdout.match(/r_frame_rate=([0-9.]+)\/([0-9.]+)/);
|
|
25
|
-
const result = {
|
|
26
|
-
duration: duration ? parseFloat(duration[1]) : null,
|
|
27
|
-
fps: fps ? parseInt(fps[1], 10) / parseInt(fps[2], 10) : null,
|
|
28
|
-
};
|
|
29
|
-
downloadMap.videoDurationResultCache[src] = result;
|
|
30
|
-
return result;
|
|
54
|
+
return (0, exports.parseVideoStreamDuration)(task.stdout);
|
|
31
55
|
}
|
|
32
56
|
const getVideoStreamDuration = (downloadMap, src, ffprobeExecutable) => {
|
|
33
57
|
return limit(() => getVideoStreamDurationUnlimited(downloadMap, src, ffprobeExecutable));
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TCaption } from 'remotion';
|
|
2
|
+
interface CaptionFfmpegInputs {
|
|
3
|
+
captionFilters: string[];
|
|
4
|
+
captionInputs: [string, string][];
|
|
5
|
+
}
|
|
6
|
+
export declare const captionsToFfmpegInputs: ({ assetsCount, captions, }: {
|
|
7
|
+
assetsCount: number;
|
|
8
|
+
captions: TCaption[][];
|
|
9
|
+
}) => CaptionFfmpegInputs;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.captionsToFfmpegInputs = void 0;
|
|
4
|
+
const captionsToFfmpegInputs = ({ assetsCount, captions, }) => {
|
|
5
|
+
const uniqueCaptions = Object.values(captions.flat(1).reduce((acc, caption) => {
|
|
6
|
+
acc[caption.id] = caption;
|
|
7
|
+
return acc;
|
|
8
|
+
}, {}));
|
|
9
|
+
/**
|
|
10
|
+
* TODO: Support more formats.
|
|
11
|
+
* `mov_text` works for SRT.
|
|
12
|
+
*/
|
|
13
|
+
const getFilter = ({ language, title }, index) => {
|
|
14
|
+
return ['-map', `${assetsCount + 1 + index}:s`, '-c:s', 'mov_text'].concat(language ? [`-metadata:s:s:${index}`, `language=${language}`] : '', title ? [`-metadata:s:s:${index}`, `title=${title}`] : '');
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
captionInputs: uniqueCaptions.map((caption) => ['-i', caption.src]),
|
|
18
|
+
captionFilters: uniqueCaptions.reduce((acc, caption, i) => acc.concat(getFilter(caption, i)), []),
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.captionsToFfmpegInputs = captionsToFfmpegInputs;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { Codec } from './codec';
|
|
2
|
-
export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "
|
|
2
|
+
export declare const getFileExtensionFromCodec: (codec: Codec, type: 'chunk' | 'final') => "mp3" | "aac" | "wav" | "gif" | "webm" | "mp4" | "mov" | "mkv";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const guessExtensionForVideo: (src: string) => Promise<"mp3" | "wav" | "
|
|
1
|
+
export declare const guessExtensionForVideo: (src: string) => Promise<"mp3" | "wav" | "webm" | "mp4">;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import execa from 'execa';
|
|
3
2
|
import { SymbolicateableError } from './error-handling/symbolicateable-error';
|
|
4
3
|
import { mimeContentType, mimeLookup } from './mime-types';
|
|
@@ -137,7 +136,7 @@ export declare const RenderInternals: {
|
|
|
137
136
|
getValidCrfRanges: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => [number, number];
|
|
138
137
|
validateSelectedPixelFormatAndCodecCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => void;
|
|
139
138
|
validateSelectedCodecAndProResCombination: (actualCodec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", actualProResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined) => void;
|
|
140
|
-
validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "
|
|
139
|
+
validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "png" | "jpeg" | "none") => "none" | "valid";
|
|
141
140
|
DEFAULT_CODEC: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif";
|
|
142
141
|
isAudioCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif" | undefined) => boolean;
|
|
143
142
|
logLevels: readonly ["verbose", "info", "warn", "error"];
|
|
@@ -70,7 +70,8 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
|
|
|
70
70
|
await task;
|
|
71
71
|
cleanup();
|
|
72
72
|
};
|
|
73
|
-
|
|
73
|
+
// Must be at least 3 because recursively called twice in mergeAudioTrack
|
|
74
|
+
const limit = (0, p_limit_1.pLimit)(3);
|
|
74
75
|
const mergeAudioTrack = (options) => {
|
|
75
76
|
return limit(mergeAudioTrackUnlimited, options);
|
|
76
77
|
};
|
package/dist/render-media.d.ts
CHANGED
|
@@ -64,4 +64,4 @@ export declare type RenderMediaOptions = {
|
|
|
64
64
|
* @description Render a video from a composition
|
|
65
65
|
* @link https://www.remotion.dev/docs/renderer/render-media
|
|
66
66
|
*/
|
|
67
|
-
export declare const renderMedia: ({ parallelism, proResProfile, crf, composition,
|
|
67
|
+
export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ...options }: RenderMediaOptions) => Promise<Buffer | null>;
|
package/dist/render-media.js
CHANGED
|
@@ -19,6 +19,7 @@ const get_duration_from_frame_range_1 = require("./get-duration-from-frame-range
|
|
|
19
19
|
const get_extension_from_codec_1 = require("./get-extension-from-codec");
|
|
20
20
|
const get_extension_of_filename_1 = require("./get-extension-of-filename");
|
|
21
21
|
const get_frame_to_render_1 = require("./get-frame-to-render");
|
|
22
|
+
const is_audio_codec_1 = require("./is-audio-codec");
|
|
22
23
|
const legacy_webpack_config_1 = require("./legacy-webpack-config");
|
|
23
24
|
const make_cancel_signal_1 = require("./make-cancel-signal");
|
|
24
25
|
const overwrite_1 = require("./overwrite");
|
|
@@ -36,9 +37,9 @@ const validate_scale_1 = require("./validate-scale");
|
|
|
36
37
|
* @description Render a video from a composition
|
|
37
38
|
* @link https://www.remotion.dev/docs/renderer/render-media
|
|
38
39
|
*/
|
|
39
|
-
const renderMedia = ({ parallelism, proResProfile, crf, composition,
|
|
40
|
-
var _a, _b, _c;
|
|
41
|
-
(0, quality_1.validateQuality)(quality);
|
|
40
|
+
const renderMedia = ({ parallelism, proResProfile, crf, composition, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ...options }) => {
|
|
41
|
+
var _a, _b, _c, _d;
|
|
42
|
+
(0, quality_1.validateQuality)(options.quality);
|
|
42
43
|
if (typeof crf !== 'undefined' && crf !== null) {
|
|
43
44
|
(0, crf_1.validateSelectedCrfAndCodecCombination)(crf, codec);
|
|
44
45
|
}
|
|
@@ -74,7 +75,10 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
74
75
|
console.log('[PRESTITCHER] Parallel encoding is disabled.');
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
|
-
const
|
|
78
|
+
const imageFormat = (0, is_audio_codec_1.isAudioCodec)(codec)
|
|
79
|
+
? 'none'
|
|
80
|
+
: (_d = options.imageFormat) !== null && _d !== void 0 ? _d : 'jpeg';
|
|
81
|
+
const quality = imageFormat === 'jpeg' ? options.quality : undefined;
|
|
78
82
|
const preEncodedFileLocation = parallelEncoding
|
|
79
83
|
? path_1.default.join(downloadMap.preEncode, 'pre-encode.' + (0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, 'chunk'))
|
|
80
84
|
: null;
|
|
@@ -124,7 +128,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
124
128
|
},
|
|
125
129
|
verbose: (_a = options.verbose) !== null && _a !== void 0 ? _a : false,
|
|
126
130
|
ffmpegExecutable,
|
|
127
|
-
imageFormat
|
|
131
|
+
imageFormat,
|
|
128
132
|
signal: cancelPrestitcher.cancelSignal,
|
|
129
133
|
});
|
|
130
134
|
stitcherFfmpeg = preStitcher.task;
|
|
@@ -162,7 +166,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
162
166
|
},
|
|
163
167
|
inputProps,
|
|
164
168
|
envVariables,
|
|
165
|
-
imageFormat
|
|
169
|
+
imageFormat,
|
|
166
170
|
quality,
|
|
167
171
|
frameRange: frameRange !== null && frameRange !== void 0 ? frameRange : null,
|
|
168
172
|
puppeteerInstance,
|
|
@@ -215,7 +219,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
|
|
|
215
219
|
outputLocation,
|
|
216
220
|
internalOptions: {
|
|
217
221
|
preEncodedFileLocation,
|
|
218
|
-
imageFormat
|
|
222
|
+
imageFormat,
|
|
219
223
|
},
|
|
220
224
|
force: overwrite !== null && overwrite !== void 0 ? overwrite : overwrite_1.DEFAULT_OVERWRITE,
|
|
221
225
|
pixelFormat,
|
package/dist/serve-static.js
CHANGED
|
@@ -19,6 +19,7 @@ const serveStatic = async (path, options) => {
|
|
|
19
19
|
downloadMap: options.downloadMap,
|
|
20
20
|
});
|
|
21
21
|
try {
|
|
22
|
+
const connections = {};
|
|
22
23
|
const server = http_1.default
|
|
23
24
|
.createServer((request, response) => {
|
|
24
25
|
var _a;
|
|
@@ -38,8 +39,20 @@ const serveStatic = async (path, options) => {
|
|
|
38
39
|
});
|
|
39
40
|
})
|
|
40
41
|
.listen(port);
|
|
42
|
+
server.on('connection', (conn) => {
|
|
43
|
+
const key = conn.remoteAddress + ':' + conn.remotePort;
|
|
44
|
+
connections[key] = conn;
|
|
45
|
+
conn.on('close', () => {
|
|
46
|
+
delete connections[key];
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
const destroyConnections = function () {
|
|
50
|
+
for (const key in connections)
|
|
51
|
+
connections[key].destroy();
|
|
52
|
+
};
|
|
41
53
|
const close = () => {
|
|
42
54
|
return new Promise((resolve, reject) => {
|
|
55
|
+
destroyConnections();
|
|
43
56
|
server.close((err) => {
|
|
44
57
|
if (err) {
|
|
45
58
|
if (err.code === 'ERR_SERVER_NOT_RUNNING') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/renderer",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.4",
|
|
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
|
"extract-zip": "2.0.1",
|
|
25
|
-
"remotion": "3.2.
|
|
25
|
+
"remotion": "3.2.4",
|
|
26
26
|
"source-map": "^0.8.0-beta.0",
|
|
27
27
|
"ws": "8.7.0"
|
|
28
28
|
},
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "ee420b99227e0e5bcf093c108e3695f5d46e3658"
|
|
61
61
|
}
|