Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow FFMPEG command to be overridden #1320

Merged
merged 11 commits into from Sep 19, 2022
11 changes: 11 additions & 0 deletions packages/cli/src/config/ffmpeg-override.ts
@@ -0,0 +1,11 @@
import type {FfmpegOverrideFn} from '@remotion/renderer';

let ffmpegOverrideFn: FfmpegOverrideFn = ({args}) => args;

export const setFfmpegOverrideFunction = (fn: FfmpegOverrideFn) => {
ffmpegOverrideFn = fn;
};

export const getFfmpegOverrideFunction = () => {
return ffmpegOverrideFn;
};
6 changes: 6 additions & 0 deletions packages/cli/src/config/index.ts
Expand Up @@ -59,6 +59,10 @@ import {
import {setDotEnvLocation} from './env-file';
import {setEveryNthFrame} from './every-nth-frame';
import {setFfmpegExecutable, setFfprobeExecutable} from './ffmpeg-executable';
import {
getFfmpegOverrideFunction,
setFfmpegOverrideFunction,
} from './ffmpeg-override';
import {setFrameRange} from './frame-range';
import {setImageFormat} from './image-format';
import {setImageSequence} from './image-sequence';
Expand Down Expand Up @@ -128,6 +132,7 @@ export const Config: ConfigType = {
setCrf,
setImageSequence,
setProResProfile,
overrideFfmpegCommand: setFfmpegOverrideFunction,
},
} as ConfigType;

Expand Down Expand Up @@ -175,6 +180,7 @@ export const ConfigInternals = {
setEnforceAudioTrack,
getKeyboardShortcutsEnabled,
getPublicDir,
getFfmpegOverrideFunction,
};

export const overrideRemotion = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/get-cli-options.ts
Expand Up @@ -275,7 +275,7 @@ export const getCliOptions = async (options: {
port: port ?? null,
muted: ConfigInternals.getMuted(),
enforceAudioTrack: ConfigInternals.getEnforceAudioTrack(),
keyboardShortcutsEnables: ConfigInternals.getKeyboardShortcutsEnabled(),
publicDir: ConfigInternals.getPublicDir(),
ffmpegOverride: ConfigInternals.getFfmpegOverrideFunction(),
};
};
3 changes: 3 additions & 0 deletions packages/cli/src/render.tsx
Expand Up @@ -79,6 +79,7 @@ export const render = async (remotionRoot: string) => {
muted,
enforceAudioTrack,
publicDir,
ffmpegOverride,
} = await getCliOptions({
isLambda: false,
type: 'series',
Expand Down Expand Up @@ -335,6 +336,8 @@ export const render = async (remotionRoot: string) => {
downloadMap,
muted,
enforceAudioTrack,
browserExecutable,
ffmpegOverride,
});

Log.info();
Expand Down
10 changes: 10 additions & 0 deletions packages/core/src/config.ts
Expand Up @@ -243,6 +243,16 @@ export type ConfigType = {
| 'proxy'
| undefined
) => void;
/**
* Override the arguments that Remotion passes to FFMPEG.
* Consult https://remotion.dev/docs/renderer/render-media#ffmpegoverride before using this feature.
*/
readonly overrideFfmpegCommand: (
command: (info: {
type: 'pre-stitcher' | 'stitcher';
args: string[];
}) => string[]
) => void;
};
};
export type {Concurrency, WebpackConfiguration, WebpackOverrideFn};
Expand Down
31 changes: 31 additions & 0 deletions packages/docs/docs/config.md
Expand Up @@ -531,6 +531,37 @@ Config.Output.setCrf(16);

