@remotion/renderer 3.1.11 → 3.2.2

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.
@@ -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=duration,r_frame_rate'],
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
- const duration = task.stdout.match(/duration=([0-9.]+)/);
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));
@@ -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';
@@ -29,6 +29,8 @@ const innerGetCompositions = async (serveUrl, page, config, proxyPort) => {
29
29
  timeoutInMilliseconds: config === null || config === void 0 ? void 0 : config.timeoutInMilliseconds,
30
30
  proxyPort,
31
31
  retriesRemaining: 2,
32
+ audioEnabled: false,
33
+ videoEnabled: false,
32
34
  });
33
35
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
34
36
  page,
@@ -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" | "mp4" | "mkv" | "mov" | "webm";
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" | "mp4" | "webm">;
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';
@@ -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" | "mp4" | "mkv" | "mov" | "webm";
70
+ getFileExtensionFromCodec: (codec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", type: "chunk" | "final") => "mp3" | "aac" | "wav" | "gif" | "webm" | "mp4" | "mov" | "mkv";
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: "swangle" | "angle" | "egl" | "swiftshader" | null;
127
- validateOpenGlRenderer: (option: "swangle" | "angle" | "egl" | "swiftshader" | null) => "swangle" | "angle" | "egl" | "swiftshader" | null;
125
+ DEFAULT_OPENGL_RENDERER: "angle" | "swangle" | "egl" | "swiftshader" | null;
126
+ validateOpenGlRenderer: (option: "angle" | "swangle" | "egl" | "swiftshader" | null) => "angle" | "swangle" | "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: "4444-xq" | "4444" | "hq" | "standard" | "light" | "proxy" | undefined) => void;
140
- validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "png" | "jpeg" | "none") => "none" | "valid";
138
+ validateSelectedCodecAndProResCombination: (actualCodec: "h264" | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" | "h264-mkv" | "gif", actualProResProfile: "proxy" | "4444-xq" | "4444" | "hq" | "standard" | "light" | undefined) => void;
139
+ validateSelectedPixelFormatAndImageFormatCombination: (pixelFormat: "yuv420p" | "yuva420p" | "yuv422p" | "yuv444p" | "yuv420p10le" | "yuv422p10le" | "yuv444p10le" | "yuva444p10le", imageFormat: "jpeg" | "png" | "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: "verbose" | "error" | "info" | "warn", level: "verbose" | "error" | "info" | "warn") => boolean;
143
+ isEqualOrBelowLogLevel: (currentLevel: "error" | "verbose" | "info" | "warn", level: "error" | "verbose" | "info" | "warn") => 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';
@@ -70,7 +70,8 @@ const mergeAudioTrackUnlimited = async ({ ffmpegExecutable, outName, files, numb
70
70
  await task;
71
71
  cleanup();
72
72
  };
73
- const limit = (0, p_limit_1.pLimit)(2);
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
  };
@@ -45,6 +45,17 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, onDown
45
45
  const { src, time, imageFormat } = (0, exports.extractUrlAndSourceFromUrl)(req.url);
46
46
  res.setHeader('access-control-allow-origin', '*');
47
47
  res.setHeader('content-type', `image/${imageFormat === 'jpeg' ? 'jpg' : 'png'}`);
48
+ // Handling this case on Lambda:
49
+ // https://support.google.com/chrome/a/answer/7679408?hl=en
50
+ // Chrome sends Private Network Access preflights for subresources
51
+ if (req.method === 'OPTIONS') {
52
+ res.statusCode = 200;
53
+ if (req.headers['access-control-request-private-network']) {
54
+ res.setHeader('Access-Control-Allow-Private-Network', 'true');
55
+ }
56
+ res.end();
57
+ return;
58
+ }
48
59
  (0, download_and_map_assets_to_file_1.downloadAsset)({ src, onDownload, downloadMap })
49
60
  .then((to) => {
50
61
  return (0, extract_frame_from_video_1.extractFrameFromVideo)({
@@ -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>;
@@ -48,6 +48,7 @@ declare type RenderFramesOptions = {
48
48
  * @deprecated Only for Remotion internal usage
49
49
  */
50
50
  downloadMap?: DownloadMap;
51
+ muted?: boolean;
51
52
  } & ConfigOrComposition & ServeUrlOrWebpackBundle;
52
53
  export declare const renderFrames: (options: RenderFramesOptions) => Promise<RenderFramesOutput>;
53
54
  export {};
@@ -44,7 +44,7 @@ const getPool = async (pages) => {
44
44
  const pool = new pool_1.Pool(puppeteerPages);
45
45
  return pool;
46
46
  };
47
- const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, quality, imageFormat = image_format_1.DEFAULT_IMAGE_FORMAT, frameRange, puppeteerInstance, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualParallelism, everyNthFrame = 1, proxyPort, cancelSignal, downloadMap, }) => {
47
+ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, quality, imageFormat = image_format_1.DEFAULT_IMAGE_FORMAT, frameRange, puppeteerInstance, onError, envVariables, onBrowserLog, onFrameBuffer, onDownload, pagesArray, serveUrl, composition, timeoutInMilliseconds, scale, actualParallelism, everyNthFrame = 1, proxyPort, cancelSignal, downloadMap, muted, }) => {
48
48
  if (!puppeteerInstance) {
49
49
  throw new Error('no puppeteer instance passed to innerRenderFrames - internal error');
50
50
  }
@@ -87,6 +87,8 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
87
87
  timeoutInMilliseconds,
88
88
  proxyPort,
89
89
  retriesRemaining: 2,
90
+ audioEnabled: !muted,
91
+ videoEnabled: imageFormat !== 'none',
90
92
  });
91
93
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
92
94
  pageFunction: (id) => {
@@ -56,10 +56,12 @@ export declare type RenderMediaOptions = {
56
56
  * @deprecated Only for Remotion internal usage
57
57
  */
58
58
  downloadMap?: DownloadMap;
59
+ muted?: boolean;
60
+ enforceAudioTrack?: boolean;
59
61
  } & ServeUrlOrWebpackBundle;
60
62
  /**
61
63
  *
62
64
  * @description Render a video from a composition
63
65
  * @link https://www.remotion.dev/docs/renderer/render-media
64
66
  */
65
- export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<Buffer | null>;
67
+ export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ...options }: RenderMediaOptions) => Promise<Buffer | null>;
@@ -10,6 +10,7 @@ const path_1 = __importDefault(require("path"));
10
10
  const remotion_1 = require("remotion");
11
11
  const download_map_1 = require("./assets/download-map");
12
12
  const can_use_parallel_encoding_1 = require("./can-use-parallel-encoding");
13
+ const codec_supports_media_1 = require("./codec-supports-media");
13
14
  const crf_1 = require("./crf");
14
15
  const delete_directory_1 = require("./delete-directory");
15
16
  const ensure_frames_in_order_1 = require("./ensure-frames-in-order");
@@ -35,7 +36,7 @@ const validate_scale_1 = require("./validate-scale");
35
36
  * @description Render a video from a composition
36
37
  * @link https://www.remotion.dev/docs/renderer/render-media
37
38
  */
38
- const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }) => {
39
+ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, ffprobeExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, muted, enforceAudioTrack, ...options }) => {
39
40
  var _a, _b, _c;
40
41
  (0, quality_1.validateQuality)(quality);
41
42
  if (typeof crf !== 'undefined' && crf !== null) {
@@ -142,6 +143,8 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
142
143
  }
143
144
  }
