字幕处理
字幕处理
概述
字幕(Subtitle)是多媒体内容的重要组成部分,FFmpeg 支持多种字幕格式的处理,包括提取、转换、烧录等操作。本章详细介绍字幕的格式、处理方法和最佳实践。
字幕格式概览
常见字幕格式
| 格式 | 扩展名 | 类型 | 说明 |
|---|
| SRT | .srt | 文本 | 最简单的字幕格式 |
| ASS | .ass | 文本 | Advanced SubStation Alpha,支持样式 |
| SSA | .ssa | 文本 | SubStation Alpha,ASS 的前身 |
| WebVTT | .vtt | 文本 | Web 字幕格式 |
| TTXT | .txml | 文本 | Timed Text XML |
| VobSub | .sub/.idx | 位图 | DVD 字幕格式 |
| PGS | .sup | 位图 | Blu-ray 字幕格式 |
| DVB | - | 位图 | 数字电视字幕 |
格式对比
| 格式 | 样式支持 | 定位 | 动画 | 兼容性 |
|---|
| SRT | ❌ | 基本 | ❌ | 极好 |
| ASS | ✅ | 高级 | ✅ | 好 |
| SSA | ✅ | 高级 | ✅ | 好 |
| WebVTT | ✅ | 基本 | ❌ | 好 |
| VobSub | ❌ | 固定 | ❌ | 好 |
| PGS | ❌ | 固定 | ❌ | 好 |
SRT 字幕格式
SRT 格式说明
1
00:00:01,000 --> 00:00:04,000
这是第一行字幕
2
00:00:05,000 --> 00:00:08,000
这是第二行字幕
SRT 操作
# 提取 SRT 字幕
ffmpeg -i input.mkv -map 0:s:0 output.srt
# 添加 SRT 字幕(软字幕)
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:s srt output.mkv
# 转换 SRT 为 ASS
ffmpeg -i subtitle.srt subtitle.ass
ASS/SSA 字幕格式
ASS 格式说明
[Script Info]
Title: Example
ScriptType: v4.00+
[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,20,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,2,2,10,10,10,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,,这是第一行字幕
Dialogue: 0,0:00:05.00,0:00:08.00,Default,,0,0,0,,这是第二行字幕
ASS 操作
# 提取 ASS 字幕
ffmpeg -i input.mkv -map 0:s:0 output.ass
# 添加 ASS 字幕(软字幕)
ffmpeg -i input.mp4 -i subtitle.ass -c copy -c:s ass output.mkv
# 转换 ASS 为 SRT
ffmpeg -i subtitle.ass subtitle.srt
ASS 样式定制
# 创建自定义 ASS 字幕
cat > custom.ass << 'EOF'
[Script Info]
Title: Custom Subtitle
ScriptType: v4.00+
[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,Microsoft YaHei,24,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,-1,0,0,0,100,100,0,0,1,3,1,2,10,10,30,1
Style: Title,Microsoft YaHei,36,&H0000FFFF,&H000000FF,&H00000000,&H80000000,-1,0,0,0,100,100,0,0,1,4,2,8,10,10,30,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,,这是默认样式的字幕
Dialogue: 0,0:00:05.00,0:00:08.00,Title,,0,0,0,,这是标题样式的字幕
EOF
WebVTT 字幕格式
WebVTT 格式说明
WEBVTT
1
00:00:01.000 --> 00:00:04.000
这是第一行字幕
2
00:00:05.000 --> 00:00:08.000
这是第二行字幕
WebVTT 操作
# 提取 WebVTT 字幕
ffmpeg -i input.mp4 -map 0:s:0 output.vtt
# 添加 WebVTT 字幕
ffmpeg -i input.mp4 -i subtitle.vtt -c copy -c:s webvtt output.mp4
# 转换 SRT 为 WebVTT
ffmpeg -i subtitle.srt subtitle.vtt
软字幕与硬字幕
软字幕(Soft Subtitle)
软字幕作为独立的字幕流存储在容器中,可以被播放器选择显示或隐藏。
# 添加软字幕(MKV 容器)
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:s srt output.mkv
# 添加软字幕(MP4 容器)
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:s mov_text output.mp4
# 添加多个软字幕
ffmpeg -i input.mp4 -i sub_cn.srt -i sub_en.srt \
-map 0 -map 1 -map 2 \
-c copy -c:s srt \
-metadata:s:s:0 language=chi \
-metadata:s:s:1 language=eng \
output.mkv
# 设置默认字幕
ffmpeg -i input.mp4 -i subtitle.srt \
-map 0 -map 1 \
-c copy -c:s srt \
-disposition:s:0 default \
output.mkv
硬字幕(Hard Subtitle)
硬字幕被直接烧录到视频画面中,无法关闭。
# SRT 硬字幕
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt" output.mp4
# ASS 硬字幕
ffmpeg -i input.mp4 -vf "ass=subtitle.ass" output.mp4
# 指定字幕编码
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='FontName=Microsoft YaHei,FontSize=24'" output.mp4
# 使用 MKV 内置字幕
ffmpeg -i input.mkv -vf "subtitles=input.mkv:si=0" output.mp4
软字幕 vs 硬字幕
| 方面 | 软字幕 | 硬字幕 |
|---|
| 可关闭 | ✅ | ❌ |
| 可切换 | ✅ | ❌ |
| 文件大小 | 小 | 不影响 |
| 画质影响 | 无 | 有(轻微) |
| 兼容性 | 依赖播放器 | 极好 |
| 编辑 | 容易 | 需要重新编码 |
| 适用场景 | 多语言、收藏 | 兼容性需求 |
字幕提取
提取文本字幕
# 提取 SRT 字幕
ffmpeg -i input.mkv -map 0:s:0 output.srt
# 提取 ASS 字幕
ffmpeg -i input.mkv -map 0:s:0 output.ass
# 提取所有字幕
ffmpeg -i input.mkv -map 0:s output_%d.srt
# 提取特定语言字幕
ffmpeg -i input.mkv -map 0:s:m:language:chi output_cn.srt
提取位图字幕
# 提取 VobSub 字幕
ffmpeg -i input.mkv -map 0:s:0 output.sub
# 提取 PGS 字幕
ffmpeg -i input.mkv -map 0:s:0 output.sup
# 转换位图字幕为文本(需要 OCR)
# 使用 SubtitleEdit 或其他 OCR 工具
查看字幕信息
# 查看字幕流信息
ffprobe -v quiet -show_streams -select_streams s input.mkv
# 查看字幕格式
ffprobe -v quiet -show_entries stream=codec_name,codec_type -select_streams s input.mkv
# 列出所有字幕流
ffprobe -v quiet -show_entries stream=index,codec_name,codec_type -select_streams s input.mkv
字幕烧录
基本烧录
# 烧录 SRT 字幕
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt" -c:v libx264 -crf 23 -c:a copy output.mp4
# 烧录 ASS 字幕
ffmpeg -i input.mp4 -vf "ass=subtitle.ass" -c:v libx264 -crf 23 -c:a copy output.mp4
# 烧录容器内字幕
ffmpeg -i input.mkv -vf "subtitles=input.mkv:si=0" -c:v libx264 -crf 23 -c:a copy output.mp4
字幕样式定制
# 自定义字体
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='FontName=Microsoft YaHei'" output.mp4
# 自定义大小
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='FontSize=24'" output.mp4
# 自定义颜色
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='PrimaryColour=&H00FFFFFF'" output.mp4
# 自定义边框
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='Outline=3,Shadow=1'" output.mp4
# 自定义位置
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:force_style='Alignment=2,MarginV=30'" output.mp4
ASS 样式参数
| 参数 | 说明 | 示例值 |
|---|
| FontName | 字体名称 | Microsoft YaHei |
| FontSize | 字体大小 | 24 |
| PrimaryColour | 主颜色 | &H00FFFFFF |
| SecondaryColour | 次颜色 | &H000000FF |
| OutlineColour | 边框颜色 | &H00000000 |
| BackColour | 背景颜色 | &H80000000 |
| Bold | 粗体 | -1/0 |
| Italic | 斜体 | -1/0 |
| Underline | 下划线 | -1/0 |
| StrikeOut | 删除线 | -1/0 |
| ScaleX | 水平缩放 | 100 |
| ScaleY | 垂直缩放 | 100 |
| Spacing | 字间距 | 0 |
| Angle | 旋转角度 | 0 |
| BorderStyle | 边框样式 | 1/3 |
| Outline | 边框宽度 | 2 |
| Shadow | 阴影 | 1 |
| Alignment | 对齐方式 | 1-9 |
| MarginL | 左边距 | 10 |
| MarginR | 右边距 | 10 |
| MarginV | 垂直边距 | 30 |
对齐方式
| 值 | 位置 |
|---|
| 1 | 左下 |
| 2 | 中下 |
| 3 | 右下 |
| 4 | 左中 |
| 5 | 居中 |
| 6 | 右中 |
| 7 | 左上 |
| 8 | 中上 |
| 9 | 右上 |
颜色格式
ASS 颜色格式为 &HAABBGGRR(十六进制):
- AA:透明度(00=不透明,FF=完全透明)
- BB:蓝色
- GG:绿色
- RR:红色
# 白色(不透明)
PrimaryColour=&H00FFFFFF
# 红色(不透明)
PrimaryColour=&H000000FF
# 半透明白色
PrimaryColour=&H80FFFFFF
字幕滤镜
subtitles 滤镜
# 基本使用
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt" output.mp4
# 指定字符编码
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:charenc=UTF-8" output.mp4
# 使用原始时间戳
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt:original_size=1920x1080" output.mp4
# 指定流索引
ffmpeg -i input.mkv -vf "subtitles=input.mkv:si=1" output.mp4
ass 滤镜
# 基本使用
ffmpeg -i input.mp4 -vf "ass=subtitle.ass" output.mp4
# 指定字体目录
ffmpeg -i input.mp4 -vf "ass=subtitle.ass:fontsdir=/usr/share/fonts" output.mp4
drawtext 滤镜
# 基本文字
ffmpeg -i input.mp4 -vf "drawtext=text='Hello':x=10:y=10:fontsize=24:fontcolor=white" output.mp4
# 使用字幕文件
ffmpeg -i input.mp4 -vf "drawtext=file=subtitle.txt:fontsize=24:fontcolor=white:x=(w-tw)/2:y=h-50" output.mp4
# 带背景的文字
ffmpeg -i input.mp4 -vf "drawtext=text='Subtitle':fontsize=24:fontcolor=white:box=1:[email protected]:boxborderw=5:x=(w-tw)/2:y=h-50" output.mp4
字幕转换
格式转换
# SRT 转 ASS
ffmpeg -i subtitle.srt subtitle.ass
# ASS 转 SRT
ffmpeg -i subtitle.ass subtitle.srt
# SRT 转 WebVTT
ffmpeg -i subtitle.srt subtitle.vtt
# WebVTT 转 SRT
ffmpeg -i subtitle.vtt subtitle.srt
字幕编码转换
# GBK 转 UTF-8
ffmpeg -i subtitle_gbk.srt -sub_charenc GBK subtitle_utf8.srt
# 指定输入编码
ffmpeg -charenc GBK -i subtitle.srt subtitle_utf8.srt
多字幕处理
添加多语言字幕
# 添加中文和英文字幕
ffmpeg -i input.mp4 -i sub_cn.srt -i sub_en.srt \
-map 0:v -map 0:a -map 1 -map 2 \
-c:v copy -c:a copy -c:s srt \
-metadata:s:s:0 language=chi \
-metadata:s:s:1 language=eng \
-disposition:s:0 default \
output.mkv
字幕合并
# 合并多个字幕文件
cat sub1.srt sub2.srt > combined.srt
# 使用 FFmpeg 合并(需要重新编号)
ffmpeg -i sub1.srt -i sub2.srt -filter_complex \
"[0:s][1:s]concat=n=2:v=0:a=0:ts=first" \
output.srt
字幕分离
# 提取所有字幕
ffmpeg -i input.mkv -map 0:s:0 sub1.srt -map 0:s:1 sub2.srt
# 提取特定字幕
ffmpeg -i input.mkv -map 0:s:0 output.srt
字幕时间调整
时间偏移
# 使用 ffprobe 查看字幕时间
ffprobe -v quiet -show_entries stream=start_time -select_streams s:0 input.mkv
# 调整字幕时间(使用外部工具)
# 使用 SubtitleEdit 或其他工具调整
字幕同步
# 提取字幕
ffmpeg -i input.mkv -map 0:s:0 subtitle.srt
# 编辑字幕时间(使用 sed 或其他工具)
# 重新添加字幕
ffmpeg -i input.mkv -i subtitle_fixed.srt -c copy -c:s srt output.mkv
字幕嵌入
嵌入到不同容器
# 嵌入到 MKV(支持所有格式)
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:s srt output.mkv
# 嵌入到 MP4(需要 mov_text)
ffmpeg -i input.mp4 -i subtitle.srt -c copy -c:s mov_text output.mp4
# 嵌入到 WebM(需要 WebVTT)
ffmpeg -i input.mp4 -i subtitle.vtt -c copy -c:s webvtt output.webm
容器格式与字幕兼容性
| 容器 | SRT | ASS | WebVTT | VobSub | PGS |
|---|
| MKV | ✅ | ✅ | ✅ | ✅ | ✅ |
| MP4 | ❌ | ❌ | ✅ | ❌ | ❌ |
| WebM | ❌ | ❌ | ✅ | ❌ | ❌ |
| AVI | ❌ | ❌ | ❌ | ❌ | ❌ |
字幕特效
ASS 特效标签
# 创建带特效的 ASS 字幕
cat > effects.ass << 'EOF'
[Script Info]
Title: Effects Example
ScriptType: v4.00+
[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,24,&H00FFFFFF,&H000000FF,&H00000000,&H80000000,0,0,0,0,100,100,0,0,1,2,1,2,10,10,30,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,,{\fad(500,500)}这是淡入淡出的字幕
Dialogue: 0,0:00:05.00,0:00:08.00,Default,,0,0,0,,{\move(100,100,300,300)}这是移动的字幕
Dialogue: 0,0:00:09.00,0:00:12.00,Default,,0,0,0,,{\fs32\c&H0000FF&}这是改变大小和颜色的字幕
EOF
常用 ASS 特效
| 标签 | 说明 | 示例 |
|---|
| \fad(in,out) | 淡入淡出 | \fad(500,500) |
| \move(x1,y1,x2,y2) | 移动 | \move(100,100,300,300) |
| \pos(x,y) | 位置 | \pos(200,200) |
| \fs(size) | 字体大小 | \fs32 |
| \c&HBBGGRR& | 颜色 | \c&H0000FF& |
| \alpha&HAA& | 透明度 | \alpha&H80& |
| \b(weight) | 粗体 | \b1 |
| \i(1/0) | 斜体 | \i1 |
| \u(1/0) | 下划线 | \u1 |
| \s(1/0) | 删除线 | \s1 |
| \bord(width) | 边框宽度 | \bord3 |
| \shad(depth) | 阴影深度 | \shad2 |
| \an(alignment) | 对齐 | \an8 |
| \k(duration) | 卡拉 OK | \k50 |
批量字幕处理
批量提取字幕
#!/bin/bash
# batch_extract_subtitles.sh
INPUT_DIR=${1:-.}
OUTPUT_DIR=${2:-subtitles}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mkv; do
filename=$(basename "$file" .mkv)
# 提取所有字幕流
stream_index=0
while true; do
subtitle=$(ffmpeg -i "$file" -map 0:s:$stream_index -c:s srt -f srt - 2>/dev/null)
if [ -z "$subtitle" ]; then
break
fi
echo "$subtitle" > "$OUTPUT_DIR/${filename}_sub${stream_index}.srt"
echo "提取: ${filename}_sub${stream_index}.srt"
stream_index=$((stream_index + 1))
done
done
echo "字幕提取完成"
批量烧录字幕
#!/bin/bash
# batch_burn_subtitles.sh
INPUT_DIR=${1:-.}
SUBTITLE_DIR=${2:-subtitles}
OUTPUT_DIR=${3:-output}
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.mp4; do
filename=$(basename "$file" .mp4)
subtitle="$SUBTITLE_DIR/${filename}.srt"
if [ -f "$subtitle" ]; then
echo "烧录: $filename"
ffmpeg -y -i "$file" -vf "subtitles=$subtitle" \
-c:v libx264 -crf 23 -c:a copy \
"$OUTPUT_DIR/$filename.mp4"
else
echo "未找到字幕: $filename"
fi
done
echo "批量烧录完成"
字幕工具推荐
命令行工具
| 工具 | 说明 | 平台 |
|---|
| SubtitleEdit | 字幕编辑器 | 跨平台 |
| Aegisub | ASS 字幕编辑器 | 跨平台 |
| srt | SRT 处理工具 | 跨平台 |
| ffmpeg | 字幕处理 | 跨平台 |
Python 库
| 库 | 说明 |
|---|
| pysrt | SRT 处理库 |
| ass | ASS 处理库 |
| srt | SRT 处理库 |
| webvtt-py | WebVTT 处理库 |
注意事项
- 编码问题:字幕文件可能使用不同编码,注意转换为 UTF-8
- 格式兼容:不同容器对字幕格式的支持不同
- 字体依赖:ASS 字幕可能依赖特定字体,确保字体可用
- 时间同步:字幕时间需要与视频同步
- 画质影响:硬字幕会重新编码视频,可能影响画质
业务场景
场景 1:多语言视频制作
# 添加中英文字幕
ffmpeg -i input.mp4 -i sub_cn.srt -i sub_en.srt \
-map 0:v -map 0:a -map 1 -map 2 \
-c:v copy -c:a copy -c:s srt \
-metadata:s:s:0 language=chi \
-metadata:s:s:1 language=eng \
-disposition:s:0 default \
output.mkv
场景 2:视频翻译
# 提取原字幕
ffmpeg -i input.mkv -map 0:s:0 original.srt
# 翻译字幕(使用翻译工具)
# 添加翻译字幕
ffmpeg -i input.mkv -i translated.srt \
-map 0 -map 1 \
-c copy -c:s srt \
-metadata:s:s:1 language=chi \
output.mkv
场景 3:字幕烧录分享
# 烧录字幕并压缩
ffmpeg -i input.mkv -vf "subtitles=input.mkv:si=0:force_style='FontSize=20,PrimaryColour=&H00FFFFFF'" \
-c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k \
output.mp4
扩展阅读
- ASS 字幕规范
- SRT 格式规范
- WebVTT 规范
- FFmpeg 字幕滤镜
- FFmpeg 字幕选项
总结
本章介绍了 FFmpeg 的字幕处理功能,包括:
- 字幕格式概览
- 软字幕与硬字幕
- 字幕提取与烧录
- 字幕样式定制
- 多字幕处理
掌握字幕处理技术可以帮助您制作多语言视频、翻译字幕和分享视频内容。