Android上使用FFmpeg添加文字水印和字幕 - 闭坑指南

现在我们都玩抖音这些短视频APP,我们看到它里面的视频有些是有字幕或者文字水印的,那这是怎么做到的呢?我们今天就来认识一下FFmpeg中强大的drawtextsubtitles滤镜。

在音视频行业,大多人都知道FFmpeg,因为基本大多数的视频播放器或者音视频处理都用到了它,但你可能不知道是FFmpeg中还有2大处理文字的利器:drawtextsubtitles

默认情况下,FFmpeg是不支持drawtextsubtitles,因为这个需要借助第三方库才能开启,如下就是开启的第三方库:

第三方库 版本 下载地址 添加版本 说明
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才支持drawtextsubtitles

绘制文本-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的水印文字和字幕的全部内容,咱们评论区见😄

相关推荐
sweetying2 小时前
30了,人生按部就班
android·程序员
用户2018792831672 小时前
Binder驱动缓冲区的工作机制答疑
android
真夜2 小时前
关于rngh手势与Slider组件手势与事件冲突解决问题记录
android·javascript·app
用户2018792831672 小时前
浅析Binder通信的三种调用方式
android
Java陈序员3 小时前
直播录制神器!一款多平台直播流自动录制客户端!
python·docker·ffmpeg
用户093 小时前
深入了解 Android 16KB内存页面
android·kotlin
火车叼位4 小时前
Android Studio与命令行Gradle表现不一致问题分析
android
前行的小黑炭6 小时前
【Android】 Context使用不当,存在内存泄漏,语言不生效等等
android·kotlin·app
前行的小黑炭7 小时前
【Android】CoordinatorLayout详解;实现一个交互动画的效果(上滑隐藏,下滑出现);附例子
android·kotlin·app
用户20187928316719 小时前
Android黑夜白天模式切换原理分析
android