144
145
  };
146
+ const mediaSupport = (0, codec_supports_media_1.codecSupportsMedia)(codec);
147
+ const disableAudio = !mediaSupport.audio || muted;
145
148
  const happyPath = createPrestitcherIfNecessary()
146
149
  .then(() => {
147
150
  const renderFramesProc = (0, render_frames_1.renderFrames)({
@@ -190,6 +193,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
190
193
  port,
191
194
  cancelSignal: cancelRenderFrames.cancelSignal,
192
195
  downloadMap,
196
+ muted: disableAudio,
193
197
  });
194
198
  return renderFramesProc;
195
199
  })
@@ -231,6 +235,8 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
231
235
  verbose: options.verbose,
232
236
  dir: outputDir !== null && outputDir !== void 0 ? outputDir : undefined,
233
237
  cancelSignal: cancelStitcher.cancelSignal,
238
+ muted: disableAudio,
239
+ enforceAudioTrack,
234
240
  }),
235
241
  stitchStart,
236
242
  ]);
@@ -117,6 +117,8 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
117
117
  timeoutInMilliseconds,
118
118
  proxyPort,
119
119
  retriesRemaining: 2,
120
+ audioEnabled: false,
121
+ videoEnabled: true,
120
122
  });
121
123
  await (0, puppeteer_evaluate_1.puppeteerEvaluateWithCatch)({
122
124
  pageFunction: (id) => {
@@ -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,5 +1,5 @@
1
1
  import type { Page } from './browser/BrowserPage';
2
- export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, }: {
2
+ export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, audioEnabled, videoEnabled, }: {
3
3
  inputProps: unknown;
4
4
  envVariables: Record<string, string> | undefined;
5
5
  page: Page;
@@ -8,4 +8,6 @@ export declare const setPropsAndEnv: ({ inputProps, envVariables, page, serveUrl
8
8
  timeoutInMilliseconds: number | undefined;
9
9
  proxyPort: number;
10
10
  retriesRemaining: number;
11
+ audioEnabled: boolean;
12
+ videoEnabled: boolean;
11
13
  }) => Promise<void>;
@@ -5,7 +5,7 @@ const TimeoutSettings_1 = require("./browser/TimeoutSettings");
5
5
  const normalize_serve_url_1 = require("./normalize-serve-url");
6
6
  const puppeteer_evaluate_1 = require("./puppeteer-evaluate");
7
7
  const validate_puppeteer_timeout_1 = require("./validate-puppeteer-timeout");
8
- const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, }) => {
8
+ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initialFrame, timeoutInMilliseconds, proxyPort, retriesRemaining, audioEnabled, videoEnabled, }) => {
9
9
  (0, validate_puppeteer_timeout_1.validatePuppeteerTimeout)(timeoutInMilliseconds);
10
10
  const actualTimeout = timeoutInMilliseconds !== null && timeoutInMilliseconds !== void 0 ? timeoutInMilliseconds : TimeoutSettings_1.DEFAULT_TIMEOUT;
11
11
  page.setDefaultTimeout(actualTimeout);
@@ -13,23 +13,29 @@ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initia
13
13
  const urlToVisit = (0, normalize_serve_url_1.normalizeServeUrl)(serveUrl);
14
14
  await page.evaluateOnNewDocument((timeout) => {
15
15
  window.remotion_puppeteerTimeout = timeout;
16
- }, [actualTimeout]);
16
+ }, actualTimeout);
17
17
  if (inputProps) {
18
18
  await page.evaluateOnNewDocument((input) => {
19
19
  window.remotion_inputProps = input;
20
- }, [JSON.stringify(inputProps)]);
20
+ }, JSON.stringify(inputProps));
21
21
  }
