@remotion/renderer 3.2.9 → 3.2.12-crf.5

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.
@@ -11,10 +11,11 @@ export declare const downloadAsset: ({ src, onDownload, downloadMap, }: {
11
11
  downloadMap: DownloadMap;
12
12
  }) => Promise<string>;
13
13
  export declare const markAllAssetsAsDownloaded: (downloadMap: DownloadMap) => void;
14
- export declare const getSanitizedFilenameForAssetUrl: ({ src, downloadDir, contentDisposition, }: {
14
+ export declare const getSanitizedFilenameForAssetUrl: ({ src, downloadDir, contentDisposition, contentType, }: {
15
15
  src: string;
16
16
  downloadDir: string;
17
17
  contentDisposition: string | null;
18
+ contentType: string | null;
18
19
  }) => string;
19
20
  export declare const downloadAndMapAssetsToFileUrl: ({ asset, onDownload, downloadMap, }: {
20
21
  asset: TAsset;
@@ -1,14 +1,38 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
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);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.downloadAndMapAssetsToFileUrl = exports.getSanitizedFilenameForAssetUrl = exports.markAllAssetsAsDownloaded = exports.downloadAsset = void 0;
7
30
  const fs_1 = __importDefault(require("fs"));
8
- const path_1 = __importDefault(require("path"));
31
+ const path_1 = __importStar(require("path"));
9
32
  const remotion_1 = require("remotion");
10
33
  const compress_assets_1 = require("../compress-assets");
11
34
  const ensure_output_directory_1 = require("../ensure-output-directory");
35
+ const mime_types_1 = require("../mime-types");
12
36
  const download_file_1 = require("./download-file");
13
37
  const sanitize_filepath_1 = require("./sanitize-filepath");
14
38
  const waitForAssetToBeDownloaded = ({ src, downloadDir, downloadMap, }) => {
@@ -121,6 +145,7 @@ const downloadAsset = async ({ src, onDownload, downloadMap, }) => {
121
145
  contentDisposition: null,
122
146
  downloadDir,
123
147
  src,
148
+ contentType: null,
124
149
  });
125
150
  (0, ensure_output_directory_1.ensureOutputDirectory)(output);
126
151
  const [assetDetails, assetData] = src.substring('data:'.length).split(',');
@@ -146,7 +171,12 @@ const downloadAsset = async ({ src, onDownload, downloadMap, }) => {
146
171
  onProgress: (progress) => {
147
172
  onProgress === null || onProgress === void 0 ? void 0 : onProgress(progress);
148
173
  },
149
- to: (contentDisposition) => (0, exports.getSanitizedFilenameForAssetUrl)({ contentDisposition, downloadDir, src }),
174
+ to: (contentDisposition, contentType) => (0, exports.getSanitizedFilenameForAssetUrl)({
175
+ contentDisposition,
176
+ downloadDir,
177
+ src,
178
+ contentType,
179
+ }),
150
180
  });
151
181
  notifyAssetIsDownloaded({ src, downloadMap, downloadDir, to });
152
182
  return to;
@@ -161,7 +191,7 @@ const markAllAssetsAsDownloaded = (downloadMap) => {
161
191
  });
162
192
  };
163
193
  exports.markAllAssetsAsDownloaded = markAllAssetsAsDownloaded;
