现在我们都玩抖音这些短视频APP,我们看到它里面的视频有些是有字幕或者文字水印的,那这是怎么做到的呢?我们今天就来认识一下FFmpeg中强大的
drawtext
和subtitles
滤镜。
在音视频行业,大多人都知道FFmpeg
,因为基本大多数的视频播放器或者音视频处理都用到了它,但你可能不知道是FFmpeg中还有2大处理文字的利器:drawtext
和subtitles
。
默认情况下,FFmpeg
是不支持drawtext
和subtitles
,因为这个需要借助第三方库才能开启,如下就是开启的第三方库:
第三方库 | 版本 | 下载地址 | 添加版本 | 说明 |
---|---|---|---|---|
fribidi | 1.0.10 | github.com/fribidi/fri... | 1.3.2 | 双向文本处理,drawtext filter依赖 |
freetype | 2.10.2 | mirror.yongbok.net/nongnu/free... | 1.3.2 | 支持多种字体格式,drawtext filter依赖 |
fontconfig | 2.13.92 | www.freedesktop.org/software/fo... | 1.3.2 | 字体配置和渲染,drawtext filter依赖 |
ass | 0.14.0 | github.com/libass/liba... | 1.3.2 | 字幕渲染库,可向视频添加字幕 |
我们在编译FFmpeg
的时候需要将上述第三方库一起编译,然后再在配置中启用如下命令:
bash
./configure \
... # 此处省略其他
# 启用fribidi
--enable-libfribidi \
# 启用fontconfig
--enable-libfontconfig \
# 启用ass
--enable-libass \
# 启用drawtext和subtitles滤镜以及相关的编解码和封装、解封装
--enable-filter=subtitles
--enable-filter=drawtext \
--enable-libfreetype \
--enable-muxer=ass \
--enable-demuxer=ass \
--enable-muxer=srt \
--enable-demuxer=srt \
--enable-muxer=webvtt \
--enable-demuxer=webvtt \
--enable-encoder=ass \
--enable-decoder=ass \
--enable-encoder=srt \
--enable-decoder=srt \
--enable-encoder=webvtt \
--enable-decoder=webvtt \
这样编译出来的FFmpeg
才支持drawtext
和subtitles
绘制文本-drawtext
其实drawtext
就是在视频上绘制文字,那举个简单的例子:
就像上面一样,我在视频上加了一串自己的文案,原理很简单,就是对视频每一帧都给写上✍🏻文字。我们主要看看FFmpeg中使用drawtext的规则:
bash
ffmpeg -y -i input -vf "drawtext=fontfile=${字体路径}/Pingfang.ttf:text=FFmpegCommand:x=(w-text_w)/2:y=(h-text_h)/2:fontsize=100:fontcolor=white" -c:v libx264 output
- -vf 就是启用滤镜,那后面的内容就是滤镜的具体内容
- drawtext 就表示我们要使用
drawtext
这个滤镜 - fontfile 就表示我们的字体路径,如果没有配置fontconfig,那这个就必须传
- text 就是我们要写的文案了
- x、y 表示显示的位置,我这里是显示到屏幕正中间
- fontsize 字体大小,默认16
- fontcolor 字体颜色,颜色是定义在ffmpeg-utils里面的,可参考文档 ffmpeg.org/ffmpeg-util...
那还有其他比较重要的参数:
- box :启用给字体绘制一个背景盒子,默认是0不绘制,1就是绘制box。还可以对盒子添加边框
boxborderw=10
(不让box太靠近文案),boxcolor
就是绘制box的填充颜色(颜色是定义在ffmpeg-utils里面的,可参考文档 ffmpeg.org/ffmpeg-util... )
lua
ffmpeg -y -i input -vf "drawtext=fontfile=${字体路径}/Pingfang.ttf:box=1:boxcolor=black:boxborderw=10:text=FFmpegCommand:x=(w-text_w)/2:y=(h-text_h)/2:fontsize=100:fontcolor=white" -c:v libx264 output
- borderw :给文字添加描边,borderw=3就表示添加3个像素的描边,默认为0。通过
bordercolor
去设置颜色,颜色也是使用 ffmpeg.org/ffmpeg-util... 此处的颜色,看结果
lua
ffmpeg -y -i input -vf "drawtext=fontfile=${字体路径}/Pingfang.ttf:borderw=3:bordercolor=black:text=FFmpegCommand:x=(w-text_w)/2:y=(h-text_h)/2:fontsize=100:fontcolor=white" -c:v libx264 output
- shadowx、shadowy :给文字添加投影,
shadowcoror
可以设置投影的颜色
lua
ffmpeg -y -i input -vf "drawtext=fontfile=${字体路径}/Pingfang.ttf:shadowx=5:shadowy=5:shadowcolor=DimGray:text=FFmpegCommand:x=(w-text_w)/2:y=(h-text_h)/2:fontsize=100:fontcolor=white" -c:v libx264 output
还有很多其他的参数,大家可以去这里 ffmpeg.org/ffmpeg-filt... 查阅
字幕-subtitles
开发过音视频的小伙伴知道,视频的字幕分两种:
- 软字幕:视频里包含了视频轨道、音频轨道、字幕轨道,将字幕放入了字幕轨道里,播放时从中读取,可将字幕进行分离。
- 硬字幕:视频中不含字幕轨道,字幕是刻录在视频画面中的,无法分离字幕。
那字幕的格式一般常使用的就2种格式:
- SRT:提供字幕内容和显示时间
- ASS:提供字幕内容、显示时间以及字体颜色、特效等
SRT
这里我们这里只介绍SRT,对ASS感兴趣的小伙伴可以自行查阅,如下就是SRT字幕内容的格式:
lua
1
00:00:00,120 --> 00:00:01,380
不知道明天会怎样
2
00:00:01,800 --> 00:00:03,360
又或是风雨会来临
就是如此简单,那如果我想设置字幕的颜色和字体大小该怎么办?我这里给大家提供了一份设置字体大小以及特效的文档
ini
01.Name 风格(Style)的名称,区分大小写,不能包含逗号。例如 Default
02.Fontname 使用的字体名称,区分大小写。例如 Arial
03.Fontsize 字体的字号,一般16号就可以
04.PrimaryColour 设置主要颜色, 为蓝-绿-红三色的十六进制代码相排列, BBGGRR. 为字幕填充颜色,例如 &Hffffff
05.SecondaryColour 设置次要颜色, 为蓝-绿-红三色的十六进制代码相排列, BBGGRR. 在卡拉OK效果中由次要颜色变为主要颜色.
06.OutlineColour 设置轮廓颜色, 为蓝-绿-红三色的十六进制代码相排列, BBGGRR.
07.BackColour 设置阴影颜色, 为蓝-绿-红三色的十六进制代码相排列, BBGGRR. ASS的这些字段还包含了alpha通道信息. (AABBGGRR), 注ASS的颜色代码要在前面加上&H
08.Bold -1为粗体, 0为常规
09.Italic -1为斜体, 0为常规
10.Underline [-1 或者 0] 下划线
11.Strikeout [-1 或者 0] 中划线/删除线
12.ScaleX 修改文字的宽度,为百分数,例如 100
13.ScaleY 修改文字的高度,为百分数
14.Spacing 文字间的额外间隙. 为像素数
15.Angle 按Z轴进行旋转的度数, 原点由alignment进行了定义. 可以为小数
16.BorderStyle 1=边框+阴影, 3=纯色背景. 当值为3时, 文字下方为轮廓颜色的背景, 最下方为阴影颜色背景.
17.Outline 当BorderStyle为1时, 该值定义文字轮廓宽度, 为像素数, 常见有0, 1, 2, 3, 4.
18.Shadow 当BorderStyle为1时, 该值定义阴影的深度, 为像素数, 常见有0, 1, 2, 3, 4.
19.Alignment 定义字幕的位置. 字幕在下方时, 1=左对齐, 2=居中, 3=右对齐. 1, 2, 3加上4后字幕出现在屏幕上方. 1, 2, 3加上8后字幕出现在屏幕中间. 例: 11=屏幕中间右对齐. Alignment对于ASS字幕而言, 字幕的位置与小键盘数字对应的位置相同.
20.MarginL 字幕可出现区域与左边缘的距离, 为像素数
21.MarginR 字幕可出现区域与右边缘的距离, 为像素数
22.MarginV 垂直距离
怎么设置字幕特效,大家一目了然,但是有2个点要注意:
- 凡是设置颜色的地方都采用的是BGR格式,而非我们常用的RGB(就是要反正写😏)。
Alignment
字幕位置,- 字幕出现在屏幕下方:1=左对齐, 2=居中, 3=右对齐。
- 字幕出现在屏幕上方:1, 2, 3加上4后. 也就是5=左上,6=顶部居中,7=右上
- 字幕出现在屏幕中间:1, 2, 3加上8后. 也就是9=左侧居中,10=正中,11=右侧居中
css
ffmpeg -y -i input -vf "subtitles=${字体文件位置}:force_style='fontname=苹方 常规,fontsize=40,PrimaryColour=&H000000,OutlineColour=&HF0F0F0,Italic=0,BorderStyle=1,Alignment=2'" -c:v libx264 output
如上就是我设置的字幕显示,每隔一段时间就显示一句(间隔时间请看上面SRT例子中的时间),不会一直固定在这里。在命令中有2个点特别重要:
- 在
force_style
之后的内容都是使用单引号("'")引起来的,不加会报错。 fontname
设置字体时需要进行fontconfig
的配置,而且一定要使用字体名而非文件名,类似下图,字体文件名为PingFang Regular.ttf
,但字体名为苹方 常规
。
配置fontconfig
那如何配置fontconfig
呢?在一般的linux、windows、macOS系统上,它会自动查找查找并获取字体字幕。在Android上不配置就会报错。 其实解决的关键点就是向FontConfig
设置环境变量:
c
extern "C"
JNIEXPORT void JNICALL
Java_com_coder_ffmpeg_jni_FFmpegConfig_00024Companion_setFontConfigPath(JNIEnv *env, jobject thiz,jstring env_value) {
const char *value = env->GetStringUTFChars(env_value,JNI_FALSE);
setenv("FONTCONFIG_PATH", value, 1);
env->ReleaseStringUTFChars(env_value,value);
}
但是请注意,这里设置FontConfigPath
不是字体文件目录哦,而是一个类似于下面这个格式的配置文件:
xml
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<!-- 设置字体目录 -->
<dir>/path/to/your/fonts</dir>
<!-- 添加字体文件匹配规则 -->
<match target="pattern">
<test name="family" qual="any">
<string>YourFontFamilyName</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>YourPreferredFontFamily</string>
</edit>
</match>
</fontconfig>
所以我们在处理的时候,需要自行构建一个这样的文件,然后通过上方setFontConfigPath
将这个配置文件设置到环境变量中。
使用开源库
是不是感觉比较复杂的样子,大家其实也完全不必要自己去写这一部分代码,很多FFmpeg
开源库都自己加了相关内容,你只需要简单接入就行了。 我本身也开源了相关的内容,大家感兴趣也可以去看看【FFmpegCommand】
以上关于在Android上使用FFmpeg的水印文字和字幕的全部内容,咱们评论区见😄