@remotion/renderer 3.2.12-crf.7 → 3.2.12
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/codec-supports-media.d.ts +0 -1
- package/dist/codec-supports-media.js +1 -8
- package/dist/combine-videos.d.ts +1 -2
- package/dist/combine-videos.js +1 -5
- package/dist/create-ffmpeg-complex-filter.d.ts +4 -1
- package/dist/extract-frame-from-video.d.ts +0 -1
- package/dist/extract-frame-from-video.js +7 -30
- 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 +6 -7
- package/dist/last-frame-from-video-cache.d.ts +0 -1
- package/dist/make-assets-download-dir.d.ts +1 -0
- package/dist/make-assets-download-dir.js +13 -0
- package/dist/provide-screenshot.d.ts +0 -1
- package/dist/puppeteer-screenshot.d.ts +0 -1
- package/dist/render-media.d.ts +0 -1
- package/dist/screenshot-dom-element.d.ts +0 -1
- package/dist/screenshot-task.d.ts +0 -1
- package/dist/stitch-frames-to-video.js +1 -1
- package/package.json +3 -3
- package/dist/captions-to-ffmpeg-inputs.d.ts +0 -10
- package/dist/captions-to-ffmpeg-inputs.js +0 -21
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const get_codec_name_1 = require("./get-codec-name");
|
|
3
|
+
exports.codecSupportsMedia = void 0;
|
|
5
4
|
const support = {
|
|
6
5
|
'h264-mkv': {
|
|
7
6
|
audio: true,
|
|
@@ -48,9 +47,3 @@ const codecSupportsMedia = (codec) => {
|
|
|
48
47
|
return support[codec];
|
|
49
48
|
};
|
|
50
49
|
exports.codecSupportsMedia = codecSupportsMedia;
|
|
51
|
-
const codecSupportsCrf = (codec) => {
|
|
52
|
-
const encoderName = (0, get_codec_name_1.getCodecName)(codec);
|
|
53
|
-
const supportsCrf = encoderName && codec !== 'prores';
|
|
54
|
-
return supportsCrf;
|
|
55
|
-
};
|
|
56
|
-
exports.codecSupportsCrf = codecSupportsCrf;
|
package/dist/combine-videos.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Codec } from './codec';
|
|
2
|
-
export declare const combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops,
|
|
2
|
+
export declare const combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, }: {
|
|
3
3
|
files: string[];
|
|
4
4
|
filelistDir: string;
|
|
5
5
|
output: string;
|
|
@@ -8,5 +8,4 @@ export declare const combineVideos: ({ files, filelistDir, output, onProgress, n
|
|
|
8
8
|
codec: Codec;
|
|
9
9
|
fps: number;
|
|
10
10
|
numberOfGifLoops: number | null;
|
|
11
|
-
crf: number | null;
|
|
12
11
|
}) => Promise<void>;
|
package/dist/combine-videos.js
CHANGED
|
@@ -8,17 +8,15 @@ exports.combineVideos = void 0;
|
|
|
8
8
|
const execa_1 = __importDefault(require("execa"));
|
|
9
9
|
const fs_1 = require("fs");
|
|
10
10
|
const path_1 = require("path");
|
|
11
|
-
const codec_supports_media_1 = require("./codec-supports-media");
|
|
12
11
|
const get_audio_codec_name_1 = require("./get-audio-codec-name");
|
|
13
12
|
const is_audio_codec_1 = require("./is-audio-codec");
|
|
14
13
|
const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
|
|
15
14
|
const truthy_1 = require("./truthy");
|
|
16
|
-
const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops,
|
|
15
|
+
const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, }) => {
|
|
17
16
|
var _a;
|
|
18
17
|
const fileList = files.map((p) => `file '${p}'`).join('\n');
|
|
19
18
|
const fileListTxt = (0, path_1.join)(filelistDir, 'files.txt');
|
|
20
19
|
(0, fs_1.writeFileSync)(fileListTxt, fileList);
|
|
21
|
-
const supportsCrf = (0, codec_supports_media_1.codecSupportsCrf)(codec);
|
|
22
20
|
try {
|
|
23
21
|
const task = (0, execa_1.default)('ffmpeg', [
|
|
24
22
|
(0, is_audio_codec_1.isAudioCodec)(codec) ? null : '-r',
|
|
@@ -42,8 +40,6 @@ const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfF
|
|
|
42
40
|
// Set max bitrate up to 1024kbps, will choose lower if that's too much
|
|
43
41
|
'-b:a',
|
|
44
42
|
'512K',
|
|
45
|
-
supportsCrf ? '-crf' : null,
|
|
46
|
-
supportsCrf ? String(crf) : null,
|
|
47
43
|
codec === 'h264' ? '-movflags' : null,
|
|
48
44
|
codec === 'h264' ? 'faststart' : null,
|
|
49
45
|
'-shortest',
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { DownloadMap } from './assets/download-map';
|
|
2
2
|
export declare const createFfmpegComplexFilter: (filters: number, downloadMap: DownloadMap) => Promise<{
|
|
3
|
-
complexFilterFlag: [
|
|
3
|
+
complexFilterFlag: [
|
|
4
|
+
string,
|
|
5
|
+
string
|
|
6
|
+
] | null;
|
|
4
7
|
cleanup: () => void;
|
|
5
8
|
}>;
|
|
@@ -32,9 +32,9 @@ const determineResizeParams = (needsResize) => {
|
|
|
32
32
|
};
|
|
33
33
|
// Uses no seeking, therefore the whole video has to be decoded. This is a last resort and should only happen
|
|
34
34
|
// if the video is corrupted
|
|
35
|
-
const getFrameOfVideoSlow = async ({ src,
|
|
36
|
-
console.warn(`\nUsing a slow method to extract the frame at ${
|
|
37
|
-
const actualOffset = `-${
|
|
35
|
+
const getFrameOfVideoSlow = async ({ src, timestamp, ffmpegExecutable, imageFormat, specialVCodecForTransparency, needsResize, }) => {
|
|
36
|
+
console.warn(`\nUsing a slow method to extract the frame at ${timestamp}ms of ${src}. See https://remotion.dev/docs/slow-method-to-extract-frame for advice`);
|
|
37
|
+
const actualOffset = `-${timestamp * 1000}ms`;
|
|
38
38
|
const command = [
|
|
39
39
|
'-itsoffset',
|
|
40
40
|
actualOffset,
|
|
@@ -72,20 +72,7 @@ const getFrameOfVideoSlow = async ({ src, duration, ffmpegExecutable, imageForma
|
|
|
72
72
|
const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
|
|
73
73
|
const isEmpty = stdErr.includes('Output file is empty');
|
|
74
74
|
if (isEmpty) {
|
|
75
|
-
|
|
76
|
-
throw new Error(`Could not get last frame of ${src}. Tried to seek to the end using the command "ffmpeg ${command.join(' ')}" but got no frame. Most likely this video is corrupted.`);
|
|
77
|
-
}
|
|
78
|
-
return getFrameOfVideoSlow({
|
|
79
|
-
ffmpegExecutable,
|
|
80
|
-
duration,
|
|
81
|
-
// Decrement in 10ms increments, or 1 frame (e.g. fps = 25 --> 40ms)
|
|
82
|
-
offset: offset + (fps === null ? 10 : 1000 / fps),
|
|
83
|
-
src,
|
|
84
|
-
imageFormat,
|
|
85
|
-
specialVCodecForTransparency,
|
|
86
|
-
needsResize,
|
|
87
|
-
fps,
|
|
88
|
-
});
|
|
75
|
+
throw new Error(`Could not get last frame of ${src}. Tried to seek to the end using the command "ffmpeg ${command.join(' ')}" but got no frame. Most likely this video is corrupted.`);
|
|
89
76
|
}
|
|
90
77
|
return stdoutBuffer;
|
|
91
78
|
};
|
|
@@ -101,14 +88,12 @@ const getLastFrameOfVideoFastUnlimited = async (options) => {
|
|
|
101
88
|
}
|
|
102
89
|
if (options.specialVCodecForTransparency === 'vp8' || offset > 40) {
|
|
103
90
|
const last = await getFrameOfVideoSlow({
|
|
104
|
-
duration,
|
|
91
|
+
timestamp: duration,
|
|
105
92
|
ffmpegExecutable,
|
|
106
93
|
src,
|
|
107
94
|
imageFormat: options.imageFormat,
|
|
108
95
|
specialVCodecForTransparency: options.specialVCodecForTransparency,
|
|
109
96
|
needsResize: options.needsResize,
|
|
110
|
-
offset: offset - 1000 / (fps === null ? 10 : fps),
|
|
111
|
-
fps,
|
|
112
97
|
});
|
|
113
98
|
return last;
|
|
114
99
|
}
|
|
@@ -158,7 +143,7 @@ const getLastFrameOfVideoFastUnlimited = async (options) => {
|
|
|
158
143
|
const unlimited = await getLastFrameOfVideoFastUnlimited({
|
|
159
144
|
ffmpegExecutable,
|
|
160
145
|
// Decrement in 10ms increments, or 1 frame (e.g. fps = 25 --> 40ms)
|
|
161
|
-
offset: offset + (fps === null ? 10 :
|
|
146
|
+
offset: offset + 1000 / (fps === null ? 10 : fps),
|
|
162
147
|
src,
|
|
163
148
|
ffprobeExecutable,
|
|
164
149
|
imageFormat: options.imageFormat,
|
|
@@ -182,16 +167,13 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
|
|
|
182
167
|
const src = await (0, ensure_presentation_timestamp_1.ensurePresentationTimestamps)(downloadMap, options.src);
|
|
183
168
|
const { specialVcodec, needsResize } = await (0, get_video_info_1.getVideoInfo)(downloadMap, src, ffprobeExecutable);
|
|
184
169
|
if (specialVcodec === 'vp8') {
|
|
185
|
-
const { fps } = await (0, get_video_stream_duration_1.getVideoStreamDuration)(downloadMap, src, ffprobeExecutable);
|
|
186
170
|
return getFrameOfVideoSlow({
|
|
187
171
|
ffmpegExecutable,
|
|
188
172
|
imageFormat,
|
|
189
173
|
specialVCodecForTransparency: specialVcodec,
|
|
190
174
|
src,
|
|
191
|
-
|
|
175
|
+
timestamp: time,
|
|
192
176
|
needsResize,
|
|
193
|
-
offset: 0,
|
|
194
|
-
fps,
|
|
195
177
|
});
|
|
196
178
|
}
|
|
197
179
|
if ((0, is_beyond_last_frame_1.isBeyondLastFrame)(downloadMap, src, time)) {
|
|
@@ -261,11 +243,6 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
|
|
|
261
243
|
});
|
|
262
244
|
return last;
|
|
263
245
|
}
|
|
264
|
-
if (stdOut.length === 0) {
|
|
265
|
-
console.log('FFMPEG Logs:');
|
|
266
|
-
console.log(stderrStr);
|
|
267
|
-
throw new Error("Couldn't extract frame from video - FFMPEG did not return any data. Check logs to see more information");
|
|
268
|
-
}
|
|
269
246
|
return stdOut;
|
|
270
247
|
};
|
|
271
248
|
const extractFrameFromVideo = async (options) => {
|
|
@@ -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" | "mp4" | "mkv" | "mov" | "webm";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const guessExtensionForVideo: (src: string) => Promise<"mp3" | "wav" | "
|
|
1
|
+
export declare const guessExtensionForVideo: (src: string) => Promise<"mp3" | "wav" | "mp4" | "webm">;
|
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';
|
|
@@ -68,7 +67,7 @@ export declare const RenderInternals: {
|
|
|
68
67
|
task: Promise<Buffer | null>;
|
|
69
68
|
getLogs: () => string;
|
|
70
69
|
}>;
|
|
71
|
-
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "
|
|
70
|
+
getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "mp4" | "mkv" | "mov" | "webm";
|
|
72
71
|
tmpDir: (str: string) => string;
|
|
73
72
|
deleteDirectory: (directory: string) => Promise<void>;
|
|
74
73
|
isServeUrl: (potentialUrl: string) => boolean;
|
|
@@ -123,8 +122,8 @@ export declare const RenderInternals: {
|
|
|
123
122
|
validPixelFormats: readonly ["yuv420p", "yuva420p", "yuv422p", "yuv444p", "yuv420p10le", "yuv422p10le", "yuv444p10le", "yuva444p10le"];
|
|
124
123
|
DEFAULT_BROWSER: import("./browser").Browser;
|
|
125
124
|
validateFrameRange: (frameRange: import("./frame-range").FrameRange | null) => void;
|
|
126
|
-
DEFAULT_OPENGL_RENDERER: "
|
|
127
|
-
validateOpenGlRenderer: (option: "
|
|
125
|
+
DEFAULT_OPENGL_RENDERER: "swangle" | "angle" | "egl" | "swiftshader" | null;
|
|
126
|
+
validateOpenGlRenderer: (option: "swangle" | "angle" | "egl" | "swiftshader" | null) => "swangle" | "angle" | "egl" | "swiftshader" | null;
|
|
128
127
|
getDefaultCrfForCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => number;
|
|
129
128
|
validateSelectedCrfAndCodecCombination: (crf: unknown, codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif") => void;
|
|
130
129
|
validImageFormats: readonly ["png", "jpeg", "none"];
|
|
@@ -136,12 +135,12 @@ export declare const RenderInternals: {
|
|
|
136
135
|
DEFAULT_TIMEOUT: number;
|
|
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
|
-
validateSelectedCodecAndProResCombination: (actualCodec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", actualProResProfile: "
|
|
140
|
-
validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "
|
|
138
|
+
validateSelectedCodecAndProResCombination: (actualCodec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", actualProResProfile: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined) => void;
|
|
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"];
|
|
144
|
-
isEqualOrBelowLogLevel: (currentLevel: "
|
|
143
|
+
isEqualOrBelowLogLevel: (currentLevel: "verbose" | "info" | "warn" | "error", level: "verbose" | "info" | "warn" | "error") => boolean;
|
|
145
144
|
isValidLogLevel: (level: string) => boolean;
|
|
146
145
|
validateEveryNthFrame: (everyNthFrame: unknown) => void;
|
|
147
146
|
perf: typeof perf;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const makeAssetsDownloadTmpDir: () => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeAssetsDownloadTmpDir = void 0;
|
|
4
|
+
const tmp_dir_1 = require("./tmp-dir");
|
|
5
|
+
let dir = null;
|
|
6
|
+
const makeAssetsDownloadTmpDir = () => {
|
|
7
|
+
if (dir) {
|
|
8
|
+
return dir;
|
|
9
|
+
}
|
|
10
|
+
dir = (0, tmp_dir_1.tmpDir)('remotion-assets-dir');
|
|
11
|
+
return dir;
|
|
12
|
+
};
|
|
13
|
+
exports.makeAssetsDownloadTmpDir = makeAssetsDownloadTmpDir;
|
package/dist/render-media.d.ts
CHANGED
|
@@ -96,7 +96,7 @@ const spawnFfmpeg = async (options) => {
|
|
|
96
96
|
const audioCodecName = (0, get_audio_codec_name_1.getAudioCodecName)(codec);
|
|
97
97
|
const proResProfileName = (0, get_prores_profile_name_1.getProResProfileName)(codec, options.proResProfile);
|
|
98
98
|
const mediaSupport = (0, codec_supports_media_1.codecSupportsMedia)(codec);
|
|
99
|
-
const supportsCrf =
|
|
99
|
+
const supportsCrf = encoderName && codec !== 'prores';
|
|
100
100
|
const tempFile = options.outputLocation
|
|
101
101
|
? null
|
|
102
102
|
: path_1.default.join(options.assetsInfo.downloadMap.stitchFrames, `out.${(0, get_extension_from_codec_1.getFileExtensionFromCodec)(codec, 'final')}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/renderer",
|
|
3
|
-
"version": "3.2.12
|
|
3
|
+
"version": "3.2.12",
|
|
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.12
|
|
25
|
+
"remotion": "3.2.12",
|
|
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": "72c9a148cafdd4468fff41bbc7ca70a1776fb15e"
|
|
61
61
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
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 {};
|
|
@@ -1,21 +0,0 @@
|
|
|
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;
|