164
- const getFilename = ({ contentDisposition, src, }) => {
194
+ const getFilename = ({ contentDisposition, src, contentType, }) => {
165
195
  const filenameProbe = 'filename=';
166
196
  if (contentDisposition === null || contentDisposition === void 0 ? void 0 : contentDisposition.includes(filenameProbe)) {
167
197
  const start = contentDisposition.indexOf(filenameProbe);
@@ -176,13 +206,26 @@ const getFilename = ({ contentDisposition, src, }) => {
176
206
  };
177
207
  }
178
208
  const { pathname, search } = new URL(src);
209
+ const ext = (0, path_1.extname)(pathname);
210
+ // Has no file extension, check if we can derive it from contentType
211
+ if (!ext && contentType) {
212
+ const matchedExt = (0, mime_types_1.getExt)(contentType);
213
+ return {
214
+ pathname: `${pathname}.${matchedExt}`,
215
+ search,
216
+ };
217
+ }
179
218
  return { pathname, search };
180
219
  };
181
- const getSanitizedFilenameForAssetUrl = ({ src, downloadDir, contentDisposition, }) => {
220
+ const getSanitizedFilenameForAssetUrl = ({ src, downloadDir, contentDisposition, contentType, }) => {
182
221
  if ((0, compress_assets_1.isAssetCompressed)(src)) {
183
222
  return src;
184
223
  }
185
- const { pathname, search } = getFilename({ contentDisposition, src });
224
+ const { pathname, search } = getFilename({
225
+ contentDisposition,
226
+ contentType,
227
+ src,
228
+ });
186
229
  const split = pathname.split('.');
187
230
  const fileExtension = split.length > 1 && split[split.length - 1]
188
231
  ? `.${split[split.length - 1]}`
@@ -1,6 +1,6 @@
1
1
  export declare const downloadFile: ({ onProgress, url, to: toFn, }: {
2
2
  url: string;
3
- to: (contentDisposition: string | null) => string;
3
+ to: (contentDisposition: string | null, contentType: string | null) => string;
4
4
  onProgress: ((progress: {
5
5
  percent: number | null;
6
6
  downloaded: number;
@@ -8,9 +8,10 @@ const downloadFile = ({ onProgress, url, to: toFn, }) => {
8
8
  return new Promise((resolve, reject) => {
9
9
  (0, read_file_1.readFile)(url)
10
10
  .then((res) => {
11
- var _a;
11
+ var _a, _b;
12
12
  const contentDisposition = (_a = res.headers['content-disposition']) !== null && _a !== void 0 ? _a : null;
13
- const to = toFn(contentDisposition);
13
+ const contentType = (_b = res.headers['content-type']) !== null && _b !== void 0 ? _b : null;
14
+ const to = toFn(contentDisposition, contentType);
14
15
  (0, ensure_output_directory_1.ensureOutputDirectory)(to);
15
16
  const sizeHeader = res.headers['content-length'];
16
17
  const totalSize = typeof sizeHeader === 'undefined' ? null : Number(sizeHeader);
@@ -4,4 +4,5 @@ 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;
7
8
  export {};
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.codecSupportsMedia = void 0;
3
+ exports.codecSupportsCrf = exports.codecSupportsMedia = void 0;
4
+ const get_codec_name_1 = require("./get-codec-name");
4
5
  const support = {
5
6
  'h264-mkv': {
6
7
  audio: true,
@@ -47,3 +48,9 @@ const codecSupportsMedia = (codec) => {
47
48
  return support[codec];
48
49
  };
49
50
  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, }: {
2
+ export declare const combineVideos: ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, crf, }: {
3
3
  files: string[];
4
4
  filelistDir: string;
5
5
  output: string;
@@ -8,4 +8,5 @@ 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;
11
12
  }) => Promise<void>;
@@ -8,15 +8,17 @@ 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");
11
12
  const get_audio_codec_name_1 = require("./get-audio-codec-name");
12
13
  const is_audio_codec_1 = require("./is-audio-codec");
13
14
  const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
14
15
  const truthy_1 = require("./truthy");
15
- const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, }) => {
16
+ const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, crf, }) => {
16
17
  var _a;
17
18
  const fileList = files.map((p) => `file '${p}'`).join('\n');
18
19
  const fileListTxt = (0, path_1.join)(filelistDir, 'files.txt');
19
20
  (0, fs_1.writeFileSync)(fileListTxt, fileList);
21
+ const supportsCrf = (0, codec_supports_media_1.codecSupportsCrf)(codec);
20
22
  try {
21
23
  const task = (0, execa_1.default)('ffmpeg', [
22
24
  (0, is_audio_codec_1.isAudioCodec)(codec) ? null : '-r',
@@ -40,6 +42,8 @@ const combineVideos = async ({ files, filelistDir, output, onProgress, numberOfF
40
42
  // Set max bitrate up to 1024kbps, will choose lower if that's too much
41
43
  '-b:a',
42
44
  '512K',
45
+ supportsCrf ? '-crf' : null,
46
+ supportsCrf ? String(crf) : null,
43
47
  codec === 'h264' ? '-movflags' : null,
44
48
  codec === 'h264' ? 'faststart' : null,
45
49
  '-shortest',
@@ -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, 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`;
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`;
38
38
  const command = [
39
39
  '-itsoffset',
40
40
  actualOffset,
@@ -72,7 +72,20 @@ const getFrameOfVideoSlow = async ({ src, timestamp, ffmpegExecutable, imageForm
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
- 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.`);
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
+ });
76
89
  }
77
90
  return stdoutBuffer;
78
91
  };
@@ -88,12 +101,14 @@ const getLastFrameOfVideoFastUnlimited = async (options) => {
88
101
  }
89
102
  if (options.specialVCodecForTransparency === 'vp8' || offset > 40) {
90
103
  const last = await getFrameOfVideoSlow({
91
- timestamp: duration,
104
+ duration,
92
105
  ffmpegExecutable,
93
106
  src,
94
107
  imageFormat: options.imageFormat,
95
108
  specialVCodecForTransparency: options.specialVCodecForTransparency,
96
109
  needsResize: options.needsResize,
110
+ offset: offset - 1000 / (fps === null ? 10 : fps),
111
+ fps,
97
112
  });
98
113
  return last;
99
114
  }
@@ -143,7 +158,7 @@ const getLastFrameOfVideoFastUnlimited = async (options) => {
143
158
  const unlimited = await getLastFrameOfVideoFastUnlimited({
144
159
  ffmpegExecutable,
145
160
  // Decrement in 10ms increments, or 1 frame (e.g. fps = 25 --> 40ms)
146
- offset: offset + 1000 / (fps === null ? 10 : fps),
161
+ offset: offset + (fps === null ? 10 : 1000 / fps),
147
162
  src,
148
163
  ffprobeExecutable,
149
164
  imageFormat: options.imageFormat,
@@ -167,13 +182,16 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
167
182
  const src = await (0, ensure_presentation_timestamp_1.ensurePresentationTimestamps)(downloadMap, options.src);
168
183
  const { specialVcodec, needsResize } = await (0, get_video_info_1.getVideoInfo)(downloadMap, src, ffprobeExecutable);
169
184
  if (specialVcodec === 'vp8') {
185
+ const { fps } = await (0, get_video_stream_duration_1.getVideoStreamDuration)(downloadMap, src, ffprobeExecutable);
170
186
  return getFrameOfVideoSlow({
171
187
  ffmpegExecutable,
172
188
  imageFormat,
173
189
  specialVCodecForTransparency: specialVcodec,
174
190
  src,
175
- timestamp: time,
191
+ duration: time,
176
192
  needsResize,
193
+ offset: 0,
194
+ fps,
177
195
  });
178
196
  }
179
197
  if ((0, is_beyond_last_frame_1.isBeyondLastFrame)(downloadMap, src, time)) {
@@ -243,6 +261,11 @@ const extractFrameFromVideoFn = async ({ time, ffmpegExecutable, ffprobeExecutab
243
261
  });
244
262
  return last;
245
263
  }
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
+ }
246
269
  return stdOut;
247
270
  };
248
271
  const extractFrameFromVideo = async (options) => {
@@ -22,6 +22,6 @@ const guessExtensionForVideo = async (src) => {
22
22
  if (stderr.includes('Video: h264')) {
23
23
  return 'mp4';
24
24
  }
25
- throw new Error(`A media file ${src} which has no file extension and whose format could not be guessed. Is this a valid media file?`);
25
+ throw new Error(`The media file "${src}" has no file extension and the format could not be guessed. Tips: a) Ensure this is a valid video or audio file b) Add a file extension to the URL like ".mp4" c) Set a "Content-Type" or "Content-Disposition" header if possible.`);
26
26
  };
27
27
  exports.guessExtensionForVideo = guessExtensionForVideo;
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;
@@ -77,7 +76,7 @@ export declare const RenderInternals: {
77
76
  validatePuppeteerTimeout: (timeoutInMilliseconds: unknown) => void;
78
77
  downloadFile: ({ onProgress, url, to: toFn, }: {
79
78
  url: string;
80
- to: (contentDisposition: string | null) => string;
79
+ to: (contentDisposition: string | null, contentType: string | null) => string;
81
80
  onProgress: ((progress: {
82
81
  percent: number | null;
83
82
  downloaded: number;
@@ -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" | "error" | "info" | "warn", level: "verbose" | "error" | "info" | "warn") => boolean;
145
144
  isValidLogLevel: (level: string) => boolean;
146
145
  validateEveryNthFrame: (everyNthFrame: unknown) => void;
147
146
  perf: typeof perf;
@@ -1,2 +1,3 @@
1
+ export declare const getExt: (contentType: string) => string | null;
1
2
  export declare function mimeLookup(path: string): string | false;
2
3
  export declare function mimeContentType(str: string): false | string;
@@ -1,12 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mimeContentType = exports.mimeLookup = void 0;
3
+ exports.mimeContentType = exports.mimeLookup = exports.getExt = void 0;
4
4
  const path_1 = require("path");
5
5
  const mime_db_1 = require("./mime-db");
6
6
  const extensions = {};
7
7
  const types = {};
8
8
  // Populate the extensions/types maps
9
9
  populateMaps(extensions, {});
10
+ const getExt = (contentType) => {
11
+ var _a, _b, _c;
12
+ return (_c = (_b = (_a = mime_db_1.mimeDb[contentType.toLowerCase()]) === null || _a === void 0 ? void 0 : _a.extensions) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : null;
13
+ };
14
+ exports.getExt = getExt;
10
15
  function mimeLookup(path) {
11
16
  if (!path || typeof path !== 'string') {
12
17
  return false;
@@ -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';
@@ -46,6 +46,9 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, ffmpegExecu
46
46
  if (outputLocation) {
47
47
  (0, validate_output_filename_1.validateOutputFilename)(codec, (0, get_extension_of_filename_1.getExtensionOfFilename)(outputLocation));
48
48
  }
49
+ const absoluteOutputLocation = outputLocation
50
+ ? path_1.default.resolve(process.cwd(), outputLocation)
51
+ : null;
49
52
  (0, validate_scale_1.validateScale)(scale);
50
53
  const everyNthFrame = (_a = options.everyNthFrame) !== null && _a !== void 0 ? _a : 1;
51
54
  const numberOfGifLoops = (_b = options.numberOfGifLoops) !== null && _b !== void 0 ? _b : null;
@@ -207,8 +210,8 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, ffmpegExecu
207
210
  .then(([{ assetsInfo }]) => {
208
211
  renderedDoneIn = Date.now() - renderStart;
209
212
  callUpdate();
210
- if (outputLocation) {
211
- (0, ensure_output_directory_1.ensureOutputDirectory)(outputLocation);
213
+ if (absoluteOutputLocation) {
214
+ (0, ensure_output_directory_1.ensureOutputDirectory)(absoluteOutputLocation);
212
215
  }
213
216
  const stitchStart = Date.now();
214
217
  return Promise.all([
@@ -216,7 +219,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, ffmpegExecu
216
219
  width: composition.width * (scale !== null && scale !== void 0 ? scale : 1),
217
220
  height: composition.height * (scale !== null && scale !== void 0 ? scale : 1),
218
221
  fps,
219
- outputLocation,
222
+ outputLocation: absoluteOutputLocation,
220
223
  internalOptions: {
221
224
  preEncodedFileLocation,
222
225
  imageFormat,
@@ -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 = encoderName && codec !== 'prores';
99
+ const supportsCrf = (0, codec_supports_media_1.codecSupportsCrf)(codec);
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.9",
3
+ "version": "3.2.12-crf.5+14dc380ad",
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.9",
25
+ "remotion": "3.2.12-crf.5+14dc380ad",
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": "66eceb7252865747a2808fc51cdbd2b57bb38486"
60
+ "gitHead": "14dc380ad148868c35c5612f48eaf8e78ab42d9c"
61
61
  }