Media tools

ffmpeg filter API: Sume's video filter allowlist and checks

Run allowlisted ffmpeg filters on a Sume-hosted clip with POST /v1/video-filter: the allowed names, filtergraph rules, the free check, and the encode settings.

6 min readSume
All posts

Sume's ffmpeg filter API is POST /v1/video-filter: send one Sume-hosted clip and a filters-only filtergraph string, and the server checks every filter name against an allowlist, wraps the graph with its own input and output, and encodes a new MP4. You never send argv, codecs, or file paths, and POST /v1/video-filter/check validates the same body for free.

The facts below come from the Video filter docs and the Sume API reference, read on 2026-09-26. The docs name Sume's filter compiler as the home of the allowlist; the filter names and encoder settings here are read from it and describe how it works today.

Which ffmpeg filters are allowed?

The allowlist has 66 names in five groups. Each takes only inline options, with no file, font, model, command, or socket option, so nothing on it can read a path or reach a network.

Not on the list: trim and setpts (cut ranges with video trim), drawtext, subtitles, movie, lut3d, and anything that reads a file or a socket. An unknown name fails with invalid_filtergraph (unknown_filter), and the message names the token and lists the allowlist.

From Video filter and the allowlist in Sume's filter compiler, read 2026-09-26.
GroupAllowed filters
Tone and coloreq, lutyuv, lutrgb, lut, hue, colorbalance, colorchannelmixer, colorlevels, colortemperature, colorcontrast, colorcorrect, colorize, colorhold, colorkey, chromakey, chromahold, negate, monochrome, exposure, normalize, histeq, vibrance, swapuv, shuffleplanes, despill, vignette
Blur, sharpen, noiseunsharp, boxblur, gblur, avgblur, smartblur, median, noise, deband, deflicker, dilation, erosion, sobel, edgedetect, cas
Geometrycrop, scale, pad, hflip, vflip, transpose, rotate, setsar, setdar, zoompan, lenscorrection, perspective
Timefps, tpad, fade, framerate, tblend, tmix
Compositing (internal labels only)split, overlay, hstack, vstack, blend, drawbox, drawgrid, format

What does a valid filtergraph look like?

A filtergraph here is filters only. The server supplies the input from video_url as [0:v] and maps the last filter to the encoder, so the graph follows these rules:

  • Start and end with a filter, not a label. Internal labels such as split[a][b] are fine; a stream specifier such as [0:v] is refused.
  • At most 2,048 characters and 32 named filters. The graph runs after any ops[] (up to 8 dim or crop ops).
  • No whitespace inside a filter: write options as name=key=value:key=value.
  • None of ://, a backslash, a backtick, $, a double quote, &, a tab, or a line break.
  • No ffmpeg argv fields in the body: keys such as vf, filter, ffmpeg, cmd, codec, crf, or -i return 400 ffmpeg_fields_rejected.

How do I check a filtergraph before I pay?

Send the same body to POST /v1/video-filter/check, or call video_filter with check_only: true on the hosted MCP server. It runs the encode's schema, allowlist, and source checks without creating a job or reserving credits; Trim, filter, or detach audio covers the rest of its contract. The response has these fields:

  • object: video_filter_check, valid, and encode: "not_run".
  • diagnostics[]: each with severity (error), code, and message, plus optional field, next_action, and details.
  • program: the normalized video_url, ops, filtergraph, filter_count, and filters (compiled names only, no argv), or null when the body itself was rejected.
  • estimate when valid (currency, usd_micros, usd_cents, label), and next_action: submit_video_filter or fix_program_and_recheck.
curl -X POST https://api.sume.com/v1/video-filter/check \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://media.sume.com/artifacts/artf_demo/talk.mp4",
    "filtergraph": "eq=contrast=1.2:saturation=0.8,gblur=sigma=2"
  }'

How does Sume encode the filtered video?

Submit the checked body to POST /v1/video-filter with an Idempotency-Key, then poll the job envelope as for any media tool. The result (kind: video_filter) carries the new video_url and the compiled filters[], and the output keeps the source's geometry, frame rate, and audio unless the program changes them.

The encoder is not configurable. Today it runs with these settings:

  • Video: libx264, preset veryfast, CRF 20, yuv420p, with the keyframe interval set to one second of the source's frame rate when that rate is known.
  • Audio: re-encoded as AAC at 192 kbps, outside the filtergraph, which only sees the video stream. A source with no audio track is still accepted, with a filter_source_has_no_audio warning.
  • Container: MP4 with +faststart.
  • HDR sources (PQ or HLG) are refused with hdr_source_unsupported, and a pixel format outside the YUV family with unsupported_pixel_format.

What are the limits and costs?

Each encode is priced per job, at the rate GET /v1/catalog lists, and the check is free. There is no provider inference, only worker ffmpeg.

Sources

Related posts

Written by Sume