文 / 刘歧 整理 / LiveVideoStack 直播回放: https://www./web/playback/index?classid=18081550127330&session_id=201808160&token=UpmOXagOUwZt681rrJ0J_fi3uef2YslR9xPZowdmKaIVnKE7ZcXWwkkNnUrZm8So4_FWYYdehfAKp0fXMnVKLQ 大家好我是刘歧,目前和几个朋友一起创办了视频云创作平台OnVideo,主要负责做一些新功能预研和整体方向把控。 今天主要从四个方面来介绍一下FFmpeg的滤镜深度应用: 1. Filter基本原理 2. Filter使用方法 3. Filter开发基础 4. Filter开发 一. Filter基本原理 基本原理的理解可以从以下六点出发:
线性处理图解 如上图所示,从滤镜线性处理图中可以看出,对每一个的滤镜处理过程必须要有输入和输出,比如在最后滤镜8的位置没有输出1来承接它的结果,则会报错。另外,如从滤镜1到滤镜2的过程,滤镜1的输出Out可以作为滤镜2的输入In,从滤镜2再往后,滤镜2的输出Out可以分为两部分,分别作为其它滤镜处理的输入。 原始数据处理 滤镜的处理都是基于原始数据来进行的,比如视频图像的每一帧,当然也包括音频。如上图所示,每一帧可以有前后的多个层,一般情况下是两层,当有多层时,如Frame1是三层,则可以先处理前两层,处理之后合并成一层,再跟另一层一起去做处理。当处理完Frame1后送到编码器进行编码,再依次处理Frame2、Frame3、Frame4,处理完后均送到编码器进行压缩编码为另一个格式,比如H.264。 二. Filter使用方法 1. 常用滤镜 常用的滤镜中重点的是:scale、trim、overlay、yadif、rotate、movie 比如常用的scale 可以用来做缩放,trim可以做比较精确的帧级的剪切,overlay可以来实现视频混流,画中画或多画面等叠加处理,rotate来做旋转,movie可以加载第三方的视频等等,yadif可以在摄像机上做隔行扫描,在PC端的播放器可以做去交错。另外,还有delogo、crop、colorkey、chromakey、zoompan; delogo可以用来模糊化某一区域,crop用于图像区域剪切,colorkey和chromakey是用于抠图的,chromakey以YUV输入为主,colorkey以RGB输入为主,zoompan可以将图像放大。 2. 命令行 ffmpeg -filters 通过这一命令,可以列出所有的滤镜,但需要弄清楚每一个滤镜的作用,比如上图的adelay,它的作用是音频转音频,延缓一个或更多的音频通道。在滤镜参数里面还包括timeline support、slice threading、command support,等在后面也会有介绍。 ffmpeg -h filters=rotate 当某个滤镜不知道它里面都有什么参数或者参数怎么用时,那么可以通过上面这条help命令去查看滤镜的内容。比如在上图,查看旋转(rotate)滤镜,可以看出它支持slice threading,而在最下面可以看到还支持timeline操作,并且输入和输出都是Video格式,再下面就是rotate的一些参数,值得注意的是,在FFmpeg里面,尤其滤镜这部分,为了让大家在输入参数时候更简单,它会把很长的参数提供一个简化的名称。 命令行的使用开头都是:filter_complex,然后再在后面接一些字符串,如下: 下面列出几个例子的命令行使用: 1. 跑马灯 [0:v][1:v]overlay=x='if(gte(t,0), -w+(mod(n, W+w))+5, NAN)':y=0[out] 应用场景如新闻播放时画面下方的小栏预告,从右跑到左。 2. 图像旋转 [1:v]rotate=a=60*PI/180:ow=180:oh=180[v1];[0:v][v1]overlay=x=-20:y=-20[o] 3. delogo(模糊化某一区域) delogo=x=72:y=32:w=168:h=86:band=1:show=1 下图为以上三条命令行处理后的展示效果:
在FFmpeg的ffplay里可以通过dumpgraph对滤镜的处理过程增加更深的了解,可以看看下面这个例子: ./ffplay -dumpgraph 1 -f lavfi 'movie=a.flv[l];movie=logo.png[r];[l][r]overlay=x=0:y=0'
在滤镜处理的过程中是先加载第一个电影,然后再加载一张PNG图片,为了叠加处理比较方便会先将它们转换成YUV,再进行叠加运算,最后输出到一个buffersink中。 3. API 滤镜Filter的API结构包括: AVFilterContext:滤镜的上下文 AVFilterInOut:滤镜的输入、输出 AVFilterGraph:滤镜的图结构 AVFilter:滤镜的具体处理类 AVFilterPad:包括输入的Pad和输出的Pad 调用API的分为两个大的步骤: 第一步,滤镜的初始化 初始化部分首先要确定In的Buffer和Out的Buffersink,接下来就是创建一个滤镜的Graph,再就是做一个滤镜的解析,最后就是通用配置。 第二步,滤镜处理 滤镜处理过程是先解码,解码之后将帧加入到Buffer,再调用滤镜处理模块,处理之后输出到Buffersink。 滤镜API的使用方法跟之前命令行的使用方法是一样的,只是略微有一点差别。如果我们不会使用多输入多输出的方式,对于API的使用实际上它的输入也可以用字符串处理的方式,就是命令行里边的处理方式,如以下官方demo的代码: 跑马灯 [0:v][1:v]overlay=x='if(gte(t,0), -w+(mod(n, W+w))+5, NAN)':y=0[out] 图像旋转 [1:v]rotate=a=60*PI/180:ow=180:oh=180[v1];[0:v][v1]overlay=x=-20:y=-20[o]
Delogo(模糊化某一区域) delogo=x=72:y=32:w=168:h=86:band=1:show=1
从上面的介绍可以看出,命令行与API实质上并没有太大的区别。 三. Filter开发基础 1. Module结构 在上面的Module结构里面,可以很清晰的看出步骤流程,先要在滤镜的类里面注册它所对应的所有信息,如滤镜名,上下文等等;下一步就是对Input和Output的处理,对帧的滤镜处理正常都是在一个Input里面处理的; 再就是要看滤镜是否支持Timeline,比如做一些动态的变量,跑马灯之类的,也要有时间线的概念。在这个里面也有一些对应的内置函数,可以把他们理解为一些数字运算的接口。以及下面还有一些变量名的定义。 2. 加入到FFmpeg中 添加滤镜的时候,主要是往下面两个里面添加:
四. Filter开发 在这一部分,为大家做了FFMPEG添加新滤镜的过程的录像,录像地址为http://bbs./add_filter.mp4,有兴趣的同学可以看一下 首先建立了一个zoomscale的滤镜文件,建立完这个文件之后,创建对应的context,然后把刚才讲到的那些接口都写进来,定义zoomscale公共的类,下面我们实现了一个filter _frame,它会把里面的input给释放掉,让它变成一个NULL,此时显示的前景图像就会变成一个纯绿色的图像,如果说这里有process commode,那么就可以在做zmq的时候用,如果没有的话,可以留空。关键是filter_frame,可以当作滤镜处理的一个入口,而get_video_buffer可以把它理解为我们看到的很多demo里面写到的get_video_buffer,即创建一个帧的对应Buffer,将其添加至Makefile之后,继续添加一个avfilter。这是FFmpeg4.0之前的版本,在后面新版本里面,采用的是数组的形式,也就没有列表那么麻烦,速度会更快一些,添加完之后,可以通过config进行查看配置,每次config完之后,会有整体的一个输出。添加完成后,进行编译,之后可以在avfilter库里直接查看滤镜是否已经加到FFmpeg的应用程序里,然后调用API部分,直接把字符串传进来就可以使用了。 Q&A: Q1:直播实时应用滤镜怎么处理? A:只要性能跟的上就可以,比如说通过滤镜里可以添加OpenCV,或者OpenGL的方式。如果原来是直接调用OpenGL,想更加方便,在FFmpeg里进行处理的话,可以把它添加到FFmpeg的滤镜里面,实现对应的OpenGL方法,再调方法即可。 Q2:在FFmpeg里面滤镜处理都是线性的吗? A:介绍是这样的,通过代码的演示可以看到滤镜的处理是一步一步进行的,处理完一帧,再处理下一帧。接口的调用也是如此。
|
|