22
22
  if (envVariables) {
23
23
  await page.evaluateOnNewDocument((input) => {
24
24
  window.remotion_envVariables = input;
25
- }, [JSON.stringify(envVariables)]);
25
+ }, JSON.stringify(envVariables));
26
26
  }
27
27
  await page.evaluateOnNewDocument((key) => {
28
28
  window.remotion_initialFrame = key;
29
- }, [initialFrame]);
29
+ }, initialFrame);
30
30
  await page.evaluateOnNewDocument((port) => {
31
31
  window.remotion_proxyPort = port;
32
- }, [proxyPort]);
32
+ }, proxyPort);
33
+ await page.evaluateOnNewDocument((enabled) => {
34
+ window.remotion_audioEnabled = enabled;
35
+ }, audioEnabled);
36
+ await page.evaluateOnNewDocument((enabled) => {
37
+ window.remotion_videoEnabled = enabled;
38
+ }, videoEnabled);
33
39
  const pageRes = await page.goto(urlToVisit);
34
40
  if (pageRes === null) {
35
41
  throw new Error(`Visited "${urlToVisit}" but got no response.`);
@@ -52,6 +58,8 @@ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initia
52
58
  retriesRemaining: retriesRemaining - 1,
53
59
  serveUrl,
54
60
  timeoutInMilliseconds,
61
+ audioEnabled,
62
+ videoEnabled,
55
63
  });
