硬字幕烧进像素里、关不掉、改了要重编;软字幕是独立一条流、能关能改。 mp4 只能装 mov_text,想保留样式得用 mkv。
这是第七章最后一节的前半段:前面做画面,这里往画面上加文字。 字幕之所以要单独讲,是因为它牵扯到「流」与「像素」两种完全不同的存在方式。
一、两种字幕,一线之隔
字幕分成两大类,区别只有一句:文字有没有变成画面的一部分。
类型 存在形式 能不能关 改文字要不要重编码
硬字幕 烧进画面像素里 不能 要 软字幕 独立的字幕流 能 不用
硬字幕的优点是「谁都能看见」——发到任何平台都一样,不用观众去开字幕开关。 缺点是改不了,而且编码一次就定型了。
软字幕的优点是「随时能改、随时能关」,播放器自己渲染。 缺点是有些平台不认,尤其是短视频平台,上传之后字幕就没了。
一句话记:硬字幕是「画」,软字幕是「层」。 「画」改不了,「层」随时能换。
二、两种字幕文件
文件本身也分两种:
格式 扩展名 能写什么
SRT .srt 序号、起止时间、一行文字 ASS/SSA .ass SRT 的全部,加上字体、颜色、位置、动效
SRT 是最通用的:纯文本,几乎什么播放器都认,但样式全靠播放器自己定。 ASS 是「带样式的字幕」,卡拉 OK、双语、花字都靠它。
SRT 的一条长这样:三行一组,序号、时间、文字,中间空一行。
时间格式是 时:分:秒,毫秒,注意毫秒前面是逗号不是点——这里写错是最常见的失败原因。
上次字幕与下次字幕之间一定要空一行,不空行的话播放器会把两条当成一条。 有些播放器宽容,有些直接整条不显示,很难查。
三、软字幕的编码格式
字幕流也是要编码的,容器不同能装的格式不同:
编码 装在哪 特点
mov_text mp4 / mov 最通用,但不支持样式 subrip mkv 就是 SRT,纯文本 ass mkv 样式全保留 webvtt webm 网页播放器原生支持
mp4 装字幕只能用 mov_text,这是容器的限制,不是编码器的限制。
想保留 ASS 的花样,得用 mkv。
mov_text 只有「文字 + 时间」,字体、颜色、位置全丢。
所以「带样式的字幕要发到手机上看」,就只能烧成硬字幕。
四、怎么选
一句话:要给平台看,做硬字幕;要给自己留后路,做软字幕。 给客户交付时常常两份都给——带硬字幕的成片,加带软字幕的工程文件。
还有第三种做法:先做软字幕,最后一步再烧成硬字幕。 这样改字只改字幕文件,不用从头编一遍,返工成本低得多。
具体到这条课件的素材:两秒、160×90、25 帧,字幕带顶多占 18 行高。 算一下就知道,字幕区只占画面的五分之一——所以字幕字号不能太大, 超过一格行高就会盖住内容。
五、动手 Demo:滤镜有没有、SRT 长什么样
下面这段代码先查这个构建里有没有字幕相关滤镜, 再把软字幕常用的四种编码与一条 SRT 打印出来。
import av
print(u"--- 这个构建里有没有字幕相关滤镜")
for nm in (u"subtitles", u"ass", u"drawtext"):
try:
av.filter.Filter(nm)
print(u" %-10s 有" % nm)
except Exception:
print(u" %-10s 没有" % nm)
print(u"--- 能用的字幕流编码(容器决定,不是滤镜)")
for nm in (u"mov_text", u"subrip", u"ass", u"webvtt"):
print(u" %s" % nm)
print(u"--- SRT 的一条长这样")
print(u"1")
print(u"00:00:01,000 --> 00:00:03,000")
print(u"第一句字幕")
实跑输出:
--------------------------------------------------------------------
7.17.1 字幕简介
--------------------------------------------------------------------
**① 两种字幕,一线之隔**
**字幕分成两大类,区别只有一句:文字有没有变成画面的一部分。**
类型 存在形式 能不能关 改文字要不要重编码
-----------------------------------------------------------------
硬字幕 烧进画面像素里 不能 要
软字幕 独立的字幕流 能 不用
**硬字幕的优点是「谁都能看见」——发到任何平台都一样。**
**缺点是改不了,而且编码一次就定型了。**
**软字幕的优点是「随时能改、随时能关」,播放器自己渲染。**
**缺点是有些平台不认,尤其是短视频平台,上传之后字幕就没了。**
**② 两种字幕文件格式**
格式 扩展名 能写什么
-----------------------------------------------------------------
SRT .srt 序号、起止时间、一行文字
ASS/SSA .ass SRT 的全部,加上字体、颜色、位置、动效
**SRT 是最通用的:纯文本,几乎什么播放器都认,但样式全靠播放器自己定。**
**ASS 是「带样式的字幕」,卡拉 OK、双语、花字都靠它。**
**SRT 的一条长这样:三行一组,序号、时间、文字,中间空一行。**
**时间格式是 `时:分:秒,毫秒`,注意毫秒前面是逗号不是点。**
**③ 软字幕的编码格式**
**字幕流也是要编码的,容器不同能装的格式不同:**
编码 装在哪 特点
---------------------------------------------------
mov_text mp4 / mov 最通用,但不支持样式
subrip mkv 就是 SRT,纯文本
ass mkv 样式全保留
webvtt webm 网页播放器原生支持
**mp4 装字幕只能用 `mov_text`,这是容器的限制,不是编码器的限制。**
**想保留 ASS 的花样,得用 mkv。**
**④ 怎么选**
**一句话:要给平台看,做硬字幕;要给自己留后路,做软字幕。**
**给客户交付时常常两份都给——带硬字幕的成片 + 带软字幕的工程文件。**
**还有第三种做法:先做软字幕,最后一步再烧成硬字幕。**
**这样改字只改字幕文件,不用从头编一遍。**
前三行是本节最重要的现实:这台机器上的 PyAV 没有 subtitles、ass、drawtext。
所以「烧字幕」在这里跑不了,下一节会用一个替代办法。
滤镜有没有,取决于 ffmpeg 编译时链了哪些外部库—— libass 管字幕、freetype 管画字,都链上了才有这几个滤镜。
后面几行打印的是「概念」不是「能力」:mov_text、subrip 这些是
字幕编码的名字,能不能用取决于容器,跟滤镜没关系。
30 秒实验
- 查环境:在你自己机器上跑
ffmpeg -filters | grep subtitles,看有没有。 - 写一条 SRT:用记事本写三行,存成
x.srt,注意毫秒前是逗号。 - 换个容器:同一份字幕封装成 mp4 与 mkv,比一比播放器里能不能关。
常见误区
- 把 SRT 时间的毫秒写成点。必须是逗号,写点整条不显示。
- 两条字幕之间不空行。会被当成一条,或者干脆全不显示。
- 以为 mp4 能装 ASS。只能装
mov_text,样式全丢。
自测三问(点开对答案)
1. 硬字幕与软字幕最本质的区别是什么? —— 文字有没有变成画面像素的一部分。 2. mp4 里能装哪种字幕编码? —— `mov_text`,不支持样式。 3. SRT 的时间格式里毫秒前是什么符号? —— 逗号,`00:00:01,000`。- ☐ (本节完,下一节 7.17.2 字幕处理)