[ffmpeg] ffmpeg filter模型介绍及开发指南
文章目录
FFmpeg filter简介
libavfilter是ffmpeg基本库之一,定义了许多音视频滤镜处理的功能,例如视频缩放、截取、翻转、叠加等功能。
这些filer都在avfilter库中实现,常用的一些filter如:
scale:视频/图像的缩放
overlay:视频/图像的叠加
rotate:以任意角度旋转视频
举个官方栗子:
在libavfilter中,一个滤镜可以有多个输入和多个输出。为了尽可能介绍清楚,我们假定有下面的滤镜链图。
在这个滤镜链图中,利用split滤镜把输入流分离成了两路流,其中一路通过crop滤镜和vfilp滤镜的同一路级联应用,再同另外一路一起通过overlay滤镜处理的流合成进行输出。则可以采用如下的命令行实现:
ffmpeg -i INPUT -vf “split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2” OUTPUT
这样最终输出将是视频上部是原始,下部是上部的镜像。(倒影效果)
滤镜链图介绍
ffmpeg的滤镜能实现很多花里胡哨的效果,这几乎得意它的滤镜链图。
一张滤镜链图由如下组件组成:
滤镜链图(filtergraph)
滤镜链(filterchain)
滤镜垫(filterpad)
滤镜(filter)
1、基本滤镜
首先最基本一个滤镜应该包括这些:
基本滤镜(filter)
当然有些滤镜没有输入, 例如输出源类的滤镜 color-src
、nullsrc
等
2、 滤镜链
多个基本滤镜输入输出link起来就成了一条滤镜链:
3、滤镜链图
对于一些复杂的滤镜,通常会有多个输入输出,进行一些音视频合成类,这时候就需要定义一张滤镜链图
一个滤镜链图(filtergraph)是连接滤镜的有向图。它可以包含循环动作,也可以在多个滤镜间形成链路,每个链接都有一个连接到滤镜的输入和一个连接到滤镜的输出。
滤镜链图中的每个滤镜都是一个滤镜注册类应用程序的实例,它定义了滤镜的功能、输入接口和输出接口。
如果滤镜没有输入端(接口),则被称作“源”,如果滤镜没有输出端则被称作“槽”
开发API
当然啦,开发的时候不需要你写一整套滤镜链图出来,ffmpeg的api会提供接口给我们使用,只需要提供一串描述滤镜链图的字符串即可,ffmpeg会解析字符串并生成这张滤镜链图。
主要用了这么几个结构体:
AVFilter
AVFilterContext
AVFilterLink
AVFilterPad
AVFilterGraph
AVFilterInOut
当然上下文是这几个里面最重要的结构体啦,代表着一个filter实例,pad、link、graph则分别起着前面所描述的作用效果。
主要API
AvfilterGraphAlloc
分配一张graph空间
AvfilterGraphCreateFilter
在一张已存在的链图中创建一个filter的实例,主要用于创建buffersrc filter和buffersink filter,其他filter会在AvfilterGraphParse2后自动创建好,我们主需要配置好链图的输入源和输出槽,并link到graph的输入输出垫(pad)上。
AvFilterInOut
这是一条filter的连接链关于输入输出的,与前面图述的filter不是一个东西哦。在解析完用户描述滤波图的字符串后该链就会代表着一条输入/输出链。
AvfilterInoutAlloc
分配AvFilterInOut空间
AvfilterGetByName
通过名字获取一个filter实例
AvfilterGraphParse2
parser用户链图描述字符串
AvfilterLink
链接前后两个Pad
AvfilterGraphConfig
最后用于检查链图是否配置正确的
AvfilterGraphDump
dump链图,会画出链图
类似如下 :
示例
这是一张简单的滤波链图的配置过程,go写的,希望对你有帮助 :
其中[]args 和descrition是输入参数 ,分别表示对输入源的描述和链图描述字符串。
graph := avfilter.AvfilterGraphAlloc()
if graph == nil {
log.Fatal("AvfilterGraphAlloc Failed.")
return nil
}
/*frame := avutil.AvFrameAlloc()
if frame == nil {
log.Fatal("AvFrameAlloc failed.")
}*/
inputs := avfilter.AvfilterInoutAlloc()
outputs := avfilter.AvfilterInoutAlloc()
if inputs == nil || outputs == nil {
log.Fatal("AvfilterInoutAlloc Failed.")
return nil
}
defer avfilter.AvfilterInoutFree(inputs)
defer avfilter.AvfilterInoutFree(outputs)
var buffersrc *avfilter.Filter
var buffersink *avfilter.Filter
if description.AudioFilter {
buffersrc = avfilter.AvfilterGetByName("abuffer")
buffersink = avfilter.AvfilterGetByName("abuffersink")
} else {
buffersrc = avfilter.AvfilterGetByName("buffer")
buffersink = avfilter.AvfilterGetByName("buffersink")
}
if buffersink == nil || buffersrc == nil {
log.Fatal("AvfilterGetByName Failed.")
return nil
}
ret := graph.AvfilterGraphParse2(description.Description, &inputs, &outputs)
if ret < 0 {
log.Fatal("AvfilterInoutAlloc Failed des : ", avutil.ErrorFromCode(ret))
return nil
}
var ins []*avfilter.Context
var outs []*avfilter.Context
var frames []*avutil.Frame
// inputs
index := 0
for cur := inputs; cur != nil; cur = cur.Next() {
//log.Debug("index :", index)
var in *avfilter.Context
//var args = "video_size=1280x720:pix_fmt=0:time_base=1/30:pixel_aspect=1/1"
inName := "in" + strconv.Itoa(index)
ret = avfilter.AvfilterGraphCreateFilter(&in, buffersrc, inName, args[i], 0, graph)
if ret < 0 {
log.Fatal("AvfilterGraphCreateFilter Failed des : ", avutil.ErrorFromCode(ret))
return nil
}
ins = append(ins, in)
ret = avfilter.AvfilterLink(ins[index], 0, cur.FilterContext(), cur.PadIdx())
if ret < 0 {
log.Fatal("AvfilterLink Failed des : ", avutil.ErrorFromCode(ret))
return nil
}
index++
}
// outputs
index = 0
for cur := outputs; cur != nil; cur = cur.Next() {
var out *avfilter.Context
outName := "out" + strconv.Itoa(index)
ret = avfilter.AvfilterGraphCreateFilter(&out, buffersink, outName, "", 0, graph)
if ret < 0 {
log.Fatal("AvfilterGraphCreateFilter Failed des : ", avutil.ErrorFromCode(ret))
return nil
}
outs = append(outs, out)
ret = avfilter.AvfilterLink(cur.FilterContext(), cur.PadIdx(), outs[index], 0)
if ret < 0 {
log.Fatal("AvfilterLink Failed des : ", avutil.ErrorFromCode(ret))
return nil
}
index++
}
ret = graph.AvfilterGraphConfig(0)
if ret < 0 {
log.Fatal("AvfilterGraphConfig Failed des : ", avutil.ErrorFromCode(ret))
//return nil
}
return &Filter{
ins : ins,
outs : outs,
graph : graph,
}
//log.Trace("GraphDump : \n", graph.AvfilterGraphDump(""))