@remotion/renderer 4.0.45 → 4.0.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md CHANGED
@@ -38,4 +38,4 @@ Support is provided on a best-we-can-do basis via GitHub Issues and Discord.
38
38
 
39
39
  You are required to obtain a company license to use Remotion if you are not within the group of entities eligible for a free license. This license will enable you to use Remotion for the allowed use cases specified in the free license, and give you access to prioritized support (read the [Support Policy](/docs/support)).
40
40
 
41
- Visit [companies.remotion.dev](https://companies.remotion.dev) for pricing and to buy a license.
41
+ Visit [remotion.pro](https://www.remotion.pro) for pricing and to buy a license.
@@ -43,6 +43,7 @@ const calculateAssetPositions = (frames) => {
43
43
  volume: [],
44
44
  playbackRate: asset.playbackRate,
45
45
  allowAmplificationDuringRender: asset.allowAmplificationDuringRender,
46
+ toneFrequency: asset.toneFrequency,
46
47
  });
47
48
  }
48
49
  const found = assets.find((a) => a.duration === null && areEqual(a, asset));
@@ -7,6 +7,7 @@ export type UnsafeAsset = Omit<TRenderAsset, 'frame' | 'id' | 'volume' | 'mediaF
7
7
  id: string;
8
8
  playbackRate: number;
9
9
  allowAmplificationDuringRender: boolean;
10
+ toneFrequency: number | null;
10
11
  };
11
12
  export type AssetVolume = number | number[];
