惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
GbyAI
GbyAI
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
L
LangChain Blog
B
Blog
阮一峰的网络日志
阮一峰的网络日志
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
M
MIT News - Artificial intelligence
D
Docker
WordPress大学
WordPress大学
J
Java Code Geeks
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
The GitHub Blog
The GitHub Blog
博客园 - 叶小钗
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MongoDB | Blog
MongoDB | Blog
博客园 - Franky

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
FFmpeg Subtitles Filter: How to Burn SRT Subtitles Into V...
Javid Jamae · 2026-05-14 · via DEV Community

Javid Jamae

Originally published at ffmpeg-micro.com

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

Enter fullscreen mode Exit fullscreen mode

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 subtitles filter requires FFmpeg compiled with libass. If you get No such filter: 'subtitles', your build doesn't have it. Most package managers include it by default (brew install ffmpeg on macOS, apt install ffmpeg on 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

Enter fullscreen mode Exit fullscreen mode

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
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).

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 with backslashes.

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. Convert if needed:

iconv -f UTF-16 -t UTF-8 captions-utf16.srt > captions.srt

Enter fullscreen mode Exit fullscreen mode

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).

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.

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.

Text renders at wrong size after scaling. Put subtitles AFTER the scale filter: -vf "scale=1280:720,subtitles=captions.srt". Chain order matters.

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.

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.

Read the full guide with more examples on ffmpeg-micro.com.