The [command line flag](/docs/cli/render#--crf) `--crf` will take precedence over this option.

### overrideFfmpegCommand

_available from v3.2.22_

Modifies the FFMPEG command that Remotion uses under the hood. It works reducer-style, meaning that you pass a function that takes a command as an argument and returns a new command.

```tsx twoslash
import { Config } from "remotion";
// ---cut---
Config.Output.overrideFfmpegCommand(({ args }) => {
return [...args, "-vf", "eq=brightness=0:saturation=1"];
});
```

The function you pass must accept an object as it's only parameter which contains the following properties:

- `type`: Either `"stitcher"` or `"pre-stitcher"`. If enough memory and CPU is available, Remotion may use parallel rendering and encoding, which means that a pre-stitcher process gets spawned before all frames are rendered. You can tell whether parallel encoding is enabled by adding `--log=verbose` to your render command.
- `args`: An array of strings that is passed as arguments to the FFMPEG command.

Your function must return a modified array of strings.

:::warning
Using this feature is discouraged. Before using it, we want to make you aware of some caveats:

- The render command can change with any new Remotion version, even when it is a patch upgrade. This might break your usage of this feature.
- Depending on the selected codec, available CPU and RAM, Remotion may or may not use "parallel encoding" which will result in multiple FFMPEG commands being executed. Your function must be able to handle being called multiple times.
- This feature is not available when using Remotion Lambda.

Before you use this hack, reach out to the Remotion team on [Discord](https://remotion.dev/discord) and ask us if we are open to implement the feature you need in a clean way - we often do implement new features quickly based on users feedback.
:::

## See also

- [Encoding guide](/docs/encoding)
74 changes: 53 additions & 21 deletions packages/docs/docs/renderer/render-media.md
Expand Up @@ -21,7 +21,7 @@ _string_

Either a local path pointing to a Remotion Webpack bundle generated by [`bundle()`](/docs/bundle) or a URL where the bundle is hosted.

### `outputLocation`
### `outputLocation?`

_string - optional since v3.0.26_

Expand All @@ -41,7 +41,7 @@ _"h264" (default) | "h265" | "vp8" | "vp9" | "mp3" | "aac" | "wav" | "prores" |

Choose a suitable codec for your output media. Refer to the [Encoding guide](/docs/encoding) to find the best codec for your use case.

### `inputProps`
### `inputProps?`

_object - optional_

Expand All @@ -57,13 +57,13 @@ A `number` specifying how many render processes should be started in parallel or

Renamed to `concurrency` in v3.2.17.

### `crf`
### `crf?`

_number | null - optional_

The constant rate factor, controlling the quality. See: [Controlling quality using the CRF setting.](/docs/encoding/#controlling-quality-using-the-crf-setting)

### `imageFormat`
### `imageFormat?`

_"jpeg" (default) | "png" | "none" - optional_

Expand All @@ -73,7 +73,7 @@ In which image format the frames should be rendered.
- `png` if you want to [render transparent videos](/docs/transparent-videos/)
- `none` if you are rendering audio

### `ffmpegExecutable`
### `ffmpegExecutable?`

_string - optional_

Expand Down Expand Up @@ -103,65 +103,65 @@ _optional, available since v3.1_

[Set the looping behavior.](/docs/config#setnumberofgifloops) This option may only be set when rendering GIFs. [See here for more details.](/docs/render-as-gif#changing-the-number-of-loops)

### `pixelFormat`
### `pixelFormat?`

_string - optional_

[A custom pixel format to use.](/docs/transparent-videos/) Usually used for special use cases like transparent videos.

### `envVariables`
### `envVariables?`

`Record<string, string> - optional`

An object containing environment variables to be injected in your project.

See: [Environment variables](/docs/env-variables/)

### `quality`
### `quality?`

_number - optional_

Sets the quality of the generated JPEG images. Must be an integer between 0 and 100. Default is to leave it up to the browser, [current default is 80](https://github.com/chromium/chromium/blob/99314be8152e688bafbbf9a615536bdbb289ea87/headless/lib/browser/protocol/headless_handler.cc#L32).

Only applies if `imageFormat` is `'jpeg'`, otherwise this option is invalid.

### `frameRange`
### `frameRange?`

_number | [number, number] - optional_

Specify a single frame (passing a `number`) or a range of frames (passing a tuple `[number, number]`) to be rendered. By passing `null` (default) all frames of a composition get rendered.

### `muted`
### `muted?`

_boolean - optional - available since v3.2.1_

If set to true, no audio is being rendered.

### `enforceAudioTrack`
### `enforceAudioTrack?`

_boolean - optional - available since v3.2.1_

Render a silent audio track if there wouldn't be any otherwise.

### `puppeteerInstance`
### `puppeteerInstance?`

_puppeteer.Browser - optional_

An already open Puppeteer [`Browser`](https://pptr.dev/#?product=Puppeteer&version=main&show=api-class-browser) instance. Use [`openBrowser()`](/docs/renderer/open-browser) to create a new instance. Reusing a browser across multiple function calls can speed up the rendering process. You are responsible for opening and closing the browser yourself. If you don't specify this option, a new browser will be opened and closed at the end.

### `scale`
### `scale?`

_optional_

Scales the output dimensions by a factor. See [Scaling](/docs/scaling) to learn more about this feature.

### `overwrite`
### `overwrite?`

_boolean - optional_

If set to false, the output file will not be written if a file already exists.

### `onStart`
### `onStart?`

_function_ - optional

Expand All @@ -175,7 +175,7 @@ const onStart = ({ frameCount }: OnStartData) => {
};
```

### `onProgress`
### `onProgress?`

_function - optional_

Expand Down Expand Up @@ -220,7 +220,7 @@ const onProgress: RenderMediaOnProgress = ({
The `progress` attribute is available from v3.2.17
:::

### `onDownload`
### `onDownload?`

_function - optional_

Expand All @@ -243,19 +243,19 @@ const onDownload: RenderMediaOnDownload = (src) => {
};
```

### `proResProfile`
### `proResProfile?`

_string - optional_

Sets a ProRes profile. Only applies to videos rendered with `prores` codec. See [Encoding guide](/docs/encoding/#controlling-quality-using-prores-profile) for possible options.

### `dumpBrowserLogs`
### `dumpBrowserLogs?`

_boolean - optional_

If true, will print browser console output to standard output.

### `onBrowserLog`
### `onBrowserLog?`

_function - optional_

Expand Down Expand Up @@ -284,7 +284,7 @@ _optional, available from v3.0.15_

A token that allows the render to be cancelled. See: [`makeCancelSignal()`](/docs/renderer/make-cancel-signal)

### `verbose`
### `verbose?`

_optional, available from v3.1.6_

Expand Down Expand Up @@ -334,6 +334,38 @@ Accepted values:
**Default for local rendering**: `null`.
**Default for Lambda rendering**: `"swangle"`.

### `ffmpegOverride?`

_function - optional - available from v3.2.22_

Modifies the FFMPEG command that Remotion uses under the hood. It works reducer-style, meaning that you pass a function that takes a command as an argument and returns a new command.

```tsx twoslash
import type { FfmpegOverrideFn } from "@remotion/renderer";

const ffmpegOverride: FfmpegOverrideFn = ({ type, args }) => {
console.log(type); // "stitcher" | "pre-stitcher
return [...args, "-vf", "eq=brightness=0:saturation=1"];
};
```

The function you pass must accept an object as it's only parameter which contains the following properties:

- `type`: Either `"stitcher"` or `"pre-stitcher"`. If enough memory and CPU is available, Remotion may use parallel rendering and encoding, which means that a pre-stitcher process gets spawned before all frames are rendered. You can tell whether parallel encoding is enabled by adding `--log=verbose` to your render command.
- `args`: An array of strings that is passed as arguments to the FFMPEG command.

Your function must return a modified array of strings.

:::warning
Using this feature is discouraged. Before using it, we want to make you aware of some caveats:

- The render command can change with any new Remotion version, even when it is a patch upgrade. This might break your usage of this feature.
- Depending on the selected codec, available CPU and RAM, Remotion may or may not use "parallel encoding" which will result in multiple FFMPEG commands being executed. Your function must be able to handle being called multiple times.
- This feature is not available when using Remotion Lambda.

Before you use this hack, reach out to the Remotion team on [Discord](https://remotion.dev/discord) and ask us if we are open to implement the feature you need in a clean way - we often do implement new features quickly based on users feedback.
:::

## See also

- [Source code for this function](https://github.com/remotion-dev/remotion/blob/main/packages/renderer/src/render-media.ts)
Expand Down