← All posts

How to Add Subtitles to Video with FFmpeg

Complete guide to adding subtitles with FFmpeg — hardcode SRT/ASS, softcode subtitle tracks, style customization, multi-language support, and subtitle extraction.

FFHub·2026-04-28
How to Add Subtitles to Video with FFmpeg

Subtitles make videos accessible, searchable, and watchable in noisy environments. FFmpeg can hardcode subtitles directly into the video, embed them as selectable tracks, extract existing subtitles, and convert between subtitle formats. This guide covers all of it with practical commands.

Hardcode vs Softcode: Which to Choose?

Before adding subtitles, you need to decide how:

MethodDescriptionProsCons
Hardcode (burn-in)Subtitles rendered into the video pixelsAlways visible, universal playbackCan't turn off, requires re-encoding
Softcode (embedded)Subtitles stored as a separate trackToggleable, multiple languagesPlayer must support it

Rule of thumb: Hardcode for social media and maximum compatibility. Softcode for long-form content and multi-language support. If you're building a UGC platform that processes user-uploaded videos, softcode is usually the better choice.

Hardcode SRT Subtitles

SRT is the most common subtitle format. To burn it into the video:

# Hardcode SRT subtitles
ffmpeg -i input.mp4 -vf "subtitles=subs.srt" output.mp4

That's it. FFmpeg uses the subtitles filter (powered by libass) to render the SRT file directly onto each frame.

Customize SRT Appearance

The default SRT rendering is plain. You can style it with the force_style option:

# Custom font, size, and color
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontName=Arial,FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2,Shadow=1'" output.mp4

Common style parameters:

ParameterExampleDescription
FontNameArialFont face
FontSize24Size in points
PrimaryColour&H00FFFFFFText color (ABGR hex)
OutlineColour&H00000000Outline color
BackColour&H80000000Shadow/background color
Outline2Outline thickness
Shadow1Shadow depth
Bold1Bold text (0 or 1)
Alignment2Position (2=bottom center)
MarginV30Vertical margin from edge

Note: Colors use ABGR format (Alpha, Blue, Green, Red), not the usual RGB.

# Yellow text with black outline, larger font, positioned higher
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=28,PrimaryColour=&H0000FFFF,OutlineColour=&H00000000,Outline=3,MarginV=40'" output.mp4

Handle Special Characters in File Paths

If your subtitle file path contains special characters, escape them:

# Escape colons in Windows paths or special characters
ffmpeg -i input.mp4 -vf "subtitles='my\ subtitles.srt'" output.mp4

# Or use the subtitle file index approach
ffmpeg -i input.mp4 -i subs.srt -filter_complex "[0:v][1:s]overlay" output.mp4

Hardcode ASS/SSA Styled Subtitles

ASS (Advanced SubStation Alpha) subtitles support rich styling — fonts, colors, animations, and positioning per line. When hardcoding ASS files, all styling is preserved:

# Hardcode ASS subtitles (all styling preserved)
ffmpeg -i input.mp4 -vf "ass=subs.ass" output.mp4

Create a Simple ASS File

Here's an example ASS file structure:

[Script Info]
Title: My Subtitles
ScriptType: v4.00+
PlayResX: 1920
PlayResY: 1080

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default,Arial,48,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,0,0,0,0,100,100,0,0,1,2,1,2,10,10,40,1

