Skip to Content
MediaTofu

Run FFmpeg

Run your own FFmpeg command against files you declare.

POST /v1/run takes an FFmpeg command and runs it in a job of its own. If you only need a common task, the tools are simpler.

curl "https://api.mediatofu.com/v1/run?wait=25" \
  -H "Authorization: Bearer $MEDIATOFU_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input_files": { "in": "https://example.com/clip.mov" },
    "output_files": { "out": "small.mp4" },
    "ffmpeg_command": "-i {{in}} -vf scale=1280:-2 -crf 26 {{out}}"
  }'

The response is a job. Each output has a download link.

Request body

FieldTypeRequiredDescription
ffmpeg_commandstringYesThe command, up to 10,000 characters. A leading ffmpeg is optional.
input_filesobjectYesKey to source, where a source is a public URL or a file id. Up to 10. May be empty if the command generates its input with -f lavfi.
output_filesobjectYesKey to output file name. At least 1, up to 10.
webhook_urlstringNoA URL to notify when the job finishes. Paid plans only.

Keys must start with a letter and contain only letters, digits and underscores, up to 32 characters. A key can't be used for both an input and an output.

Output file names must start with a letter or digit, contain only letters, digits, _ and - before the extension (at most 64 characters), and end in an extension of 1 to 8 letters or digits, like out.mp4. Two outputs can't share a name.

Placeholders

Write {{key}} wherever a file name goes. Before running, each placeholder becomes that file's name in the job folder.

  • An input becomes its key plus the extension from its URL or file id: {{in}} for clip.mov becomes in.mov. A source with no extension becomes just the key.
  • An output becomes the file name you declared.
  • Every declared key must appear in the command, and every placeholder must be declared.

-i must be followed by a placeholder, unless it comes right after -f lavfi:

{
  "input_files": {},
  "output_files": { "out": "tone.mp3" },
  "ffmpeg_command": "-f lavfi -i sine=frequency=440:duration=2 {{out}}"
}

How the command is parsed

There is never a shell. The command is split into arguments the way a shell would split words, including single quotes, double quotes and backslash escapes, and each argument goes straight to FFmpeg. Pipes, $VAR, globs and && have no effect. FFmpeg runs with -nostdin -hide_banner -y, so outputs are always overwritten and nothing can prompt for input.

What gets rejected

Your filters, codecs and flags work as usual, as long as the command stays inside the job's own files. These commands are rejected with status 400 before anything runs.

CommandError
-i {{in}} -i other.mp4 {{out}}Every -i must be an {{input}} placeholder, or follow -f lavfi.
-i {{in}} -vf movie=http://example.com/logo.png {{out}}URLs and protocols can't be used inside ffmpeg_command. Declare them in input_files.
-i {{in}} -vf movie=/etc/passwd {{out}}Paths outside the job aren't allowed: movie=/etc/passwd
-i {{in}} -filter_script filters.txt {{out}}The option -filter_script is not allowed.
  • URLs and protocols like http:, file:, concat: or tcp: can't appear inside the command. Declare the file in input_files instead.
  • Paths that are absolute, start with ~, or use .. are rejected, including inside filter arguments.
  • Options that read or write files outside the job are rejected, along with anything written in FFmpeg's -/ file form, like -/filter. The rejected options are:
-filter_script  -filter_complex_script  -attach  -dump_attachment  -report
-vstats  -vstats_file  -passlogfile  -progress  -sdp_file
-protocol_whitelist  -protocol_blacklist  -safe
-init_hw_device  -filter_hw_device

The checks keep commands inside the job and fail early. The real boundary is the job's own container, which has no internet and no secrets.

Other request errors are listed under Errors.

On this page