DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

一、FFmpeg filter的原理

1. 引言及示例

FFmpeg中的libavfilter提供了一整套的基于filter的机制。

filter本身是一个插件的形式,可以快速的组装需要的效果。

比如下面的filter,可以实现视频的水平镜像效果。

ffplay.exe sample.rmvb -vf hflip

 

1.1 FFmpeg为什么重新定义filter API?

FFmpeg定义的libavcodec接口已经成为在编解码领域的事实上的行业标准。

但音视频filter并没有类似的标准,多个不同的多媒体项目(比如MPlayer、Xine、GStreamer等)都实现了自定义的filter系统。

为了统一filter库API接口,FFmpeg提出了参考DirectDraw实现了高质量、高效、灵活的音视频filter接口。

 

 

1.2 传统概念上filter是什么?

filter可以翻译成过滤器,滤镜、滤波器。物理概念上,常见的过滤器跟净化器概念重复,比如滤水器、空气净化器等。

  • 在计算机程序中,filter是指一段代码,可用于检查输入或者输出,按照预定的规则处理并传递这些数据。

换种说法,filter是一种传递(pass-through)代码块,将输入数据做特定的变换并输出。

通常filter自身不做任何输入/输出。

举个例子,linux下的grep可以认为是一个filter,按照正则表达式匹配选择,从输入中选择输出数据。

  • 在电信工程领域,filter通常指的用于信号处理的设备,

比如音频处理比较典型的低通滤波器、高通滤波器、带通滤波器、去噪滤波器等。

 

1.3 filter的分类

按照处理数据的类型,通常多媒体的filter分为:

  • 音频filter
  • 视频filter
  • 字幕filter

另一种按照处于编解码器的位置划分:

  • prefilters: used before encoding
  • intrafilters: used while encoding (and are thus an integral part of a video codec)
  • postfilters: used after decoding

FFmpeg中filter分为:

  • source filter (只有输出)
  • audio filter
  • video filter
  • Multimedia filter
  • sink filter (只有输入)

除了source和sink filter,其他filter都至少有一个输入、至少一个输出。

 

1.4 示例

下面也是一个例子,使用filter实现宽高减半显示:

ffplay.exe sample.rmvb -vf scale=iw/2:ih/2

 

下面是使用mptestsrc的source filter作为ffplay输入,直接显示:

ffplay -f lavfi mptestsrc=t=dc_luma

ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_color=#00ff00,scale=1200:800:flags=16

 

 

2. 基本原理

FFmpeg filter可以认为是一些预定义的范式,可以实现类似积木的多种功能的自由组合。

每个filter都有固定数目的输入和输出,而且实际使用中不允许有空悬的输入输出端。

使用文本描述时我们可以通过标识符指定输入和输出端口,将不同filter串联起来,构成更复杂的filter。这就形成了嵌套的filter。

当然每个filter可以通过ffmpeg/ffplay命令行实现,但通常filter更方便。

ffmpeg.exe、ffplay.exe能够通过filter处理原始的音视频数据。

ffmpeg将filtergraph分为simple filtergraph和complex filtergraph。

 

通常simple filtergraph只有一个输入和输出,ffmpeg命令行中使用-vf、-af识别,

基本原理图如下:

 

complex filtergraph,通常是具有多个输入输出文件,并有多条执行路径;

ffmpeg命令行中使用-lavfi、-filter_complex,基本原理图如下:

 

在libavfilter, 一个filter可以包含多个输入、多个输出。

下图是一个filtergraph的示例:

上图中filtergraph将输入 流(INPUT) 分成两个流(分别是main 和 tmp ),

其中一个(即tmp)通过crop filter和vflip filter,它们的输出命名为 (flip)

另一个(即main)不做处理;

然后通过overlay filter将这两个流(即 main 和 flip)合成一个流输出(OUTPUT)。

 

这个filtergraph可以用下面命令行表示:

ffmpeg -i INPUT -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT

 

3. Filter的语法

FFmpeg中filter包含三个层次,filter->filterchain->filtergraph。

具体可以参考下图:

 

上图中,

第一层是 filter 的语法;

第二层是 filterchain的语法;

第三层是 filtergraph的语法。

 

3.1 Filter 的语法

[input_link_label_1][input_link_label_2] ...

filter_name=param_name1=param_value1:param_name2=param_value2

[ouput_link_lable_1][output_link_label_2]...

 

其中:

[input_link_label_X] :指以 label 标识的Filter的输入,label可以随意命令,它是可选的,可以有多个,用方括号分隔;

filter_name : 是fliter的名称, 必须有;它的参数是可选 的,以":"分隔或"+"号,可以有参数名,也可以没有;

[output_link_label_X] : 指以 label 标识的Filter的输入,label可以随意命令,它是可选的, 可以有多个,用方括号分隔;

 

没有音频、视频输入的filter称为source filter;

没有音频、视频输出的filter称为sink filter。

 

例如:

ffmpeg -i video.avi

-filter_complex 'extractplanes=y+u+v[y][u][v]' -map '[y]' y.avi -map '[u]' u.avi -map '[v]' v.avi

这个抽取视频Y、U、V分量的filter,就有三个输出,分别是 [y][u][v], 抽取后,将不同的输出保存到不同的文件中;

 

例如:

ffmpeg -i video.avi -vf 'delogo=x=0:y=0:w=100:h=77:band=10' output.avi

 

3.2 filterchain的语法

filter1,filter2,....

它是多个filter的组合,以逗号分隔;并且每个filter是输入是前一个filter的输出;

 

例如:

ffmpeg -i audio.aac

-filter_complex "aresample=async=16000,adelay=316397,volume=1.0" -acodec libfdk_aac -y output.mp4

这里用到了三个filter,分别的aresample, adelay, volume, 组成一个filterchain;

 

 

3.3 filtergraph的语法

filterchain1;filterchain2;...

它是多个filterchain的组合,以分号";"分隔,

 

例如:

ffmpeg -i INPUT -filter_complex "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT

这里用到了三个filterchain, 分别是:

split [main][tmp]; // 它只有一个filter,即 split; 它有一个默认的输入,即INPUT解码后的frame;

有两个输出, 以 [main], [tmp] 标识;

[tmp] crop=iw:ih/2:0:0, vflip [flip] // 它由两个filter组成,即crop和vflip;一个输入 [tmp], 一个输出[flip];

[main][flip] overlay=0:H/2 // 它由一个filter组成,即overlay, 有两输入,分别是[main][flip], 一个默认的输出;

 

 

posted on 2022-02-28 11:01  DoubleLi  阅读(650)  评论(0编辑  收藏  举报