56
64
  }
57
65
  if (status !== 200 &&
@@ -82,8 +90,9 @@ const setPropsAndEnv = async ({ inputProps, envVariables, page, serveUrl, initia
82
90
  frame: null,
83
91
  page,
84
92
  });
85
- if (siteVersion !== '3') {
86
- throw new Error(`Incompatible site: When visiting ${urlToVisit}, a bundle was found, but one that is not compatible with this version of Remotion. The bundle format changed in version 3.0.11. To resolve this error, please bundle and deploy again.`);
93
+ const requiredVersion = '4';
94
+ if (siteVersion !== requiredVersion) {
95
+ throw new Error(`Incompatible site: When visiting ${urlToVisit}, a bundle was found, but one that is not compatible with this version of Remotion. Found version: ${siteVersion} - Required version: ${requiredVersion}. To resolve this error, please bundle and deploy again.`);
87
96
  }
88
97
  };
89
98
  exports.setPropsAndEnv = setPropsAndEnv;
@@ -30,6 +30,8 @@ export declare type StitcherOptions = {
30
30
  preEncodedFileLocation: string | null;
31
31
  imageFormat: ImageFormat;
32
32
  };
33
+ muted?: boolean;
34
+ enforceAudioTrack?: boolean;
33
35
  };
34
36
  declare type ReturnType = {
35
37
  task: Promise<Buffer | null>;
@@ -100,6 +100,14 @@ const spawnFfmpeg = async (options) => {
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')}`);
103
+ const shouldRenderAudio = mediaSupport.audio &&
104
+ (options.assetsInfo.assets.flat(1).length > 0 ||
105
+ options.enforceAudioTrack) &&
106
+ !options.muted;
107
+ const shouldRenderVideo = mediaSupport.video;
108
+ if (!shouldRenderAudio && !shouldRenderVideo) {
109
+ throw new Error('The output format has neither audio nor video. This can happen if you are rendering an audio codec and the output file has no audio or the muted flag was passed.');
110
+ }
103
111
  if (options.verbose) {
104
112
  console.log('[verbose] ffmpeg', (_e = options.ffmpegExecutable) !== null && _e !== void 0 ? _e : 'ffmpeg in PATH');
105
113
  console.log('[verbose] encoder', encoderName);
@@ -109,7 +117,8 @@ const spawnFfmpeg = async (options) => {
109
117
  console.log('[verbose] crf', crf);
110
118
  }
111
119
  console.log('[verbose] codec', codec);
112
- console.log('[verbose] isAudioOnly', mediaSupport.audio && !mediaSupport.video);
120
+ console.log('[verbose] shouldRenderAudio', shouldRenderAudio);
121
+ console.log('[verbose] shouldRenderVideo', shouldRenderVideo);
113
122
  console.log('[verbose] proResProfileName', proResProfileName);
114
123
  }
115
124
  (0, crf_1.validateSelectedCrfAndCodecCombination)(crf, codec);
@@ -120,7 +129,7 @@ const spawnFfmpeg = async (options) => {
120
129
  const totalFrameProgress = 0.5 * preStitchProgress * expectedFrames + muxProgress * 0.5;
121
130
  (_a = options.onProgress) === null || _a === void 0 ? void 0 : _a.call(options, Math.round(totalFrameProgress));
122
131
  };
123
- const audio = mediaSupport.audio
132
+ const audio = shouldRenderAudio
124
133
  ? await getAssetsData({
125
134
  assets: options.assetsInfo.assets,
126
135
  onDownload: options.onDownload,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "3.1.11",
3
+ "version": "3.2.2",
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.1.11",
25
+ "remotion": "3.2.2",
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": "bc4184c9faf944a3bac2fd56bdf990cc74e3ec94"
60
+ "gitHead": "8e5f2d05adf7ddd3824ea734fa888b4b4761f364"
61
61
  }
@@ -1 +0,0 @@
1
- export declare const makeAssetsDownloadTmpDir: () => string;
@@ -1,13 +0,0 @@
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;