@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.
@@ -4,5 +4,4 @@ declare type MediaSupport = {
4
4
  audio: boolean;
5
5
  };
6
6
  export declare const codecSupportsMedia: (codec: Codec) => MediaSupport;
7
- export declare const codecSupportsCrf: (codec: Codec) => boolean | "" | null;
8
7
  export {};
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.codecSupportsCrf = exports.codecSupportsMedia = void 0;
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;
@@ -1,5 +1,5 @@
1
1
  import type { Codec } from './codec';
2
- export declare const combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, crf, }: {
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>;
@@ -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, crf, }) => {
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: [string, string] | null;
3
+ complexFilterFlag: [
4
+ string,
5
+ string
6
+ ] | null;
4
7
  cleanup: () => void;
5
8
  }>;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { OffthreadVideoImageFormat } from 'remotion';
3
2
  import type { DownloadMap } from './assets/download-map';
4
3
  import type { FfmpegExecutable } from './ffmpeg-executable';
@@ -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, duration, ffmpegExecutable, imageFormat, specialVCodecForTransparency, needsResize, offset, fps, }) => {
36
- console.warn(`\nUsing a slow method to extract the frame at ${duration}ms of ${src}. See https://remotion.dev/docs/slow-method-to-extract-frame for advice`);
37
- const actualOffset = `-${duration * 1000 - offset}ms`;
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
- if (offset > 70) {
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 : 1000 / fps),
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
- duration: time,
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" | "webm" | "mp4" | "mov" | "mkv";
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" | "webm" | "mp4">;
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" | "webm" | "mp4" | "mov" | "mkv";
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: "angle" | "swangle" | "egl" | "swiftshader" | null;
127
- validateOpenGlRenderer: (option: "angle" | "swangle" | "egl" | "swiftshader" | null) => "angle" | "swangle" | "egl" | "swiftshader" | null;
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: "proxy" | "4444-xq" | "4444" | "hq" | "standard" | "light" | undefined) => void;
140
- validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "jpeg" | "png" | "none") => "none" | "valid";
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: "error" | "verbose" | "info" | "warn", level: "error" | "verbose" | "info" | "warn") => boolean;
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;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { OffthreadVideoImageFormat } from 'remotion';
3
2
  import type { DownloadMap, SpecialVCodecForTransparency } from './assets/download-map';
4
3
  import type { FfmpegExecutable } from './ffmpeg-executable';
@@ -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;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ImageFormat } from './image-format';
4
3
  export declare const provideScreenshot: ({ page, imageFormat, options, quality, }: {
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
4
3
  export declare const screenshot: (page: Page, options: ScreenshotOptions) => Promise<Buffer | string | void>;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { SmallTCompMetadata } from 'remotion';
3
2
  import type { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
4
3
  import type { DownloadMap } from './assets/download-map';
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ImageFormat } from './image-format';
4
3
  export declare const screenshotDOMElement: ({ page, imageFormat, quality, opts, }: {
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import type { Page } from './browser/BrowserPage';
3
2
  import type { ScreenshotOptions } from './browser/ScreenshotOptions';
4
3
  import type { StillImageFormat } from './image-format';
@@ -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 = (0, codec_supports_media_1.codecSupportsCrf)(codec);
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-crf.7+93db68411",
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-crf.7+93db68411",
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": "93db68411377be8a8345f52ad3ea4d281424decc"
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;