FFmpeg Subtitles Filter: How to Burn SRT Subtitles Into Video

FFmpeg's subtitles filter burns SRT or ASS captions directly into the video pixels. Unlike soft subtitles (which viewers can toggle off), burned-in subtitles are permanent. They show up everywhere: social media players that strip subtitle tracks, messaging apps, and platforms that don't support external caption files.
The basic command is one line, but the filter's syntax for styling, positioning, and encoding has a few traps that waste hours if you don't know about them.
The Basic Command
ffmpeg -i input.mp4 -vf "subtitles=captions.srt" -c:v libx264 -crf 23 -c:a copy output.mp4
FFmpeg reads captions.srt, renders each subtitle at its timestamp, and encodes the result into a new MP4. The -c:a copy flag passes audio through untouched so you don't re-encode it for no reason.
Two things to know up front:
- The
subtitlesfilter requires FFmpeg compiled with libass. If you getNo such filter: 'subtitles', your build doesn't have it. Most package managers include it by default (brew install ffmpegon macOS,apt install ffmpegon Ubuntu), but minimal Docker images often skip it. - The filter reads the SRT file at filter-graph init time. If the file path has spaces or colons, you need to escape them (more on that below).
Styling with force_style
The default appearance (white text, thin black outline) works, but you'll almost always want to customize it. The force_style parameter accepts ASS override tags:
ffmpeg -i input.mp4 \
-vf "subtitles=captions.srt:force_style='FontSize=28,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,Shadow=1'" \
-c:v libx264 -crf 23 -c:a copy output.mp4
force_style Parameter Reference
| Parameter | What it does | Example value |
|---|---|---|
| FontSize | Text size in pixels | `28` |
| FontName | Font family | `Arial` |
| PrimaryColour | Text fill color (ASS hex: `&HAABBGGRR`) | `&H00FFFFFF` (white) |
| OutlineColour | Outline color | `&H00000000` (black) |
| BackColour | Shadow/background color | `&H80000000` (50% black) |
| Outline | Outline thickness in pixels | `2` |
| Shadow | Shadow distance in pixels | `1` |
| BorderStyle | 1 = outline + shadow, 4 = opaque box | `4` |
| Alignment | Position on screen (numpad layout) | `2` (bottom center) |
| MarginV | Vertical margin from the edge | `30` |
| MarginL | Left margin | `20` |
| MarginR | Right margin | `20` |
| Bold | Bold text (1 = on, 0 = off) | `1` |
The color format is tricky. ASS uses &HAABBGGRR, not the #RRGGBB you're used to from CSS. White is &H00FFFFFF. Yellow is &H0000FFFF. Red is &H000000FF. The AA prefix is transparency (00 = fully opaque, FF = fully transparent).
YouTube-Style White on Black Outline
ffmpeg -i input.mp4 \
-vf "subtitles=captions.srt:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,Shadow=0'" \
-c:v libx264 -crf 23 -c:a copy output.mp4
Semi-Transparent Background Box
ffmpeg -i input.mp4 \
-vf "subtitles=captions.srt:force_style='FontSize=22,PrimaryColour=&H00FFFFFF,BackColour=&H80000000,Outline=0,Shadow=4,BorderStyle=4'" \
-c:v libx264 -crf 23 -c:a copy output.mp4
BorderStyle=4 switches from outline mode to opaque-box mode. The Shadow value controls the box padding.
Character Encoding and Escaping
Three escaping rules that catch people off guard:
Colons in file paths. On Windows, paths like C:\Users\me\captions.srt break the filter because : is a parameter separator. Escape them: subtitles=C\:\\Users\\me\\captions.srt.
Single quotes inside force_style. The force_style value is wrapped in single quotes. If your font name contains an apostrophe, escape it with a backslash.
UTF-8 encoding. The SRT file must be UTF-8. If you get garbled characters or blank subtitles, check with file captions.srt. Windows editors sometimes save as UTF-16 or Latin-1. Convert first:
iconv -f UTF-16 -t UTF-8 captions-utf16.srt > captions.srt
SRT vs ASS: Which Format to Use
The subtitles filter handles both SRT and ASS files.
Use SRT when you want uniform styling across all captions and you're controlling the look with force_style. This is 90% of use cases.
Use ASS when you need different styles for different speakers, karaoke-style word highlighting, or per-line positioning. Video editors like Aegisub export ASS natively.
One important detail: force_style overrides the styles in an ASS file header. If you've styled your ASS file in Aegisub, don't also pass force_style or you'll lose that work.
Common Pitfalls
"No such filter: subtitles" means your FFmpeg build doesn't include libass. Reinstall with subtitle support: brew install ffmpeg (macOS), sudo apt install ffmpeg libass-dev (Ubuntu). Building from source? Add --enable-libass to configure.
Timing is off after trimming. If you use -ss (seek) to trim the video, subtitle timestamps don't shift automatically. Put -ss before -i as an input option so the subtitles filter sees the adjusted timeline.
Output file is bigger than the input. Burning subtitles forces a full re-encode. Use -crf 23 or lower for quality parity. Don't use -c:v copy because the filter can't modify copied frames.
Filter graph error on multi-stream files. If the input has multiple video streams, FFmpeg might pick the wrong one. Be explicit with -map 0:v:0 -map 0:a:0.
Text renders at wrong size after scaling. If you're also scaling the video, put subtitles AFTER the scale filter: -vf "scale=1280:720,subtitles=captions.srt". Chain order matters. The filter renders text based on the frame dimensions at that point in the chain.
Burning Subtitles at Scale
Running FFmpeg locally works for a handful of videos. If you're burning subtitles into hundreds of videos a day for social media automation or content repurposing, you need cloud infrastructure.
FFmpeg Micro runs the same subtitles filter on auto-scaling cloud servers. Upload your video, pass the filter options through the API, and download the result. No FFmpeg install, no server management.
The subtitle training page walks through the full API workflow, including auto-generating SRT files from speech using the transcription endpoint.
Get a free API key to try it.
FAQ
Does the subtitles filter work with WebM and MKV output?
Yes. The filter burns text into video frames, so it works with any output container. Use -c:v libvpx-vp9 for WebM or -c:v libx264 for MKV/MP4.
Can I use the subtitles filter with a URL instead of a local file?
No. The subtitles filter only reads local files. Download your SRT first with curl or wget before passing it to the filter.
How do I burn subtitles without re-encoding?
You can't. The filter modifies video frames, which requires a full decode-and-encode cycle. To minimize quality loss, match the original codec and use a CRF value equal to or lower than the source.
What's the difference between the subtitles and ass filters?
Both use libass for rendering. The subtitles filter reads SRT, ASS, and SSA files. The ass filter only reads ASS/SSA but supports more advanced ASS features. For SRT files, use subtitles.
Can I burn two subtitle tracks from different SRT files?
Yes. Chain two filters: -vf "subtitles=english.srt:force_style='Alignment=2',subtitles=spanish.srt:force_style='Alignment=8,MarginV=20'". English renders at the bottom, Spanish at the top.
*Last verified: 2026-05-14 against FFmpeg 7.x and FFmpeg Micro API v1*
About Javid Jamae
Founder & CEO at FFmpeg Micro
Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.
You might also like

How to Add Subtitles to Video with FFmpeg
Learn how to add subtitles and captions to video using FFmpeg CLI and the FFmpeg Micro API. Covers SRT files, styling, text overlays, and automation.

How to Add Text to Video with FFmpeg (CLI and API)
Learn two ways to add text overlays to video: FFmpeg drawtext filter for CLI and FFmpeg Micro @text-overlay API for automation.

How to Trim and Cut Video with FFmpeg (CLI + API Guide)
Learn how to trim and cut video with FFmpeg using -ss, -t, and -to flags. Covers keyframe-accurate cutting, stream copy vs re-encode, and the FFmpeg Micro API.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free