[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,Hello, this is a subtitle.
Dialogue: 0,0:00:05.00,0:00:08.00,Default,,0,0,0,,This line has {\b1}bold{\b0} text.

Convert SRT to ASS with Custom Styling

# Convert SRT to ASS (then you can edit the ASS styles)
ffmpeg -i subs.srt subs.ass

After converting, edit the [V4+ Styles] section in the ASS file to customize appearance. You may also want to convert your video to a different format before adding subtitles, depending on your target platform.

Softcode Subtitles (Embedded Tracks)

Softcoded subtitles are stored as a separate stream inside the container. The viewer can toggle them on/off.

Add SRT as a Subtitle Track

# Add SRT subtitle track to MP4
ffmpeg -i input.mp4 -i subs.srt -c copy -c:s mov_text output.mp4

# Add SRT subtitle track to MKV (MKV supports SRT natively)
ffmpeg -i input.mp4 -i subs.srt -c copy -c:s srt output.mkv

Important: MP4 containers require mov_text codec for subtitles. MKV supports SRT, ASS, and many other formats natively.

Add Multiple Subtitle Languages

# Add English and Spanish subtitle tracks to MKV
ffmpeg -i input.mp4 -i english.srt -i spanish.srt \
  -map 0:v -map 0:a -map 1 -map 2 \
  -c copy -c:s srt \
  -metadata:s:s:0 language=eng -metadata:s:s:0 title="English" \
  -metadata:s:s:1 language=spa -metadata:s:s:1 title="Spanish" \
  output.mkv

For MP4:

# Add multiple subtitle tracks to MP4
ffmpeg -i input.mp4 -i english.srt -i chinese.srt \
  -map 0:v -map 0:a -map 1 -map 2 \
  -c copy -c:s mov_text \
  -metadata:s:s:0 language=eng -metadata:s:s:0 title="English" \
  -metadata:s:s:1 language=chi -metadata:s:s:1 title="Chinese" \
  output.mp4

Set Default Subtitle Track

# Mark the first subtitle track as default
ffmpeg -i input.mp4 -i subs.srt \
  -map 0 -map 1 \
  -c copy -c:s mov_text \
  -disposition:s:0 default \
  output.mp4

Add ASS Subtitles as Soft Track

# Add ASS to MKV (preserves all styling for compatible players)
ffmpeg -i input.mp4 -i subs.ass -map 0 -map 1 -c copy -c:s ass output.mkv

Extract Subtitles from Video

Extract to SRT

# Extract the first subtitle track to SRT
ffmpeg -i input.mkv -map 0:s:0 output.srt

# Extract the second subtitle track
ffmpeg -i input.mkv -map 0:s:1 output.srt

Extract to ASS

# Extract subtitle track as ASS (preserves styling)
ffmpeg -i input.mkv -map 0:s:0 output.ass

List Available Subtitle Tracks

# Show all streams including subtitles
ffprobe -v error -show_entries stream=index,codec_name,codec_type -of csv input.mkv

# More detailed subtitle info
ffprobe -v error -select_streams s -show_entries stream=index,codec_name:stream_tags=language,title -of json input.mkv

Extract All Subtitle Tracks

#!/bin/bash
# Extract all subtitle tracks from a video
INPUT="input.mkv"

# Count subtitle streams
COUNT=$(ffprobe -v error -select_streams s -show_entries stream=index -of csv=p=0 "$INPUT" | wc -l)

for i in $(seq 0 $((COUNT - 1))); do
  # Get language tag
  LANG=$(ffprobe -v error -select_streams s:$i -show_entries stream_tags=language -of csv=p=0 "$INPUT")
  LANG=${LANG:-"track$i"}
  ffmpeg -i "$INPUT" -map 0:s:$i "${INPUT%.*}_${LANG}.srt"
done

Convert Subtitle Formats

FFmpeg can convert between subtitle formats:

# SRT to ASS
ffmpeg -i subs.srt subs.ass

# ASS to SRT (loses styling)
ffmpeg -i subs.ass subs.srt

# SRT to WebVTT
ffmpeg -i subs.srt subs.vtt

# SUB/IDX (DVD) to SRT (requires OCR — FFmpeg can't do this directly)
# Use a tool like SubtitleEdit or Tesseract for bitmap-to-text conversion
FromToPreserves Styling?
SRT → ASSYesAdds default styling
ASS → SRTNoLoses all styling
SRT → VTTPartialBasic formatting kept
VTT → SRTPartialLoses VTT-specific features

Subtitle Timing Adjustments

Delay or Advance Subtitles

# Delay subtitles by 2.5 seconds
ffmpeg -i input.mp4 -itsoffset 2.5 -i subs.srt -map 0 -map 1 -c copy -c:s mov_text output.mp4

For hardcoded subtitles, use the setpts filter or adjust the SRT file directly (if you need to trim or merge video segments, timing adjustments become especially important):

# Shift hardcoded subtitles (using subtitle filter with offset)
ffmpeg -i input.mp4 -vf "subtitles=subs.srt" -ss 00:00:02.500 output.mp4

Hardcode Subtitles with Resolution Control

When hardcoding, subtitle rendering quality depends on the video resolution. For best results, match the original resolution:

# Hardcode subtitles while keeping original resolution
ffmpeg -i input.mp4 -vf "subtitles=subs.srt" -c:v libx264 -crf 23 -c:a copy output.mp4

# Hardcode and scale to 1080p
ffmpeg -i input.mp4 -vf "subtitles=subs.srt,scale=-2:1080" -c:v libx264 -crf 23 -c:a copy output.mp4

Subtitle Font Rendering for Different Resolutions

# For 720p video — smaller font
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=20'" -c:v libx264 -crf 23 output.mp4

# For 4K video — larger font
ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=48,Outline=3'" -c:v libx264 -crf 23 output.mp4

Batch Subtitle Operations

Hardcode Subtitles for All Videos

# Assumes each video has a matching .srt file
for f in *.mp4; do
  srt="${f%.mp4}.srt"
  if [ -f "$srt" ]; then
    ffmpeg -i "$f" -vf "subtitles=$srt" -c:v libx264 -crf 23 -c:a copy "subtitled_${f}"
  fi
done

Softcode Subtitles for All Videos

# Add matching SRT files as subtitle tracks
for f in *.mp4; do
  srt="${f%.mp4}.srt"
  if [ -f "$srt" ]; then
    ffmpeg -i "$f" -i "$srt" -c copy -c:s mov_text "soft_${f}"
  fi
done

Troubleshooting

"No such filter: subtitles" — FFmpeg was compiled without libass support. Install a full build:

# macOS
brew install ffmpeg

# Ubuntu/Debian
sudo apt install ffmpeg libass-dev

Subtitles don't appear — Check the subtitle file encoding. FFmpeg expects UTF-8:

# Convert subtitle encoding to UTF-8
iconv -f ISO-8859-1 -t UTF-8 subs_latin.srt > subs_utf8.srt

Wrong subtitle position or size — The video resolution doesn't match the subtitle's assumed resolution. Use force_style to override:

ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontSize=24,MarginV=30'" output.mp4

Special characters display as boxes — The font doesn't support the characters. Specify a font that supports your language:

ffmpeg -i input.mp4 -vf "subtitles=subs.srt:force_style='FontName=Noto Sans CJK SC'" output.mp4

MP4 output fails with "unknown codec" for subtitles — MP4 only supports mov_text. Use MKV for other subtitle formats, or hardcode instead.

Cloud Alternative with FFHub

Hardcoding subtitles requires re-encoding, which is CPU-intensive — a 1-hour video can take 20+ minutes on a standard machine. FFHub runs FFmpeg in the cloud via API, so you can offload subtitle burning to fast cloud servers while your machine stays free.

This is especially useful when you need to generate multiple subtitle versions (different languages, different styles) from the same source video.

Summary

  • Hardcode (-vf "subtitles=subs.srt") for guaranteed visibility on all platforms
  • Softcode (-c:s mov_text for MP4, -c:s srt for MKV) for toggleable tracks
  • Use force_style to customize SRT subtitle appearance
  • Use ASS format when you need rich styling and animations
  • Use -map to add multiple subtitle languages
  • Use ffprobe to inspect existing subtitle tracks before extraction
  • Always ensure subtitle files are UTF-8 encoded

Related Articles

How to Add Subtitles to Video with FFmpeg | FFHub