12
13
  export type MediaAsset = Omit<UnsafeAsset, 'duration' | 'volume'> & {
@@ -13,7 +13,7 @@ export declare const supportedAudioCodecs: {
13
13
  readonly vp9: readonly ["opus", "pcm-16"];
14
14
  readonly wav: readonly ["pcm-16"];
15
15
  };
16
- declare const audioCodecNames: readonly ["pcm_s16le", "aac", "libmp3lame", "libopus"];
16
+ declare const audioCodecNames: readonly ["pcm_s16le", "libfdk_aac", "libmp3lame", "libopus"];
17
17
  type FfmpegAudioCodecName = (typeof audioCodecNames)[number];
18
18
  export declare const mapAudioCodecToFfmpegAudioCodecName: (audioCodec: AudioCodec) => FfmpegAudioCodecName;
19
19
  export declare const defaultAudioCodecs: {
@@ -18,10 +18,15 @@ const _satisfies = exports.supportedAudioCodecs;
18
18
  if (_satisfies) {
19
19
  // Just for type checking
20
20
  }
21
- const audioCodecNames = ['pcm_s16le', 'aac', 'libmp3lame', 'libopus'];
21
+ const audioCodecNames = [
22
+ 'pcm_s16le',
23
+ 'libfdk_aac',
24
+ 'libmp3lame',
25
+ 'libopus',
26
+ ];
22
27
  const mapAudioCodecToFfmpegAudioCodecName = (audioCodec) => {
23
28
  if (audioCodec === 'aac') {
24
- return 'aac';
29
+ return 'libfdk_aac';
25
30
  }
26
31
  if (audioCodec === 'mp3') {
27
32
  return 'libmp3lame';
@@ -32,14 +32,24 @@ export declare const enum BrowserEmittedEvents {
32
32
  }
33
33
  export declare class HeadlessBrowser extends EventEmitter {
34
34
  #private;
35
- static _create({ connection, defaultViewport, closeCallback, }: {
35
+ static _create({ connection, defaultViewport, closeCallback, forgetEventLoop, rememberEventLoop, }: {
36
36
  connection: Connection;
37
37
  defaultViewport: Viewport;
38
38
  closeCallback: BrowserCloseCallback;
39
+ forgetEventLoop: () => void;
40
+ rememberEventLoop: () => void;
39
41
  }): Promise<HeadlessBrowser>;
40
42
  connection: Connection;
43
+ forgetEventLoop: () => void;
44
+ rememberEventLoop: () => void;
41
45
  get _targets(): Map<string, Target>;
42
- constructor(connection: Connection, defaultViewport: Viewport, closeCallback?: BrowserCloseCallback);
46
+ constructor({ closeCallback, connection, defaultViewport, forgetEventLoop, rememberEventLoop, }: {
47
+ connection: Connection;
48
+ defaultViewport: Viewport;
49
+ closeCallback: BrowserCloseCallback;
50
+ forgetEventLoop: () => void;
51
+ rememberEventLoop: () => void;
52
+ });
43
53
  browserContexts(): BrowserContext[];
44
54
  newPage(context: Promise<AnySourceMapConsumer | null>, logLevel: LogLevel, indent: boolean): Promise<Page>;
45
55
  _createPageInContext(context: Promise<AnySourceMapConsumer | null>, logLevel: LogLevel, indent: boolean): Promise<Page>;
@@ -33,15 +33,21 @@ const EventEmitter_1 = require("./EventEmitter");
33
33
  const Target_1 = require("./Target");
34
34
  const util_1 = require("./util");
35
35
  class HeadlessBrowser extends EventEmitter_1.EventEmitter {
36
- static async _create({ connection, defaultViewport, closeCallback, }) {
37
- const browser = new HeadlessBrowser(connection, defaultViewport, closeCallback);
36
+ static async _create({ connection, defaultViewport, closeCallback, forgetEventLoop, rememberEventLoop, }) {
37
+ const browser = new HeadlessBrowser({
38
+ connection,
39
+ defaultViewport,
40
+ closeCallback,
41
+ forgetEventLoop,
42
+ rememberEventLoop,
43
+ });
38
44
  await connection.send('Target.setDiscoverTargets', { discover: true });
39
45
  return browser;
40
46
  }
41
47
  get _targets() {
42
48
  return __classPrivateFieldGet(this, _HeadlessBrowser_targets, "f");
43
49
  }
44
- constructor(connection, defaultViewport, closeCallback) {
50
+ constructor({ closeCallback, connection, defaultViewport, forgetEventLoop, rememberEventLoop, }) {
45
51
  super();
46
52
  _HeadlessBrowser_instances.add(this);
47
53
  _HeadlessBrowser_defaultViewport.set(this, void 0);
@@ -51,16 +57,15 @@ class HeadlessBrowser extends EventEmitter_1.EventEmitter {
51
57
  _HeadlessBrowser_targets.set(this, void 0);
52
58
  __classPrivateFieldSet(this, _HeadlessBrowser_defaultViewport, defaultViewport, "f");
53
59
  this.connection = connection;
54
- __classPrivateFieldSet(this, _HeadlessBrowser_closeCallback, closeCallback ||
55
- function () {
56
- return undefined;
57
- }, "f");
60
+ __classPrivateFieldSet(this, _HeadlessBrowser_closeCallback, closeCallback, "f");
58
61
  __classPrivateFieldSet(this, _HeadlessBrowser_defaultContext, new BrowserContext(this), "f");
59
62
  __classPrivateFieldSet(this, _HeadlessBrowser_contexts, new Map(), "f");
60
63
  __classPrivateFieldSet(this, _HeadlessBrowser_targets, new Map(), "f");
61
64
  this.connection.on('Target.targetCreated', __classPrivateFieldGet(this, _HeadlessBrowser_instances, "m", _HeadlessBrowser_targetCreated).bind(this));
62
65
  this.connection.on('Target.targetDestroyed', __classPrivateFieldGet(this, _HeadlessBrowser_instances, "m", _HeadlessBrowser_targetDestroyed).bind(this));
63
66
  this.connection.on('Target.targetInfoChanged', __classPrivateFieldGet(this, _HeadlessBrowser_instances, "m", _HeadlessBrowser_targetInfoChanged).bind(this));
67
+ this.forgetEventLoop = forgetEventLoop;
68
+ this.rememberEventLoop = rememberEventLoop;
64
69
  }
65
70
  browserContexts() {
66
71
  return [__classPrivateFieldGet(this, _HeadlessBrowser_defaultContext, "f"), ...Array.from(__classPrivateFieldGet(this, _HeadlessBrowser_contexts, "f").values())];
@@ -28,6 +28,8 @@ export declare class BrowserRunner {
28
28
  });
29
29
  start(options: LaunchOptions): void;
30
30
  close(): Promise<void>;
31
+ forgetEventLoop(): void;
32
+ rememberEventLoop(): void;
31
33
  kill(): void;
32
34
  setupConnection(options: {
33
35
  timeout: number;
@@ -153,6 +153,28 @@ class BrowserRunner {
153
153
  (0, util_1.removeEventListeners)(__classPrivateFieldGet(this, _BrowserRunner_listeners, "f"));
154
154
  return __classPrivateFieldGet(this, _BrowserRunner_processClosing, "f");
155
155
  }
156
+ forgetEventLoop() {
157
+ var _a, _b;
158
+ (0, assert_1.assert)(this.proc, 'BrowserRunner not started.');
159
+ this.proc.unref();
160
+ // @ts-expect-error
161
+ (_a = this.proc.stdout) === null || _a === void 0 ? void 0 : _a.unref();
162
+ // @ts-expect-error
163
+ (_b = this.proc.stderr) === null || _b === void 0 ? void 0 : _b.unref();
164
+ (0, assert_1.assert)(this.connection, 'BrowserRunner not connected.');
165
+ this.connection.transport.forgetEventLoop();
166
+ }
167
+ rememberEventLoop() {
168
+ var _a, _b;
169
+ (0, assert_1.assert)(this.proc, 'BrowserRunner not started.');
170
+ this.proc.ref();
171
+ // @ts-expect-error
172
+ (_a = this.proc.stdout) === null || _a === void 0 ? void 0 : _a.ref();
173
+ // @ts-expect-error
174
+ (_b = this.proc.stderr) === null || _b === void 0 ? void 0 : _b.ref();
175
+ (0, assert_1.assert)(this.connection, 'BrowserRunner not connected.');
176
+ this.connection.transport.rememberEventLoop();
177
+ }
156
178
  kill() {
157
179
  var _a;
158
180
  // If the process failed to launch (for example if the browser executable path
@@ -4,6 +4,7 @@ import { EventEmitter } from './EventEmitter';
4
4
  import type { NodeWebSocketTransport } from './NodeWebSocketTransport';
5
5
  export declare class Connection extends EventEmitter {
6
6
  #private;
7
+ transport: NodeWebSocketTransport;
7
8
  constructor(transport: NodeWebSocketTransport);
8
9
  static fromSession(session: CDPSession): Connection | undefined;
9
10
  session(sessionId: string): CDPSession | null;
@@ -1,16 +1,16 @@
1
1
  "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
2
7
  var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
8
  if (kind === "m") throw new TypeError("Private method is not writable");
4
9
  if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
12
  };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _Connection_instances, _Connection_transport, _Connection_lastId, _Connection_sessions, _Connection_closed, _Connection_callbacks, _Connection_onMessage, _Connection_onClose, _CDPSession_sessionId, _CDPSession_targetType, _CDPSession_callbacks, _CDPSession_connection;
13
+ var _Connection_instances, _Connection_lastId, _Connection_sessions, _Connection_closed, _Connection_callbacks, _Connection_onMessage, _Connection_onClose, _CDPSession_sessionId, _CDPSession_targetType, _CDPSession_callbacks, _CDPSession_connection;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.CDPSession = exports.CDPSessionEmittedEvents = exports.Connection = void 0;
16
16
  /**
@@ -38,14 +38,13 @@ class Connection extends EventEmitter_1.EventEmitter {
38
38
  constructor(transport) {
39
39
  super();
40
40
  _Connection_instances.add(this);
41
- _Connection_transport.set(this, void 0);
42
41
  _Connection_lastId.set(this, 0);
43
42
  _Connection_sessions.set(this, new Map());
44
43
  _Connection_closed.set(this, false);
45
44
  _Connection_callbacks.set(this, new Map());
46
- __classPrivateFieldSet(this, _Connection_transport, transport, "f");
47
- __classPrivateFieldGet(this, _Connection_transport, "f").onmessage = __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_onMessage).bind(this);
48
- __classPrivateFieldGet(this, _Connection_transport, "f").onclose = __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_onClose).bind(this);
45
+ this.transport = transport;
46
+ this.transport.onmessage = __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_onMessage).bind(this);
47
+ this.transport.onclose = __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_onClose).bind(this);
49
48
  }
50
49
  static fromSession(session) {
51
50
  return session.connection();
@@ -75,12 +74,12 @@ class Connection extends EventEmitter_1.EventEmitter {
75
74
  var _a;
76
75
  const id = __classPrivateFieldSet(this, _Connection_lastId, (_a = __classPrivateFieldGet(this, _Connection_lastId, "f"), ++_a), "f");
77
76
  const stringifiedMessage = JSON.stringify({ ...message, id });
78
- __classPrivateFieldGet(this, _Connection_transport, "f").send(stringifiedMessage);
77
+ this.transport.send(stringifiedMessage);
79
78
  return id;
80
79
  }
81
80
  dispose() {
82
81
  __classPrivateFieldGet(this, _Connection_instances, "m", _Connection_onClose).call(this);
83
- __classPrivateFieldGet(this, _Connection_transport, "f").close();
82
+ this.transport.close();
84
83
  }
85
84
  /**
86
85
  * @param targetInfo - The target info
@@ -99,7 +98,7 @@ class Connection extends EventEmitter_1.EventEmitter {
99
98
  }
100
99
  }
101
100
  exports.Connection = Connection;
102
- _Connection_transport = new WeakMap(), _Connection_lastId = new WeakMap(), _Connection_sessions = new WeakMap(), _Connection_closed = new WeakMap(), _Connection_callbacks = new WeakMap(), _Connection_instances = new WeakSet(), _Connection_onMessage = function _Connection_onMessage(message) {
101
+ _Connection_lastId = new WeakMap(), _Connection_sessions = new WeakMap(), _Connection_closed = new WeakMap(), _Connection_callbacks = new WeakMap(), _Connection_instances = new WeakSet(), _Connection_onMessage = function _Connection_onMessage(message) {
103
102
  const object = JSON.parse(message);
104
103
  if (object.method === 'Target.attachedToTarget') {
105
104
  const { sessionId } = object.params;
@@ -152,8 +151,8 @@ _Connection_transport = new WeakMap(), _Connection_lastId = new WeakMap(), _Conn
152
151
  if (__classPrivateFieldGet(this, _Connection_closed, "f")) {
153
152
  return;
154
153
  }
155
- __classPrivateFieldGet(this, _Connection_transport, "f").onmessage = undefined;
156
- __classPrivateFieldGet(this, _Connection_transport, "f").onclose = undefined;
154
+ this.transport.onmessage = undefined;
155
+ this.transport.onclose = undefined;
157
156
  for (const callback of __classPrivateFieldGet(this, _Connection_callbacks, "f").values()) {
158
157
  callback.reject(rewriteError(new Errors_1.ProtocolError(), `Protocol error (${callback.method}): Target closed. https://www.remotion.dev/docs/target-closed`));
159
158
  }
@@ -92,6 +92,8 @@ class ChromeLauncher {
92
92
  connection,
93
93
  defaultViewport,
94
94
  closeCallback: runner.close.bind(runner),
95
+ forgetEventLoop: runner.forgetEventLoop.bind(runner),
96
+ rememberEventLoop: runner.rememberEventLoop.bind(runner),
95
97
  });
96
98
  }
97
99
  catch (error) {
@@ -6,12 +6,14 @@ interface ConnectionTransport {
6
6
  onclose?: () => void;
7
7
  }
8
8
  export declare class NodeWebSocketTransport implements ConnectionTransport {
9
- #private;
10
9
  static create(urlString: string): Promise<NodeWebSocketTransport>;
10
+ websocket: WS;
11
11
  onmessage?: (message: string) => void;
12
12
  onclose?: () => void;
13
13
  constructor(ws: WS);
14
14
  send(message: string): void;
15
15
  close(): void;
16
+ forgetEventLoop(): void;
17
+ rememberEventLoop(): void;
16
18
  }
17
19
  export {};
@@ -1,16 +1,4 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _NodeWebSocketTransport_ws;
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
3
  exports.NodeWebSocketTransport = void 0;
16
4
  /**
@@ -61,27 +49,33 @@ class NodeWebSocketTransport {
61
49
  });
62
50
  }
63
51
  constructor(ws) {
64
- _NodeWebSocketTransport_ws.set(this, void 0);
65
- __classPrivateFieldSet(this, _NodeWebSocketTransport_ws, ws, "f");
66
- __classPrivateFieldGet(this, _NodeWebSocketTransport_ws, "f").addEventListener('message', (event) => {
52
+ this.websocket = ws;
53
+ this.websocket.addEventListener('message', (event) => {
67
54
  if (this.onmessage) {
68
55
  this.onmessage.call(null, event.data);
69
56
  }
70
57
  });
71
- __classPrivateFieldGet(this, _NodeWebSocketTransport_ws, "f").addEventListener('close', () => {
58
+ this.websocket.addEventListener('close', () => {
72
59
  if (this.onclose) {
73
60
  this.onclose.call(null);
74
61
  }
75
62
  });
76
63
  // Silently ignore all errors - we don't know what to do with them.
77
- __classPrivateFieldGet(this, _NodeWebSocketTransport_ws, "f").addEventListener('error', () => undefined);
64
+ this.websocket.addEventListener('error', () => undefined);
78
65
  }
79
66
  send(message) {
80
- __classPrivateFieldGet(this, _NodeWebSocketTransport_ws, "f").send(message);
67
+ this.websocket.send(message);
81
68
  }
82
69
  close() {
83
- __classPrivateFieldGet(this, _NodeWebSocketTransport_ws, "f").close();
70
+ this.websocket.close();
71
+ }
72
+ forgetEventLoop() {
73
+ // @ts-expect-error
74
+ this.websocket._socket.unref();
75
+ }
76
+ rememberEventLoop() {
77
+ // @ts-expect-error
78
+ this.websocket._socket.ref();
84
79
  }
85
80
  }
86
81
  exports.NodeWebSocketTransport = NodeWebSocketTransport;
87
- _NodeWebSocketTransport_ws = new WeakMap();
@@ -20,6 +20,7 @@ const calculateFfmpegFilter = ({ asset, fps, durationInFrames, channels, assetDu
20
20
  durationInFrames,
21
21
  assetDuration,
22
22
  allowAmplificationDuringRender: asset.allowAmplificationDuringRender,
23
+ toneFrequency: asset.toneFrequency,
23
24
  });
24
25
  };
25
26
  exports.calculateFfmpegFilter = calculateFfmpegFilter;
@@ -10,6 +10,7 @@ type Options = {
10
10
  fps: number;
11
11
  numberOfGifLoops: number | null;
12
12
  audioCodec: AudioCodec | null;
13
+ audioBitrate: string | null;
13
14
  };
14
15
  export declare const combineVideos: (options: Options) => Promise<void>;
15
16
  export {};
@@ -12,7 +12,7 @@ const parse_ffmpeg_progress_1 = require("./parse-ffmpeg-progress");
12
12
  const truthy_1 = require("./truthy");
13
13
  const combineVideos = async (options) => {
14
14
  var _a;
15
- const { files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, audioCodec, } = options;
15
+ const { files, filelistDir, output, onProgress, numberOfFrames, codec, fps, numberOfGifLoops, audioCodec, audioBitrate, } = options;
16
16
  const fileList = files.map((p) => `file '${p}'`).join('\n');
17
17
  const fileListTxt = (0, node_path_1.join)(filelistDir, 'files.txt');
18
18
  (0, node_fs_1.writeFileSync)(fileListTxt, fileList);
@@ -38,9 +38,10 @@ const combineVideos = async (options) => {
38
38
  resolvedAudioCodec
39
39
  ? (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec)
40
40
  : null,
41
- // Set max bitrate up to 512kbps, will choose lower if that's too much
41
+ resolvedAudioCodec === 'aac' ? '-cutoff' : null,
42
+ resolvedAudioCodec === 'aac' ? '18000' : null,
42
43
  '-b:a',
43
- '512K',
44
+ audioBitrate ? audioBitrate : '320k',
44
45
  codec === 'h264' ? '-movflags' : null,
45
46
  codec === 'h264' ? 'faststart' : null,
46
47
  '-y',
@@ -56,7 +57,7 @@ const combineVideos = async (options) => {
56
57
  logger_1.Log.verbose(data.toString('utf8'));
57
58
  }
58
59
  else {
59
- logger_1.Log.verbose(parsed);
60
+ logger_1.Log.verbose(`Combined ${parsed} frames`);
60
61
  onProgress(parsed);
61
62
  }
62
63
  }
package/dist/index.d.ts CHANGED
@@ -152,6 +152,7 @@ export declare const RenderInternals: {
152
152
  fps: number;
153
153
  numberOfGifLoops: number | null;
154
154
  audioCodec: "mp3" | "aac" | "pcm-16" | "opus" | null;
155
+ audioBitrate: string | null;
155
156
  }) => Promise<void>;
156
157
  getMinConcurrency: () => number;
157
158
  getMaxConcurrency: () => number;
package/dist/locks.js CHANGED
@@ -25,6 +25,9 @@ const createLock = ({ timeout }) => {
25
25
  });
26
26
  });
27
27
  resolveWaiters();
28
+ if (locks.length === 0) {
29
+ return Promise.resolve();
30
+ }
28
31
  if (timeout === null) {
29
32
  return success;
30
33
  }
@@ -26,9 +26,10 @@ function valueFromRemoteObject(remoteObject) {
26
26
  return remoteObject.value;
27
27
  }
28
28
  function puppeteerEvaluateWithCatchAndTimeout({ args, frame, page, pageFunction, }) {
29
+ let timeout = null;
29
30
  return Promise.race([
30
31
  new Promise((_, reject) => {
31
- setTimeout(() => {
32
+ timeout = setTimeout(() => {
32
33
  reject(new Error(
33
34
  // This means the page is not responding anymore
34
35
  // This error message is retryable - sync it with packages/lambda/src/shared/is-flaky-error.ts
@@ -41,7 +42,12 @@ function puppeteerEvaluateWithCatchAndTimeout({ args, frame, page, pageFunction,
41
42
  page,
42
43
  pageFunction,
43
44
  }),
44
- ]);
45
+ ]).then((data) => {
46
+ if (timeout !== null) {
47
+ clearTimeout(timeout);
48
+ }
49
+ return data;
50
+ });
45
51
  }
46
52
  exports.puppeteerEvaluateWithCatchAndTimeout = puppeteerEvaluateWithCatchAndTimeout;
47
53
  async function puppeteerEvaluateWithCatch({ page, pageFunction, frame, args, }) {
@@ -150,14 +150,19 @@ const innerSetPropsAndEnv = async ({ serializedInputPropsWithCustomSchema, envVa
150
150
  }
151
151
  }
152
152
  };
153
- const setPropsAndEnv = (params) => {
154
- return Promise.race([
153
+ const setPropsAndEnv = async (params) => {
154
+ let timeout = null;
155
+ const result = await Promise.race([
155
156
  innerSetPropsAndEnv(params),
156
157
  new Promise((_, reject) => {
157
- setTimeout(() => {
158
+ timeout = setTimeout(() => {
158
159
  reject(new Error(`Timed out after ${params.timeoutInMilliseconds} while setting up the headless browser. This could be because the you specified takes a long time to load (or network resources that it includes like fonts) or because the browser is not responding. Optimize the site or increase the browser timeout.`));
159
160
  }, params.timeoutInMilliseconds);
160
161
  }),
161
162
  ]);
163
+ if (timeout !== null) {
164
+ clearTimeout(timeout);
165
+ }
166
+ return result;
162
167
  };
163
168
  exports.setPropsAndEnv = setPropsAndEnv;
@@ -193,9 +193,8 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec,
193
193
  audio,
194
194
  '-c:a',
195
195
  (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec),
196
- // Set bitrate up to 320k, for aac it might effectively be lower
197
196
  '-b:a',
198
- audioBitrate !== null && audioBitrate !== void 0 ? audioBitrate : '320k',
197
+ audioBitrate ? audioBitrate : '320k',
199
198
  force ? '-y' : null,
200
199
  outputLocation !== null && outputLocation !== void 0 ? outputLocation : tempFile,
201
200
  ].filter(remotion_1.Internals.truthy));
@@ -254,8 +253,9 @@ const innerStitchFramesToVideo = async ({ assetsInfo, audioBitrate, audioCodec,
254
253
  resolvedAudioCodec
255
254
  ? ['-c:a', (0, audio_codec_1.mapAudioCodecToFfmpegAudioCodecName)(resolvedAudioCodec)]
256
255
  : null,
257
- // Set max bitrate up to 1024kbps, will choose lower if that's too much
258
- resolvedAudioCodec ? ['-b:a', audioBitrate || '512K'] : null,
256
+ resolvedAudioCodec ? ['-b:a', audioBitrate || '320k'] : null,
257
+ resolvedAudioCodec === 'aac' ? '-cutoff' : null,
258
+ resolvedAudioCodec === 'aac' ? '18000' : null,
259
259
  // Ignore metadata that may come from remote media
260
260
  ['-map_metadata', '-1'],
261
261
  [
@@ -6,7 +6,7 @@ export type ProcessedTrack = {
6
6
  pad_start: string | null;
7
7
  pad_end: string | null;
8
8
  };
9
- export declare const stringifyFfmpegFilter: ({ trimLeft, trimRight, channels, startInVideo, volume, fps, playbackRate, durationInFrames, assetDuration, allowAmplificationDuringRender, }: {
9
+ export declare const stringifyFfmpegFilter: ({ trimLeft, trimRight, channels, startInVideo, volume, fps, playbackRate, durationInFrames, assetDuration, allowAmplificationDuringRender, toneFrequency, }: {
10
10
  trimLeft: number;
11
11
  trimRight: number;
12
12
  channels: number;
@@ -17,4 +17,5 @@ export declare const stringifyFfmpegFilter: ({ trimLeft, trimRight, channels, st
17
17
  playbackRate: number;
18
18
  assetDuration: number | null;
19
19
  allowAmplificationDuringRender: boolean;
20
+ toneFrequency: number | null;
20
21
  }) => FilterWithoutPaddingApplied | null;
@@ -5,11 +5,14 @@ const calculate_atempo_1 = require("./assets/calculate-atempo");
5
5
  const ffmpeg_volume_expression_1 = require("./assets/ffmpeg-volume-expression");
6
6
  const sample_rate_1 = require("./sample-rate");
7
7
  const truthy_1 = require("./truthy");
8
- const stringifyFfmpegFilter = ({ trimLeft, trimRight, channels, startInVideo, volume, fps, playbackRate, durationInFrames, assetDuration, allowAmplificationDuringRender, }) => {
8
+ const stringifyFfmpegFilter = ({ trimLeft, trimRight, channels, startInVideo, volume, fps, playbackRate, durationInFrames, assetDuration, allowAmplificationDuringRender, toneFrequency, }) => {
9
9
  const startInVideoSeconds = startInVideo / fps;
10
10
  if (assetDuration && trimLeft >= assetDuration) {
11
11
  return null;
12
12
  }
13
+ if (toneFrequency !== null && (toneFrequency <= 0 || toneFrequency > 2)) {
14
+ throw new Error('toneFrequency must be a positive number between 0.01 and 2');
15
+ }
13
16
  const volumeFilter = (0, ffmpeg_volume_expression_1.ffmpegVolumeExpression)({
14
17
  volume,
15
18
  fps,
@@ -37,6 +40,9 @@ const stringifyFfmpegFilter = ({ trimLeft, trimRight, channels, startInVideo, vo
37
40
  volumeFilter.value === '1'
38
41
  ? null
39
42
  : `volume=${volumeFilter.value}:eval=${volumeFilter.eval}`,
43
+ toneFrequency && toneFrequency !== 1
44
+ ? `asetrate=${sample_rate_1.DEFAULT_SAMPLE_RATE}*${toneFrequency},aresample=${sample_rate_1.DEFAULT_SAMPLE_RATE},atempo=1/${toneFrequency}`
45
+ : null,
40
46
  // For n channels, we delay n + 1 channels.
41
47
  // This is because `ffprobe` for some audio files reports the wrong amount
42
48
  // of channels.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/renderer",
3
- "version": "4.0.45",
3
+ "version": "4.0.47",
4
4
  "description": "Renderer for Remotion",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,14 +18,14 @@
18
18
  "extract-zip": "2.0.1",
19
19
  "source-map": "^0.8.0-beta.0",
20
20
  "ws": "8.7.0",
21
- "remotion": "4.0.45"
21
+ "remotion": "4.0.47"
22
22
  },
23
23
  "peerDependencies": {
24
24
  "react": ">=16.8.0",
25
25
  "react-dom": ">=16.8.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@jonny/eslint-config": "3.0.266",
28
+ "@jonny/eslint-config": "3.0.276",
29
29
  "@testing-library/dom": "^8.16.0",
30
30
  "@testing-library/react": "13.3.0",
31
31
  "@types/node": "18.14.6",
@@ -40,13 +40,13 @@
40
40
  "vitest": "0.31.1"
41
41
  },
42
42
  "optionalDependencies": {
43
- "@remotion/compositor-darwin-arm64": "4.0.45",
44
- "@remotion/compositor-darwin-x64": "4.0.45",
45
- "@remotion/compositor-linux-arm64-gnu": "4.0.45",
46
- "@remotion/compositor-linux-arm64-musl": "4.0.45",
47
- "@remotion/compositor-linux-x64-gnu": "4.0.45",
48
- "@remotion/compositor-linux-x64-musl": "4.0.45",
49
- "@remotion/compositor-win32-x64-msvc": "4.0.45"
43
+ "@remotion/compositor-darwin-arm64": "4.0.47",
44
+ "@remotion/compositor-darwin-x64": "4.0.47",
45
+ "@remotion/compositor-linux-arm64-gnu": "4.0.47",
46
+ "@remotion/compositor-linux-arm64-musl": "4.0.47",
47
+ "@remotion/compositor-linux-x64-gnu": "4.0.47",
48
+ "@remotion/compositor-linux-x64-musl": "4.0.47",
49
+ "@remotion/compositor-win32-x64-msvc": "4.0.47"
50
50
  },
51
51
  "keywords": [
52
52
  "remotion",