FFmpeg Renders Differently on Every Machine

April 12, 2026 · observation

I had my caption pipeline working on my machine. Styled ASS subtitles, proper fonts, nice outlines. Sent the script to a colleague. Completely broken on their end.


The Problem

FFmpeg is not one binary — it's compiled with different flags on different systems. The key one here: libass.

If your FFmpeg has libass, you can do:

ffmpeg -i video.mp4 -vf "ass='captions.ass'" output.mp4

Full styling. Fonts, colors, outlines, fade animations, per-caption positioning. Beautiful.

If it doesn't have libass (common on minimal installs, Docker images, CI runners), that command just fails. No graceful degradation — hard crash.


What I Tried

Attempt 1: Subtitles filter.

ffmpeg -i video.mp4 -vf "subtitles='captions.srt':force_style='...'" output.mp4

More widely available, but limited. You get font, size, color. No animations, no per-caption positioning. The force_style parameter is a single style applied to everything. Better than nothing.

Attempt 2: Drawtext filter.

ffmpeg -i video.mp4 -vf "drawtext=text='Hello':enable='between(t,0,1.5)':fontsize=48:..." output.mp4

Universal — works on literally any FFmpeg build. But painful:
- One filter per caption. A 4-minute video has 80+ captions = 80+ drawtext filters chained.
- FFmpeg has a filter chain length limit. I had to batch them — 20 captions per invocation, re-encoding sequentially. Slow as hell.
- No animations. No fade. Just text appearing and disappearing.


The Fallback Chain

I ended up with a three-level strategy:

  1. Try ASS filter → if it works, you get full styling + animations (~22s for a 4-min video)
  2. If ASS fails, try subtitles filter → limited styling, no animation (~25–30s)
  3. If subtitles fails, fall back to drawtext → universal, ugly, slow (~45–120s depending on caption count)

Detection is just: try the command, check the exit code. If it fails, drop to the next level.


What Annoys Me

This is a solved problem in web development. You feature-detect and degrade gracefully. But in video tooling, everyone assumes you have their exact setup. Every tutorial says "just use the ASS filter" like it's guaranteed to exist.

I'm writing this down because I spent two hours debugging a "works on my machine" issue that turned out to be a compile flag. If you're building anything that shells out to FFmpeg and needs to run on machines you don't control — plan for all three. Don't assume libass.


← back to blog