6、字幕流提取:提取SRT/ASS字幕、处理内嵌字幕与内封字幕的区别
字幕提取,说实话是音视频处理里最容易被低估的环节。很多人觉得不就是把字幕文件拷出来吗?其实坑不少。我最早做视频压制时,就吃过内嵌字幕的亏——折腾半天发现字幕根本提不出来,因为已经"画"进画面里了。
这一章,咱们把字幕提取这件事彻底讲透。你会搞清楚内嵌和内封到底差在哪,以及怎么用FFmpeg把SRT、ASS字幕干净地抽出来。
6.1 先搞懂:内嵌字幕 vs 内封字幕
这两个概念,我见过太多人搞混了。咱们用一句话说清楚:
- 内嵌字幕(硬字幕):字幕已经"烧"进视频画面里了。你看到的每个字,都是图像的一部分。说白了,它不再是字幕数据,而是像素。
- 内封字幕(软字幕):字幕以独立流的形式封装在容器里(比如MKV、MP4)。它还是文本或图形数据,可以随时提取、关闭、切换。
核心区别一句话:内嵌字幕是"画"上去的,提不出来;内封字幕是"包"进去的,可以提取。
为什么会这样?你想想看,内嵌字幕在编码阶段就已经和视频帧合并了。FFmpeg拿到的是已经混合好的像素数据,它没法把"字"和"背景"分开。而内封字幕,本质上和视频流、音频流是平级的——它有自己的流索引。
6.2 怎么判断字幕是内嵌还是内封?
拿到一个视频文件,别急着提取。先看看它到底有没有字幕流。我习惯用这条命令:
ffprobe -v error -show_entries stream=index,codec_name,codec_type:stream_tags=language -of default=noprint_wrappers=1 input.mp4
输出里如果看到 codec_type=subtitle,那就是内封字幕。如果完全没有字幕流,但视频里确实有字幕——嗯,那就是内嵌的,死心吧。
我的小技巧:用 ffprobe -v error -select_streams s -show_entries stream=index,codec_name input.mkv 可以只看字幕流信息,省得被视频音频刷屏。
6.3 提取内封字幕:SRT和ASS
确认有字幕流之后,提取就简单了。但要注意,SRT和ASS的提取方式略有不同。
6.3.1 提取SRT字幕
SRT是最常见的文本字幕格式。提取命令很直接:
ffmpeg -i input.mkv -map 0:s:0 output.srt
这里 -map 0:s:0 的意思是:从第一个输入文件(0)中,取第一个字幕流(s:0)。如果你有多个字幕流,比如中英文各一条,可以这样:
ffmpeg -i input.mkv -map 0:s:0 chinese.srt -map 0:s:1 english.srt
注意:有些MP4文件里的字幕流是"隐藏"的,用 -map 0:s 可能找不到。这时候试试 -map 0:t,因为有些封装器把字幕当附件处理。我曾经被这个坑过,折腾了半小时才发现是封装方式的问题。
6.3.2 提取ASS字幕
ASS字幕比SRT复杂,因为它包含样式信息——字体、颜色、位置、动画等。提取命令和SRT类似:
ffmpeg -i input.mkv -map 0:s:0 output.ass
但有个问题:ASS字幕依赖的字体文件通常不会自动提取。如果你想把字幕和字体一起打包带走,可以这样:
ffmpeg -i input.mkv -map 0:s -map 0:t? -c copy output_with_fonts.mkv
这个命令会把所有字幕流和附件(字体)都复制出来。嗯,这里要注意,0:t? 后面的问号表示"如果有附件就提取,没有也不报错"。
6.4 处理内嵌字幕:真的没办法吗?
说实话,内嵌字幕想完美提取,几乎不可能。但如果你实在需要"提取"它,有两条路可以走:
- OCR识别:把视频帧里的字幕区域截下来,用OCR引擎转成文本。FFmpeg本身不带OCR功能,但可以配合Tesseract使用。
- 重新压制:如果原始字幕文件还在,重新封装一次。这不算提取,但能解决问题。
我曾经在项目里遇到过客户非要提取内嵌字幕的情况。最后用了逐帧截图+Tesseract的方案,准确率大概85%,还得人工校对。说实话,性价比很低。
我的建议:如果字幕是内嵌的,别浪费时间提取。直接找原始字幕文件,或者用语音识别重新生成。内嵌字幕提取,说白了就是"从图像里抠字",技术可行但工程上不划算。
6.5 实战:批量提取字幕流
假设你有一个文件夹,里面全是MKV文件,每个都有中英文字幕。你想批量提取中文SRT。可以写个简单的脚本:
for file in *.mkv; do
ffmpeg -i "$file" -map 0:s:0 "${file%.mkv}.srt"
done
这个脚本假设第一个字幕流(s:0)是中文。如果不确定顺序,先用ffprobe检查一下。
我的习惯:批量操作前,先拿一个文件测试。确认字幕流索引对了,再跑全量。不然几十个文件提取错了,回头改起来很痛苦。
6.6 字幕流提取的常见坑
最后,总结几个我踩过的坑:
- 坑一:字幕流索引搞错。有些视频的字幕流顺序不是按语言排的。用ffprobe看清楚再提取。
- 坑二:编码问题。SRT文件可能是UTF-8、UTF-16甚至GBK编码。提取后如果乱码,加个
-c:s srt或者用iconv转码。 - 坑三:ASS字体缺失。提取的ASS文件如果缺少字体,播放时会用默认字体替代,样式全乱。记得把字体文件也提取出来。
- 坑四:MP4里的字幕。MP4容器对字幕支持不太好,有些播放器根本不认。建议用MKV作为字幕提取的源文件。
特别提醒:如果你提取的字幕用于重新封装,注意时间轴是否匹配。不同版本的视频,帧率、裁剪、速度调整都可能导致字幕不同步。我遇到过提取的字幕比视频快2秒的情况,最后发现是源视频被做过帧率转换。
6.7 本章知识体系
下面这张图,帮你理清字幕提取的核心逻辑:
这张图把字幕提取的决策路径画清楚了。拿到视频文件,先判断是内嵌还是内封。内封的直接提取,内嵌的...嗯,换个思路吧。
字幕提取这件事,说难不难,说简单也不简单。关键是要搞清楚你面对的是什么类型的字幕。内封字幕用FFmpeg几秒钟搞定,内嵌字幕就别白费力气了。我个人建议,做字幕相关工作前,先用ffprobe摸清文件结构,能省下不少时间。
一句话总结:内封字幕用 -map 0:s:0 提取,内嵌字幕放弃治疗。别跟像素过不去。
公众号:蓝海资料掘金营,微信deep3321