[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(""))