ffmpegsubtitlescaptionsvideo-processingapi

How to Add Subtitles to Video with FFmpeg

·Javid Jamae·4 min read
How to Add Subtitles to Video with FFmpeg

You need captions on your video. Maybe it's for accessibility, maybe TikTok and Instagram penalize uncaptioned content in their algorithms, or maybe you just want your audience to watch with the sound off. Whatever the reason, you're going to reach for FFmpeg.

And then you'll spend an hour fighting with filter syntax.

Adding Subtitles with FFmpeg CLI

FFmpeg supports two main approaches for burning subtitles into video: the subtitles filter (for SRT/ASS files) and the drawtext filter (for simple text overlays). The subtitles filter is what you want for actual captions.

Assuming you have an SRT file ready, the basic command looks like this:

ffmpeg -i input.mp4 -vf "subtitles=captions.srt" -c:v libx264 -crf 23 -c:a aac output.mp4

That works. But the moment you need to customize font size, color, or positioning, you're writing ASS override tags inside your SRT file or converting to ASS format entirely:

ffmpeg -i input.mp4 -vf "subtitles=captions.srt:force_style='FontSize=24,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,Outline=2'" -c:v libx264 -crf 23 -c:a aac output.mp4

That single line is already hard to read. Add font paths (which differ between Linux, macOS, and Windows), character encoding issues, and the fact that FFmpeg silently fails on malformed SRT files, and you've got a debugging session ahead of you.

If you only need to process a handful of videos on your own machine, the CLI approach is fine. But if you're building a product that captions videos at scale, you don't want this running on your server.

Burning Subtitles via the FFmpeg Micro API

FFmpeg Micro wraps FFmpeg's subtitle capabilities into a REST API. You send your video and subtitle file, specify the filter, and get back a captioned video. No server, no font path issues, no dependency management.

The approach uses the filters field on the /v1/transcodes endpoint. You provide your video and SRT file as inputs, then apply the subtitles filter:

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [
      {"url": "https://storage.example.com/video.mp4"},
      {"url": "https://storage.example.com/captions.srt"}
    ],
    "outputFormat": "mp4",
    "filters": [
      {"filter": "subtitles=captions.srt"}
    ]
  }'

Both files get downloaded and processed together. The subtitles filter references the SRT file by name, and FFmpeg burns the captions directly into the video frames.

You can style the subtitles the same way you would with CLI, using the force_style parameter:

curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [
      {"url": "https://storage.example.com/video.mp4"},
      {"url": "https://storage.example.com/captions.srt"}
    ],
    "outputFormat": "mp4",
    "filters": [
      {"filter": "subtitles=captions.srt:force_style=FontSize=28,PrimaryColour=&H00FFFFFF"}
    ]
  }'

The response gives you a job ID. Poll GET /v1/transcodes/{id} until the status is completed, then grab the output with GET /v1/transcodes/{id}/download.

Simple Text Overlays Without an SRT File

Sometimes you don't need timed captions. You just need a line of text burned into the video, like a watermark, a title card, or a call-to-action. FFmpeg Micro has a virtual option for that.

The @text-overlay option lets you add styled text without writing any FFmpeg filter syntax:

{
  "inputs": [
    {"url": "https://storage.example.com/video.mp4"}
  ],
  "outputFormat": "mp4",
  "options": [
    {
      "option": "@text-overlay",
      "argument": {
        "text": "Subscribe for more tips",
        "style": {
          "position": "bottom-center",
          "fontSize": 48,
          "fontColor": "#FFFFFF",
          "outlineThickness": 2
        }
      }
    }
  ]
}

Behind the scenes, this generates an ASS subtitle file with your text and styling, then applies the subtitles filter. You get clean, anti-aliased text without touching any FFmpeg syntax.

SRT File Format Quick Reference

If you're generating SRT files programmatically (which you probably are if you're reading this), the format is simple:

1
00:00:01,000 --> 00:00:04,000
Welcome to this tutorial.

2
00:00:04,500 --> 00:00:08,000
Today we're covering video captions.

3
00:00:08,500 --> 00:00:12,000
Burned-in subtitles work everywhere.

Each block has a sequence number, a timestamp range with comma-separated milliseconds (not periods), and the text. Blank line between blocks. UTF-8 encoding. That's it.

If you're using a speech-to-text service like Whisper, Deepgram, or AssemblyAI, they can output SRT directly. Pipe that into the FFmpeg Micro API and you've got an automated captioning pipeline.

Automating Captions at Scale

The real value of an API-based approach shows up when you're processing more than a few videos. A typical automation flow:

  1. Video gets uploaded to your app
  2. Speech-to-text service generates an SRT file
  3. Your backend sends both files to FFmpeg Micro's /v1/transcodes endpoint
  4. Poll for completion or use a webhook
  5. Download the captioned video and serve it to your users

You can wire this up with n8n, Make.com, or just a simple script. The point is that you're not managing FFmpeg installations, font dependencies, or scaling infrastructure.

FFmpeg Micro has a free tier, so you can test this entire flow without paying anything. Sign up and grab an API key to try it with your own videos.

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free