@remotion/renderer 3.0.16 → 3.0.17

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,4 +1,5 @@
1
- export declare function getAudioChannelsAndDuration(path: string): Promise<{
1
+ import { FfmpegExecutable } from 'remotion';
2
+ export declare function getAudioChannelsAndDuration(path: string, ffprobeExecutable: FfmpegExecutable): Promise<{
2
3
  channels: number;
3
4
  duration: number | null;
4
5
  }>;
@@ -5,7 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getAudioChannelsAndDuration = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
- async function getAudioChannelsAndDuration(path) {
8
+ async function getAudioChannelsAndDuration(path, ffprobeExecutable) {
9
9
  const args = [
10
10
  ['-v', 'error'],
11
11
  ['-show_entries', 'stream=channels:format=duration'],
@@ -14,7 +14,7 @@ async function getAudioChannelsAndDuration(path) {
14
14
  ]
15
15
  .reduce((acc, val) => acc.concat(val), [])
16
16
  .filter(Boolean);
17
- const task = await (0, execa_1.default)('ffprobe', args);
17
+ const task = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', args);
18
18
  const channels = task.stdout.match(/channels=([0-9]+)/);
19
19
  const duration = task.stdout.match(/duration=([0-9.]+)/);
20
20
  return {
@@ -2,17 +2,15 @@
2
2
  /// <reference types="node" />
3
3
  import { FfmpegExecutable } from 'remotion';
4
4
  import { Readable } from 'stream';
5
+ import { LastFrameOptions } from './last-frame-from-video-cache';
5
6
  export declare function streamToString(stream: Readable): Promise<string>;
6
- export declare const getLastFrameOfVideo: ({ ffmpegExecutable, offset, src, }: {
7
- ffmpegExecutable: FfmpegExecutable;
8
- offset: number;
9
- src: string;
10
- }) => Promise<Buffer>;
7
+ export declare const getLastFrameOfVideo: (options: LastFrameOptions) => Promise<Buffer>;
11
8
  declare type Options = {
12
9
  time: number;
13
10
  src: string;
14
11
  ffmpegExecutable: FfmpegExecutable;
12
+ ffprobeExecutable: FfmpegExecutable;
15
13
  };
16
- export declare const extractFrameFromVideoFn: ({ time, src, ffmpegExecutable, }: Options) => Promise<Buffer>;
14
+ export declare const extractFrameFromVideoFn: ({ time, src, ffmpegExecutable, ffprobeExecutable, }: Options) => Promise<Buffer>;
17
15
  export declare const extractFrameFromVideo: (options: Options) => Promise<Buffer>;
18
16
  export {};
@@ -5,7 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.extractFrameFromVideo = exports.extractFrameFromVideoFn = exports.getLastFrameOfVideo = exports.streamToString = void 0;
7
7
  const execa_1 = __importDefault(require("execa"));
8
+ const remotion_1 = require("remotion");
8
9
  const frame_to_ffmpeg_timestamp_1 = require("./frame-to-ffmpeg-timestamp");
10
+ const is_beyond_last_frame_1 = require("./is-beyond-last-frame");
11
+ const last_frame_from_video_cache_1 = require("./last-frame-from-video-cache");
9
12
  const p_limit_1 = require("./p-limit");
10
13
  function streamToString(stream) {
11
14
  const chunks = [];
@@ -16,15 +19,32 @@ function streamToString(stream) {
16
19
  });
17
20
  }
18
21
  exports.streamToString = streamToString;
19
- const getLastFrameOfVideo = async ({ ffmpegExecutable, offset, src, }) => {
22
+ const lastFrameLimit = (0, p_limit_1.pLimit)(5);
23
+ const mainLimit = (0, p_limit_1.pLimit)(5);
24
+ const getLastFrameOfVideoUnlimited = async ({ ffmpegExecutable, ffprobeExecutable, offset, src, }) => {
20
25
  if (offset > 100) {
21
26
  throw new Error('could not get last frame of ' +
22
27
  src +
23
28
  '. Tried to seek 100ms before the end of the video and no frame was found. The video container has a duration that is longer than it contains video.');
24
29
  }
25
- const actualOffset = `-${offset + 10}ms`;
30
+ const durationCmd = await (0, execa_1.default)(ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : 'ffprobe', [
31
+ '-v',
32
+ 'error',
33
+ '-select_streams',
34
+ 'v:0',
35
+ '-show_entries',
36
+ 'stream=duration',
37
+ '-of',
38
+ 'default=noprint_wrappers=1:nokey=1',
39
+ src,
40
+ ]);
41
+ const duration = parseFloat(durationCmd.stdout);
42
+ if (Number.isNaN(duration)) {
43
+ throw new TypeError(`Could not get duration of ${src}: ${durationCmd.stdout}`);
44
+ }
45
+ const actualOffset = `${duration * 1000 - offset - 10}ms`;
26
46
  const { stdout, stderr } = (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', [
27
- '-sseof',
47
+ '-ss',
28
48
  actualOffset,
29
49
  '-i',
30
50
  src,
@@ -61,13 +81,34 @@ const getLastFrameOfVideo = async ({ ffmpegExecutable, offset, src, }) => {
61
81
  const [stdErr, stdoutBuffer] = await Promise.all([stdErrString, stdoutChunk]);
62
82
  const isEmpty = stdErr.includes('Output file is empty');
63
83
  if (isEmpty) {
64
- return (0, exports.getLastFrameOfVideo)({ ffmpegExecutable, offset: offset + 10, src });
84
+ return getLastFrameOfVideoUnlimited({
85
+ ffmpegExecutable,
86
+ offset: offset + 10,
87
+ src,
88
+ ffprobeExecutable,
89
+ });
65
90
  }
66
91
  return stdoutBuffer;
67
92
  };
93
+ const getLastFrameOfVideo = async (options) => {
94
+ const fromCache = (0, last_frame_from_video_cache_1.getLastFrameFromCache)(options);
95
+ if (fromCache) {
96
+ return fromCache;
97
+ }
98
+ const result = await lastFrameLimit(getLastFrameOfVideoUnlimited, options);
99
+ (0, last_frame_from_video_cache_1.setLastFrameInCache)(options, result);
100
+ return result;
101
+ };
68
102
  exports.getLastFrameOfVideo = getLastFrameOfVideo;
69
- const limit = (0, p_limit_1.pLimit)(5);
70
- const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
103
+ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, ffprobeExecutable, }) => {
104
+ if ((0, is_beyond_last_frame_1.isBeyondLastFrame)(src, time)) {
105
+ return (0, exports.getLastFrameOfVideo)({
106
+ ffmpegExecutable,
107
+ ffprobeExecutable,
108
+ offset: 0,
109
+ src,
110
+ });
111
+ }
71
112
  const ffmpegTimestamp = (0, frame_to_ffmpeg_timestamp_1.frameToFfmpegTimestamp)(time);
72
113
  const { stdout, stderr } = (0, execa_1.default)(ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : 'ffmpeg', [
73
114
  '-ss',
@@ -117,8 +158,10 @@ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
117
158
  stdoutBuffer,
118
159
  ]);
119
160
  if (stderrStr.includes('Output file is empty')) {
161
+ (0, is_beyond_last_frame_1.markAsBeyondLastFrame)(src, time);
120
162
  return (0, exports.getLastFrameOfVideo)({
121
163
  ffmpegExecutable,
164
+ ffprobeExecutable,
122
165
  offset: 0,
123
166
  src,
124
167
  });
@@ -126,7 +169,10 @@ const extractFrameFromVideoFn = async ({ time, src, ffmpegExecutable, }) => {
126
169
  return stdOut;
127
170
  };
128
171
  exports.extractFrameFromVideoFn = extractFrameFromVideoFn;
129
- const extractFrameFromVideo = (options) => {
130
- return limit(exports.extractFrameFromVideoFn, options);
172
+ const extractFrameFromVideo = async (options) => {
173
+ const perf = remotion_1.Internals.perf.startPerfMeasure('extract-frame');
174
+ const res = await mainLimit(exports.extractFrameFromVideoFn, options);
175
+ remotion_1.Internals.perf.stopPerfMeasure(perf);
176
+ return res;
131
177
  };
132
178
  exports.extractFrameFromVideo = extractFrameFromVideo;
@@ -11,6 +11,7 @@ declare type GetCompositionsConfig = {
11
11
  timeoutInMilliseconds?: number;
12
12
  chromiumOptions?: ChromiumOptions;
13
13
  ffmpegExecutable?: FfmpegExecutable;
14
+ ffprobeExecutable?: FfmpegExecutable;
14
15
  port?: number | null;
15
16
  };
16
17
  export declare const getCompositions: (serveUrlOrWebpackUrl: string, config?: GetCompositionsConfig) => Promise<TCompMetadata[]>;
@@ -60,7 +60,7 @@ const getCompositions = async (serveUrlOrWebpackUrl, config) => {
60
60
  chromiumOptions: (_b = config === null || config === void 0 ? void 0 : config.chromiumOptions) !== null && _b !== void 0 ? _b : {},
61
61
  });
62
62
  return new Promise((resolve, reject) => {
63
- var _a, _b;
63
+ var _a, _b, _c;
64
64
  const onError = (err) => reject(err);
65
65
  const cleanupPageError = (0, handle_javascript_exception_1.handleJavascriptException)({
66
66
  page,
@@ -74,7 +74,8 @@ const getCompositions = async (serveUrlOrWebpackUrl, config) => {
74
74
  onDownload: () => undefined,
75
75
  onError,
76
76
  ffmpegExecutable: (_a = config === null || config === void 0 ? void 0 : config.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
77
- port: (_b = config === null || config === void 0 ? void 0 : config.port) !== null && _b !== void 0 ? _b : null,
77
+ ffprobeExecutable: (_b = config === null || config === void 0 ? void 0 : config.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
78
+ port: (_c = config === null || config === void 0 ? void 0 : config.port) !== null && _c !== void 0 ? _c : null,
78
79
  })
79
80
  .then(({ serveUrl, closeServer, offthreadPort }) => {
80
81
  close = closeServer;
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ export declare const RenderInternals: {
33
33
  serveStatic: (path: string | null, options: {
34
34
  port: number | null;
35
35
  ffmpegExecutable: import("remotion").FfmpegExecutable;
36
+ ffprobeExecutable: import("remotion").FfmpegExecutable;
36
37
  downloadDir: string;
37
38
  onDownload: import("./assets/download-and-map-assets-to-file").RenderMediaOnDownload;
38
39
  onError: (err: Error) => void;
@@ -0,0 +1,2 @@
1
+ export declare const isBeyondLastFrame: (src: string, time: number) => boolean | 0;
2
+ export declare const markAsBeyondLastFrame: (src: string, time: number) => void;
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.markAsBeyondLastFrame = exports.isBeyondLastFrame = void 0;
4
+ const map = {};
5
+ const isBeyondLastFrame = (src, time) => {
6
+ return map[src] && time >= map[src];
7
+ };
8
+ exports.isBeyondLastFrame = isBeyondLastFrame;
9
+ const markAsBeyondLastFrame = (src, time) => {
10
+ map[src] = time;
11
+ };
12
+ exports.markAsBeyondLastFrame = markAsBeyondLastFrame;
@@ -0,0 +1,13 @@
1
+ /// <reference types="node" />
2
+ import { FfmpegExecutable } from 'remotion';
3
+ export declare type LastFrameOptions = {
4
+ ffmpegExecutable: FfmpegExecutable;
5
+ ffprobeExecutable: FfmpegExecutable;
6
+ offset: number;
7
+ src: string;
8
+ };
9
+ export declare const setLastFrameInCache: (options: LastFrameOptions, data: Buffer) => void;
10
+ export declare const getLastFrameFromCache: (options: LastFrameOptions) => Buffer | null;
11
+ export declare const removedLastFrameFromCache: (key: string) => void;
12
+ export declare const ensureMaxSize: () => void;
13
+ export declare const clearLastFileCache: () => void;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ // OffthreadVideo requires sometimes that the last frame of a video gets extracted, however, this can be slow. We allocate a cache for it but that can be garbage collected
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.clearLastFileCache = exports.ensureMaxSize = exports.removedLastFrameFromCache = exports.getLastFrameFromCache = exports.setLastFrameInCache = void 0;
5
+ let map = {};
6
+ const MAX_CACHE_SIZE = 50 * 1024 * 1024; // 50MB
7
+ let bufferSize = 0;
8
+ const makeLastFrameCacheKey = (options) => {
9
+ return [options.ffmpegExecutable, options.offset, options.src].join('-');
10
+ };
11
+ const setLastFrameInCache = (options, data) => {
12
+ const key = makeLastFrameCacheKey(options);
13
+ if (map[key]) {
14
+ bufferSize -= map[key].data.byteLength;
15
+ }
16
+ map[key] = { data, lastAccessed: Date.now() };
17
+ bufferSize += data.byteLength;
18
+ (0, exports.ensureMaxSize)();
19
+ };
20
+ exports.setLastFrameInCache = setLastFrameInCache;
21
+ const getLastFrameFromCache = (options) => {
22
+ var _a;
23
+ const key = makeLastFrameCacheKey(options);
24
+ if (!map[key]) {
25
+ return null;
26
+ }
27
+ map[key].lastAccessed = Date.now();
28
+ return (_a = map[key].data) !== null && _a !== void 0 ? _a : null;
29
+ };
30
+ exports.getLastFrameFromCache = getLastFrameFromCache;
31
+ const removedLastFrameFromCache = (key) => {
32
+ if (!map[key]) {
33
+ return;
34
+ }
35
+ bufferSize -= map[key].data.byteLength;
36
+ delete map[key];
37
+ };
38
+ exports.removedLastFrameFromCache = removedLastFrameFromCache;
39
+ const ensureMaxSize = () => {
40
+ // eslint-disable-next-line no-unmodified-loop-condition
41
+ while (bufferSize > MAX_CACHE_SIZE) {
42
+ const earliest = Object.entries(map).sort((a, b) => {
43
+ return a[1].lastAccessed - b[1].lastAccessed;
44
+ })[0];
45
+ (0, exports.removedLastFrameFromCache)(earliest[0]);
46
+ }
47
+ };
48
+ exports.ensureMaxSize = ensureMaxSize;
49
+ const clearLastFileCache = () => {
50
+ map = {};
51
+ };
52
+ exports.clearLastFileCache = clearLastFileCache;
@@ -5,8 +5,9 @@ export declare const extractUrlAndSourceFromUrl: (url: string) => {
5
5
  src: string;
6
6
  time: number;
7
7
  };
8
- export declare const startOffthreadVideoServer: ({ ffmpegExecutable, downloadDir, onDownload, onError, }: {
8
+ export declare const startOffthreadVideoServer: ({ ffmpegExecutable, ffprobeExecutable, downloadDir, onDownload, onError, }: {
9
9
  ffmpegExecutable: FfmpegExecutable;
10
+ ffprobeExecutable: FfmpegExecutable;
10
11
  downloadDir: string;
11
12
  onDownload: RenderMediaOnDownload;
12
13
  onError: (err: Error) => void;
@@ -22,7 +22,7 @@ const extractUrlAndSourceFromUrl = (url) => {
22
22
  return { src, time: parseFloat(time) };
23
23
  };
24
24
  exports.extractUrlAndSourceFromUrl = extractUrlAndSourceFromUrl;
25
- const startOffthreadVideoServer = ({ ffmpegExecutable, downloadDir, onDownload, onError, }) => {
25
+ const startOffthreadVideoServer = ({ ffmpegExecutable, ffprobeExecutable, downloadDir, onDownload, onError, }) => {
26
26
  return (req, res) => {
27
27
  if (!req.url) {
28
28
  throw new Error('Request came in without URL');
@@ -45,6 +45,7 @@ const startOffthreadVideoServer = ({ ffmpegExecutable, downloadDir, onDownload,
45
45
  time,
46
46
  src: to,
47
47
  ffmpegExecutable,
48
+ ffprobeExecutable,
48
49
  });
49
50
  })
50
51
  .then((readable) => {
@@ -1,11 +1,12 @@
1
1
  import { FfmpegExecutable } from 'remotion';
2
2
  import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file';
3
- export declare const prepareServer: ({ downloadDir, ffmpegExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }: {
3
+ export declare const prepareServer: ({ downloadDir, ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }: {
4
4
  webpackConfigOrServeUrl: string;
5
5
  downloadDir: string;
6
6
  onDownload: RenderMediaOnDownload;
7
7
  onError: (err: Error) => void;
8
8
  ffmpegExecutable: FfmpegExecutable;
9
+ ffprobeExecutable: FfmpegExecutable;
9
10
  port: number | null;
10
11
  }) => Promise<{
11
12
  serveUrl: string;
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.prepareServer = void 0;
4
4
  const is_serve_url_1 = require("./is-serve-url");
5
5
  const serve_static_1 = require("./serve-static");
6
- const prepareServer = async ({ downloadDir, ffmpegExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }) => {
6
+ const prepareServer = async ({ downloadDir, ffmpegExecutable, ffprobeExecutable, onDownload, onError, webpackConfigOrServeUrl, port, }) => {
7
7
  if ((0, is_serve_url_1.isServeUrl)(webpackConfigOrServeUrl)) {
8
8
  const { port: offthreadPort, close: closeProxy } = await (0, serve_static_1.serveStatic)(null, {
9
9
  downloadDir,
10
10
  onDownload,
11
11
  onError,
12
12
  ffmpegExecutable,
13
+ ffprobeExecutable,
13
14
  port,
14
15
  });
15
16
  return Promise.resolve({
@@ -23,6 +24,7 @@ const prepareServer = async ({ downloadDir, ffmpegExecutable, onDownload, onErro
23
24
  onDownload,
24
25
  onError,
25
26
  ffmpegExecutable,
27
+ ffprobeExecutable,
26
28
  port,
27
29
  });
28
30
  return Promise.resolve({
@@ -2,6 +2,7 @@ import { FfmpegExecutable } from 'remotion';
2
2
  import { MediaAsset } from './assets/types';
3
3
  declare type Options = {
4
4
  ffmpegExecutable: FfmpegExecutable;
5
+ ffprobeExecutable: FfmpegExecutable;
5
6
  outName: string;
6
7
  asset: MediaAsset;
7
8
  expectedFrames: number;
@@ -10,8 +10,8 @@ const calculate_ffmpeg_filters_1 = require("./calculate-ffmpeg-filters");
10
10
  const ffmpeg_filter_file_1 = require("./ffmpeg-filter-file");
11
11
  const p_limit_1 = require("./p-limit");
12
12
  const resolve_asset_src_1 = require("./resolve-asset-src");
13
- const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, outName, asset, expectedFrames, fps, }) => {
14
- const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)((0, resolve_asset_src_1.resolveAssetSrc)(asset.src));
13
+ const preprocessAudioTrackUnlimited = async ({ ffmpegExecutable, ffprobeExecutable, outName, asset, expectedFrames, fps, }) => {
14
+ const { channels, duration } = await (0, get_audio_channels_1.getAudioChannelsAndDuration)((0, resolve_asset_src_1.resolveAssetSrc)(asset.src), ffprobeExecutable);
15
15
  const filter = (0, calculate_ffmpeg_filters_1.calculateFfmpegFilter)({
16
16
  asset,
17
17
  durationInFrames: expectedFrames,
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.provideScreenshot = void 0;
4
4
  const screenshot_dom_element_1 = require("./screenshot-dom-element");
5
- const provideScreenshot = async ({ page, imageFormat, options, quality, }) => {
5
+ const provideScreenshot = ({ page, imageFormat, options, quality, }) => {
6
6
  return (0, screenshot_dom_element_1.screenshotDOMElement)({
7
7
  page,
8
8
  opts: {
@@ -35,6 +35,7 @@ declare type RenderFramesOptions = {
35
35
  chromiumOptions?: ChromiumOptions;
36
36
  scale?: number;
37
37
  ffmpegExecutable?: FfmpegExecutable;
38
+ ffprobeExecutable?: FfmpegExecutable;
38
39
  port?: number | null;
39
40
  cancelSignal?: CancelSignal;
40
41
  } & ConfigOrComposition & ServeUrlOrWebpackBundle;
@@ -54,7 +54,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
54
54
  const pages = new Array(actualParallelism).fill(true).map(async () => {
55
55
  const page = await puppeteerInstance.newPage();
56
56
  pagesArray.push(page);
57
- page.setViewport({
57
+ await page.setViewport({
58
58
  width: composition.width,
59
59
  height: composition.height,
60
60
  deviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
@@ -135,6 +135,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
135
135
  await (0, seek_to_frame_1.seekToFrame)({ frame, page: freePage });
136
136
  if (imageFormat !== 'none') {
137
137
  if (onFrameBuffer) {
138
+ const id = remotion_1.Internals.perf.startPerfMeasure('save');
138
139
  const buffer = await (0, provide_screenshot_1.provideScreenshot)({
139
140
  page: freePage,
140
141
  imageFormat,
@@ -144,6 +145,7 @@ const innerRenderFrames = ({ onFrameUpdate, outputDir, onStart, inputProps, qual
144
145
  output: undefined,
145
146
  },
146
147
  });
148
+ remotion_1.Internals.perf.stopPerfMeasure(id);
147
149
  onFrameBuffer(buffer, frame);
148
150
  }
149
151
  else {
@@ -236,7 +238,7 @@ const renderFrames = (options) => {
236
238
  const actualParallelism = (0, get_concurrency_1.getActualConcurrency)((_d = options.parallelism) !== null && _d !== void 0 ? _d : null);
237
239
  const openedPages = [];
238
240
  return new Promise((resolve, reject) => {
239
- var _a, _b;
241
+ var _a, _b, _c;
240
242
  const cleanup = [];
241
243
  const onError = (err) => reject(err);
242
244
  Promise.all([
@@ -246,7 +248,8 @@ const renderFrames = (options) => {
246
248
  onDownload,
247
249
  onError,
248
250
  ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
249
- port: (_b = options.port) !== null && _b !== void 0 ? _b : null,
251
+ ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
252
+ port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
250
253
  }),
251
254
  browserInstance,
252
255
  ])
@@ -23,6 +23,7 @@ export declare type RenderMediaOptions = {
23
23
  crf?: number | null;
24
24
  imageFormat?: 'png' | 'jpeg' | 'none';
25
25
  ffmpegExecutable?: FfmpegExecutable;
26
+ ffprobeExecutable?: FfmpegExecutable;
26
27
  pixelFormat?: PixelFormat;
27
28
  envVariables?: Record<string, string>;
28
29
  quality?: number;
@@ -42,4 +43,4 @@ export declare type RenderMediaOptions = {
42
43
  cancelSignal?: CancelSignal;
43
44
  browserExecutable?: BrowserExecutable;
44
45
  } & ServeUrlOrWebpackBundle;
45
- export declare const renderMedia: ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }: RenderMediaOptions) => Promise<void>;
46
+ 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<void>;
@@ -24,7 +24,7 @@ const tmp_dir_1 = require("./tmp-dir");
24
24
  const validate_even_dimensions_with_codec_1 = require("./validate-even-dimensions-with-codec");
25
25
  const validate_output_filename_1 = require("./validate-output-filename");
26
26
  const validate_scale_1 = require("./validate-scale");
27
- const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat, ffmpegExecutable, inputProps, pixelFormat, codec, envVariables, quality, frameRange, puppeteerInstance, outputLocation, onProgress, overwrite, onDownload, dumpBrowserLogs, onBrowserLog, onStart, timeoutInMilliseconds, chromiumOptions, scale, browserExecutable, port, cancelSignal, ...options }) => {
27
+ 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 }) => {
28
28
  remotion_1.Internals.validateQuality(quality);
29
29
  if (typeof crf !== 'undefined' && crf !== null) {
30
30
  remotion_1.Internals.validateSelectedCrfAndCodecCombination(crf, codec);
@@ -137,7 +137,9 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
137
137
  if (cancelled) {
138
138
  return;
139
139
  }
140
+ const id = remotion_1.Internals.perf.startPerfMeasure('piping');
140
141
  (_a = stitcherFfmpeg === null || stitcherFfmpeg === void 0 ? void 0 : stitcherFfmpeg.stdin) === null || _a === void 0 ? void 0 : _a.write(buffer);
142
+ remotion_1.Internals.perf.stopPerfMeasure(id);
141
143
  setFrameToStitch(frame + 1);
142
144
  }
143
145
  : undefined,
@@ -149,6 +151,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
149
151
  chromiumOptions,
150
152
  scale,
151
153
  ffmpegExecutable,
154
+ ffprobeExecutable,
152
155
  browserExecutable,
153
156
  port,
154
157
  cancelSignal: cancelRenderFrames.cancelSignal,
@@ -180,6 +183,7 @@ const renderMedia = ({ parallelism, proResProfile, crf, composition, imageFormat
180
183
  crf,
181
184
  assetsInfo,
182
185
  ffmpegExecutable,
186
+ ffprobeExecutable,
183
187
  onProgress: (frame) => {
184
188
  stitchStage = 'muxing';
185
189
  encodedFrames = frame;
@@ -22,6 +22,7 @@ declare type InnerStillOptions = {
22
22
  onDownload?: RenderMediaOnDownload;
23
23
  cancelSignal?: CancelSignal;
24
24
  ffmpegExecutable?: FfmpegExecutable;
25
+ ffprobeExecutable?: FfmpegExecutable;
25
26
  };
26
27
  declare type RenderStillOptions = InnerStillOptions & ServeUrlOrWebpackBundle & {
27
28
  port?: number | null;
@@ -76,7 +76,7 @@ const innerRenderStill = async ({ composition, quality, imageFormat = 'png', ser
76
76
  forceDeviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
77
77
  }));
78
78
  const page = await browserInstance.newPage();
79
- page.setViewport({
79
+ await page.setViewport({
80
80
  width: composition.width,
81
81
  height: composition.height,
82
82
  deviceScaleFactor: scale !== null && scale !== void 0 ? scale : 1,
@@ -146,7 +146,7 @@ const renderStill = (options) => {
146
146
  const downloadDir = (0, make_assets_download_dir_1.makeAssetsDownloadTmpDir)();
147
147
  const onDownload = (_a = options.onDownload) !== null && _a !== void 0 ? _a : (() => () => undefined);
148
148
  const happyPath = new Promise((resolve, reject) => {
149
- var _a, _b;
149
+ var _a, _b, _c;
150
150
  const onError = (err) => reject(err);
151
151
  let close = null;
152
152
  (0, prepare_server_1.prepareServer)({
@@ -155,7 +155,8 @@ const renderStill = (options) => {
155
155
  onDownload,
156
156
  onError,
157
157
  ffmpegExecutable: (_a = options.ffmpegExecutable) !== null && _a !== void 0 ? _a : null,
158
- port: (_b = options.port) !== null && _b !== void 0 ? _b : null,
158
+ ffprobeExecutable: (_b = options.ffprobeExecutable) !== null && _b !== void 0 ? _b : null,
159
+ port: (_c = options.port) !== null && _c !== void 0 ? _c : null,
159
160
  })
160
161
  .then(({ serveUrl, closeServer, offthreadPort }) => {
161
162
  close = closeServer;
@@ -3,6 +3,7 @@ import { RenderMediaOnDownload } from './assets/download-and-map-assets-to-file'
3
3
  export declare const serveStatic: (path: string | null, options: {
4
4
  port: number | null;
5
5
  ffmpegExecutable: FfmpegExecutable;
6
+ ffprobeExecutable: FfmpegExecutable;
6
7
  downloadDir: string;
7
8
  onDownload: RenderMediaOnDownload;
8
9
  onError: (err: Error) => void;
@@ -14,6 +14,7 @@ const serveStatic = async (path, options) => {
14
14
  const port = await (0, get_port_1.getDesiredPort)((_b = (_a = options === null || options === void 0 ? void 0 : options.port) !== null && _a !== void 0 ? _a : remotion_1.Internals.getServerPort()) !== null && _b !== void 0 ? _b : undefined, 3000, 3100);
15
15
  const offthreadRequest = (0, offthread_video_server_1.startOffthreadVideoServer)({
16
16
  ffmpegExecutable: options.ffmpegExecutable,
17
+ ffprobeExecutable: options.ffprobeExecutable,
17
18
  downloadDir: options.downloadDir,
18
19
  onDownload: options.onDownload,
19
20
  onError: options.onError,
@@ -16,6 +16,7 @@ export declare type StitcherOptions = {
16
16
  proResProfile?: ProResProfile;
17
17
  verbose?: boolean;
18
18
  ffmpegExecutable?: FfmpegExecutable;
19
+ ffprobeExecutable?: FfmpegExecutable;
19
20
  dir?: string;
20
21
  cancelSignal?: CancelSignal;
21
22
  internalOptions?: {
@@ -25,7 +25,7 @@ const packageJsonPath = path_1.default.join(__dirname, '..', 'package.json');
25
25
  const packageJson = fs_1.default.existsSync(packageJsonPath)
26
26
  ? JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'))
27
27
  : null;
28
- const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFrames, verbose, ffmpegExecutable, onProgress, }) => {
28
+ const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFrames, verbose, ffmpegExecutable, ffprobeExecutable, onProgress, }) => {
29
29
  const fileUrlAssets = await (0, convert_assets_to_file_urls_1.convertAssetsToFileUrls)({
30
30
  assets,
31
31
  downloadDir,
@@ -45,6 +45,7 @@ const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFra
45
45
  const filterFile = path_1.default.join(tempPath, `${index}.wav`);
46
46
  const result = await (0, preprocess_audio_track_1.preprocessAudioTrack)({
47
47
  ffmpegExecutable: ffmpegExecutable !== null && ffmpegExecutable !== void 0 ? ffmpegExecutable : null,
48
+ ffprobeExecutable: ffprobeExecutable !== null && ffprobeExecutable !== void 0 ? ffprobeExecutable : null,
48
49
  outName: filterFile,
49
50
  asset,
50
51
  expectedFrames,
@@ -68,7 +69,7 @@ const getAssetsData = async ({ assets, downloadDir, onDownload, fps, expectedFra
68
69
  return outName;
69
70
  };
70
71
  const spawnFfmpeg = async (options) => {
71
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
72
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
72
73
  remotion_1.Internals.validateDimension(options.height, 'height', 'passed to `stitchFramesToVideo()`');
73
74
  remotion_1.Internals.validateDimension(options.width, 'width', 'passed to `stitchFramesToVideo()`');
74
75
  remotion_1.Internals.validateFps(options.fps, 'passed to `stitchFramesToVideo()`');
@@ -115,6 +116,7 @@ const spawnFfmpeg = async (options) => {
115
116
  expectedFrames,
116
117
  verbose: (_f = options.verbose) !== null && _f !== void 0 ? _f : false,
117
118
  ffmpegExecutable: (_g = options.ffmpegExecutable) !== null && _g !== void 0 ? _g : null,
119
+ ffprobeExecutable: (_h = options.ffprobeExecutable) !== null && _h !== void 0 ? _h : null,
118
120
  onProgress: (prog) => updateProgress(prog, 0),
119
121
  });
120
122
  if (isAudioOnly) {
@@ -129,11 +131,11 @@ const spawnFfmpeg = async (options) => {
129
131
  options.force ? '-y' : null,
130
132
  options.outputLocation,
131
133
  ].filter(remotion_1.Internals.truthy));
132
- (_h = options.cancelSignal) === null || _h === void 0 ? void 0 : _h.call(options, () => {
134
+ (_j = options.cancelSignal) === null || _j === void 0 ? void 0 : _j.call(options, () => {
133
135
  ffmpegTask.kill();
134
136
  });
135
137
  await ffmpegTask;
136
- (_j = options.onProgress) === null || _j === void 0 ? void 0 : _j.call(options, expectedFrames);
138
+ (_k = options.onProgress) === null || _k === void 0 ? void 0 : _k.call(options, expectedFrames);
137
139
  return {
138
140
  getLogs: () => '',
139
141
  task: Promise.resolve(),
@@ -141,8 +143,8 @@ const spawnFfmpeg = async (options) => {
141
143
  }
142
144
  const ffmpegArgs = [
143
145
  ['-r', String(options.fps)],
144
- ...(((_k = options.internalOptions) === null || _k === void 0 ? void 0 : _k.preEncodedFileLocation)
145
- ? [['-i', (_l = options.internalOptions) === null || _l === void 0 ? void 0 : _l.preEncodedFileLocation]]
146
+ ...(((_l = options.internalOptions) === null || _l === void 0 ? void 0 : _l.preEncodedFileLocation)
147
+ ? [['-i', (_m = options.internalOptions) === null || _m === void 0 ? void 0 : _m.preEncodedFileLocation]]
146
148
  : [
147
149
  ['-f', 'image2'],
148
150
  ['-s', `${options.width}x${options.height}`],
@@ -153,7 +155,7 @@ const spawnFfmpeg = async (options) => {
153
155
  // -c:v is the same as -vcodec as -codec:video
154
156
  // and specified the video codec.
155
157
  ['-c:v', encoderName],
156
- ...(((_m = options.internalOptions) === null || _m === void 0 ? void 0 : _m.preEncodedFileLocation)
158
+ ...(((_o = options.internalOptions) === null || _o === void 0 ? void 0 : _o.preEncodedFileLocation)
157
159
  ? []
158
160
  : [
159
161
  proResProfileName ? ['-profile:v', proResProfileName] : null,
@@ -181,15 +183,15 @@ const spawnFfmpeg = async (options) => {
181
183
  console.log(ffmpegArgs);
182
184
  }
183
185
  const ffmpegString = ffmpegArgs.flat(2).filter(Boolean);
184
- const task = (0, execa_1.default)((_o = options.ffmpegExecutable) !== null && _o !== void 0 ? _o : 'ffmpeg', ffmpegString, {
186
+ const task = (0, execa_1.default)((_p = options.ffmpegExecutable) !== null && _p !== void 0 ? _p : 'ffmpeg', ffmpegString, {
185
187
  cwd: options.dir,
186
188
  });
187
- (_p = options.cancelSignal) === null || _p === void 0 ? void 0 : _p.call(options, () => {
189
+ (_q = options.cancelSignal) === null || _q === void 0 ? void 0 : _q.call(options, () => {
188
190
  task.kill();
189
191
  });
190
192
  let ffmpegOutput = '';
191
193
  let isFinished = false;
192
- (_q = task.stderr) === null || _q === void 0 ? void 0 : _q.on('data', (data) => {
194
+ (_r = task.stderr) === null || _r === void 0 ? void 0 : _r.on('data', (data) => {
193
195
  var _a;
194
196
  const str = data.toString();
195
197
  ffmpegOutput += str;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "3.0.16",
3
+ "version": "3.0.17",
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
  "puppeteer-core": "13.5.1",
25
- "remotion": "3.0.16",
25
+ "remotion": "3.0.17",
26
26
  "serve-handler": "6.1.3",
27
27
  "source-map": "^0.8.0-beta.0"
28
28
  },
@@ -59,5 +59,5 @@
59
59
  "publishConfig": {
60
60
  "access": "public"
61
61
  },
62
- "gitHead": "9f09f61ae8fb65674d7dfbfc526a8f909d426519"
62
+ "gitHead": "c973653a9ced0d8793ce0cb03ce5f837b149d865"
63
63
  }