本文 以 ffmpeg4.4 源码为准。
a.mp4下载链接:百度网盘,提取码:nl0s 。logo.jpg 地址:点击查看
命令如下:
ffmpeg.exe -i a.mp4 -i logo.jpg -filter_complex "[1:v]scale=176:144[logo];[0:v][logo]overlay=x=0:y=0" output.mp4 -y
上面命令实现的功能就是 把 “弦外之音” 的 logo 放在视频左上角。
ffmpeg 命令行有两种 filter 用法:
1,-vf
,普通滤镜, 在 《ffmpeg命令分析-vf》有过讲解。
什么是简单滤镜?只有一个输入流是简单滤镜
2,-filter_complex
,-lavfi
这两个命令参数是一样的,这是复杂滤镜,lavfi 是估计是 libavfilter 的缩写。
什么是复杂滤镜?有多个输入流的就是复杂滤镜,本文命令有2个输入流,属于复杂滤镜
复杂滤镜 就是本文的分析重点。
首先 filter_complex 在 ffmpeg_opt.c 的定义如下:
{ "filter_complex", HAS_ARG | OPT_EXPERT, { .func_arg = opt_filter_complex },
"create a complex filtergraph", "graph_description" }
从定义可以看出 filter_complex 会调用 opt_filter_complex 函数。
opt_filter_complex 函数的定义如下:
static int opt_filter_complex(void *optctx, const char *opt, const char *arg)
{
GROW_ARRAY(filtergraphs, nb_filtergraphs);
if (!(filtergraphs[nb_filtergraphs - 1] = av_mallocz(sizeof(*filtergraphs[0]))))
return AVERROR(ENOMEM);
filtergraphs[nb_filtergraphs - 1]->index = nb_filtergraphs - 1;
filtergraphs[nb_filtergraphs - 1]->graph_desc = av_strdup(arg);
if (!filtergraphs[nb_filtergraphs - 1]->graph_desc)
return AVERROR(ENOMEM);
input_stream_potentially_available = 1;
return 0;
}
从上面的代码可以看出, opt_filter_complex 做的事情非常简单,就是 malloc 一个 struct FilterGraph
,然后放进行 全局变量 filtergraphs 里面。
-filter_complex 后面的参数字符串 "[1:v]scale=176:144[logo];[0:v][logo]overlay=x=0:y=0"
就被放进行 graph_desc 进行保存。
ffmpeg 会通过 graph_desc 这个参数判断这个 FilterGraph 是不是一个复杂 FilterGraph ,通过 filtergraph_is_simple()
函数实现。
在之前文章 《ffmpeg源码分析-open_output_file》里,我们知道 init_simple_filtergraph
函数 是在 open_output_file 里面执行的。
init_simple_filtergraph 是初始化 简单filter。init_complex_filters 是初始化 复杂filter,他们之间的调用流程如下: