Android直播开发之旅(18):FFmpeg中滤镜(filter)的工作原理

本文介绍了FFmpeg中滤镜的工作原理,包括滤镜、滤镜链和滤镜图的概念,以及简单滤镜和复杂滤镜的使用。通过滤镜API的介绍,展示了如何在代码中配置和使用滤镜,包括创建滤镜图、建立滤镜连接以及发送原始帧到滤镜和读取处理后帧的操作。
摘要由CSDN通过智能技术生成

1. 什么是滤镜

 滤镜(filter)是指将未经过处理的原始音频帧(如PCM)视频帧(如YUV、RGB)经过滤镜器处理后,得到具体“特殊效果”的音频帧或视频帧,比如音频帧被添加回声、视频帧被旋转、缩放、添加水印等等。需要注意的是,滤镜处理的是原始音视频帧数据,输出的仍然是原始数据,因此不会造成数据损伤。FFmpeg的libavfilter库中提供了很多的内置滤镜,我们可以单独使用一个滤镜进行数据处理,也可以将多个滤镜连接起来组合使用,其中一个滤镜的输出可以连接到另一个滤镜的输入,因此滤镜分为简单滤镜复杂滤镜。在FFmpeg中,滤镜模块支持多路输入和多路输出,其提供了两种方式使用滤镜,即命令API,首先我们来看下在命令中定义一个滤镜,语法如下:

[input_link_lable1][input_link_lable2]... filter_name=parameters [output_link_lable1][output_link_lable12]...

 其中,[input_link_lable*]是该滤镜的输入连接符号(link label),可以有多个,表示滤镜的输入;[output_link_lable*]是该滤镜的输出连接符号,可以有多个,表示滤镜的输出;filter_name表示该滤镜的具体名称,如缩放滤镜"scale";parameters表示滤镜参数。

注:如果连接符号没标明,则说明上一个滤镜的输出就是当前滤镜的输入。

1.1 简单滤镜(滤镜链)

 简单滤镜通常是指处理的滤镜中包含一个或多个滤镜,当包含多个滤镜时,每个滤镜以逗号分隔构成一个滤镜序列,这样的滤镜序列被称之为滤镜链(filterchain)。语法如下:

filter1,fiter2,filter3,...,filterN-2,filterN-1,filterN

 需要注意的是,滤镜链中如果有空格,需要将滤镜链用双引号括起来,因为命令行中空格是分隔参数用的。举例如下:

ffmpeg -i src.mp4-vf hqdn3d,pad=2*iw dest.mp4

命令参数说明:

  • -i src.mp4:指定输入音/视频源;

  • -vf:指定简单视频滤镜,“-vf”等同“-filter:v”,

    ​ 如果处理音频,该参数应为"-af",且“-af”等同“-filter:a”;

  • "hqdn3d,pad=2*iw":表示包含两个滤镜的滤镜链,其中"hqdn3d"滤镜用于降噪、"pad=2*iw"滤镜用于将图像的宽度填充到输入宽度的2倍;

  • dest.mp4:输出视频,为输入视频经过降噪、填充宽度后的输出结果。

效果图:

 _______        _____________        _______        ________
|       |      |             |      |       |      |        |
| input | ---> |    hqdn3    | ---> | pad   | ---> | output |
|_______|      |_____________|      |_______|      |________|

1.2 复杂滤镜(滤镜图)

 复杂滤镜通常是指滤镜图(filter graph),用处简单滤镜处理不了的场合。滤镜图(filterchain)由滤镜链(filterchain)序列组成,滤镜链之间用分号分割,整个滤镜图需要用双引号括起来。语法如下:

"filter1;fiter2;filter3;...;filterN-2;filterN-1;filterN"

 根据输入、输出的数量,滤镜图有可分为简单滤镜图(simple filter graph)复杂滤镜图(complex filter graph)。其中,简单滤镜图只能处理单路输入流和输出流,且要求输入和输出具有相同的流类型;而复杂滤镜图支持多路输入流和(或)多路输出流,或者输出流与输入流类型不同的场合,比如overlay滤镜和amix滤镜就是复杂滤镜图。

  • 简单滤镜图
 _______        _____________________        ________
|       |      |                     |      |        |
| input | ---> | simple filter graph | ---> | output |
|_______|      |_____________________|      |________|
  • 复杂滤镜图
_________
|         |
| input 0 |\                    __________
|_________| \                  |          |
             \   _________    /| output 0 |
              \ |         |  / |__________|
 _________     \| complex | /
|         |     |         |/
| input 1 |---->| filter  |\
|_________|     |         | \   __________
               /| graph   |  \ |          |
              / |         |   \| output 1 |
 _________   /  |_________|    |__________|
|         | /
| input 2 |/
|_________|
  • 示例如下:
ffmpeg -i INPUT -lavfi "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT

参数说明:

  • -i:指定输入流;

  • -lavfi:指定复杂滤镜图,"-lavfi"等价于"-filter_complex";2

  • "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2":复杂滤镜图,由三个滤镜链(用分号分割)组成。第一个滤镜链包含一个split滤镜,该滤镜产生两个输出[main]和[tmp];第二个滤镜链包含crop滤镜和vflip滤镜,输入为[tmp],输出为[flip];第三个滤镜链包含一个overlay滤镜,[main] [flip]作为输入。整行命令实现的功能是:**将输入分隔为两路,其中一路经过裁剪和垂直翻转后,再与另一路混合,生成输出文件。**示意图如下所示:

                    [main]
    input --> split ---------------------> overlay --> output
                |                             ^
                |[tmp]                  [flip]|
                +-----> crop --> vflip -------+
    

滤镜、滤镜链、滤镜图区别与联系?

 从广义角度,滤镜指图像处理中的一个功能,通常以滤镜链和滤镜图的形式使用;从狭义角度,滤镜指滤镜链的单个特例。滤镜图由滤镜链序列组成,滤镜链由多个滤镜特例序列组成。一个滤镜图可以只包含一个滤镜链,而一个滤镜链也可以只包含一个滤镜特例,这种特例情况下,一个滤镜图仅有单个滤镜特例构成,即滤镜图=滤镜链=单个滤镜。

2. 滤镜API介绍与使用

2.1 滤镜API介绍

2.1.1 结构体

  • AVFilter:表示一个滤镜器(Filter),位于…/libavfilter/avfilter.h。

 该结构体用于定义一个滤镜,包含滤镜的名称、

typedef struct AVFilter {
   
    // 滤镜器名称,非空且唯一
    const char *name;
    // 滤镜器描述信息,可为NULL
    const char *description;
    // List of inputs, terminated by a zeroed element
    const AVFilterPad *inputs;
    // List of outputs, terminated by a zeroed element.
    const AVFilterPad *outputs;
    const AVClass *priv_class;
	// 前缀为AVFILTER_FLAG_*的标志
    int flags;

    // private API
    ...
} AVFilter;
  • AVFilterContext:表示一个滤镜器(Filter)的实例(instance),位于…/libavfilter/avfilter.h。
struct AVFilterContext {
   
    const AVClass *av_class;      
	// 该实例对应的滤镜器(Filter)
    const AVFilter *filter;        
	// 滤镜器实例名称
    char *name;                    
    AVFilterPad   *input_pads;      ///< array of input pads
    AVFilterLink **inputs;          ///< array of pointers to input links
    unsigned    nb_inputs;          ///< number of input pads

    AVFilterPad   *output_pads;     ///< array of output pads
    AVFilterLink **outputs;         ///< array of pointers to output links
    unsigned    nb_outputs;         ///< number of output pads

    void 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值