FFmpeg burn subtitles into video: subtitles filter, force_style
Burn subtitles into a video with FFmpeg's subtitles filter: -vf subtitles=subs.srt re-encodes the picture, and force_style overrides the font and colour.

To burn subtitles into a video with FFmpeg, run the subtitles filter on the picture: ffmpeg -i input.mp4 -vf subtitles=subs.srt -c:a copy output.mp4. The filter draws every line of the .srt into the frames, so the video is re-encoded while -c:a copy keeps the audio as it is. Add force_style to change the font or colour.
The FFmpeg behavior below is quoted from the FFmpeg filters documentation and the ffmpeg documentation, and the Sume facts come from the Video captions and Video filter docs, all read on 2026-09-29. Anything called current behavior is read from Sume's code. Burned-in subtitles can't be turned off by the viewer; hard vs soft subtitles covers that choice.
Why does burning subtitles re-encode the video?
Because the text becomes part of the picture. The ffmpeg docs say that with stream copy, applying filters "is obviously also impossible, since filters work on decoded frames". So -c copy can't be combined with -vf subtitles=… for the video stream. -c:a copy is fine: -c takes a stream specifier, and copy marks a stream as not re-encoded, so only the audio skips the encoder.
- The filter needs an FFmpeg built with
--enable-libass, since it draws through the libass library. - It reads SRT and other text formats by converting them to ASS (Advanced SubStation Alpha). For a file that is already .ass, the
assfilter does the same job. charencsets the input character encoding, which the docs call only useful if the file is not UTF-8.subtitles=video.mkvburns the default subtitle stream of that file, andsubtitles=video.mkv:si=1the second one.
How do I change the font and colour with force_style?
force_style overrides the file's default style with ASS style KEY=VALUE pairs separated by commas. The docs' own example draws sub.srt in 80% transparent blue DejaVu Serif. FFmpeg's escaping notes describe three levels: option values, the filtergraph (where , is special), and the shell. So wrap the style in single quotes inside the filter, and the whole filter in double quotes for the shell.
| Option | What it does |
|---|---|
filename, f | The subtitle file to read; required. The first unnamed value is taken as the filename |
force_style | Overrides default style or script info with ASS KEY=VALUE pairs |
fontsdir | A folder of fonts used in addition to the font provider's |
original_size | The size the ASS file was made for, so fonts scale right after a size change |
charenc | Input character encoding, if not UTF-8 |
stream_index, si | Which subtitle stream to read from a file |
# Plain burn-in: video re-encoded, audio copied
ffmpeg -i input.mp4 -vf subtitles=subs.srt -c:a copy output.mp4
# Font and colour overridden with ASS style fields
ffmpeg -i input.mp4 \
-vf "subtitles=subs.srt:force_style='Fontname=DejaVu Serif,PrimaryColour=&HCCFF0000'" \
-c:a copy output.mp4
# Fonts from your own folder, in addition to the system's
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:fontsdir=./fonts" -c:a copy output.mp4Can I burn subtitles without running FFmpeg myself?
Not with Sume's hosted FFmpeg filter: subtitles and drawtext are not on its allowlist, and neither is anything that reads a file. Sume burns text through its caption job instead, POST /v1/video-captions, which takes a public HTTPS video_url. It takes no .srt upload, so send each SRT block as a cue with text, start, and end in seconds; Sume burns exactly that copy at those times. Burn an SRT file into a video shows the conversion.
- The look comes from a caption
style(such asslamorblack-outline) and optionaldesignoverrides, not from ASS fields, so aforce_stylestring doesn't carry over. - A job takes up to 200 cues. In current code it refuses a source over 60 seconds, and a source with no audio stream even when you send cues.
- Each accepted job reserves and captures $0.20 for videos up to 60 seconds, plus a 5.5% agent fee by default.
- The job returns a captioned
video_urlwhen ready, and raw transcripts are not part of its public contract.
Sources
Related posts
More in Developers
- FFmpeg change frame rate: the fps filter vs -r
Change a video's frame rate with FFmpeg's fps filter: -vf fps=30 drops or duplicates frames and keeps the running time. How -r and framerate differ.
- FFmpeg crop video: crop=w:h:x:y, centre, and 9:16
Crop a video with FFmpeg's crop filter: -vf crop=w:h:x:y keeps a w×h area whose top-left corner is at x,y; leave out x and y to crop the centre.
- FFmpeg fade in fade out: video and audio, from and to black
Fade a video in and out with FFmpeg: fade=t=in and fade=t=out on the picture, afade on the sound, with the fade-out starting at the length minus its duration.
- FFmpeg increase volume: the volume filter, in dB or ×
Increase volume in FFmpeg with -af volume: volume=2 or volume=6dB, with -c:v copy so the video isn't re-encoded. Check headroom with volumedetect first.
Written by Sume