生活随笔
收集整理的這篇文章主要介紹了
FFmpeg Filter基本使用
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
FFmpeg Filter基本使用
目錄
FFmpeg filter簡(jiǎn)介 filter的使??法 filter的語(yǔ)法 filterchain的語(yǔ)法 filtergraph的語(yǔ)法 基本結(jié)構(gòu) 創(chuàng)建簡(jiǎn)單的濾波過(guò)程 創(chuàng)建復(fù)雜的濾波過(guò)程 濾波API
ffmpeg中有很多已經(jīng)實(shí)現(xiàn)好的濾波器,這些濾波器的實(shí)現(xiàn)位于libavfilter?錄之下,?戶需要進(jìn)?濾波時(shí),就是是調(diào)?這些濾波器來(lái)實(shí)現(xiàn)的。ffmpeg對(duì)于調(diào)?濾波器有?整套的調(diào)?機(jī)制。
1. FFmpeg filter簡(jiǎn)介
FFmpeg filter提供了很多?視頻特效處理的功能,?如視頻縮放、截取、翻轉(zhuǎn)、疊加等。 其中定義了很多的filter,例如以下常?的?些filter。 scale:視頻/圖像的縮放 overlay:視頻/圖像的疊加 crop:視頻/圖像的裁剪 trim:截取視頻的?段 rotate:以任意?度旋轉(zhuǎn)視頻 ?持的filter的列表可以通過(guò)以下命令獲得。
ffmpeg
- filters
以下是filter的?個(gè)簡(jiǎn)單的應(yīng)?示例,對(duì)視頻的寬和?減半。
ffmpeg
- i input
- vf scale
= iw
/ 2 : ih
/ 2 output
2. filter的使??法
學(xué)習(xí)filter的使?,先需要了解?下filter的語(yǔ)法。
FFmpeg中filter包含三個(gè)層次,filter->filterchain->filtergraph。
具體參考下圖:
說(shuō)明:
第?層是 filter 的語(yǔ)法 第?層是 filterchain的語(yǔ)法。 第三層是 filtergraph的語(yǔ)法 filtergraph可以??本形式表示,可以作為ffmpeg中的-filter/-vf/-af和-filter_complex選項(xiàng)以及ffplay中的-vf/-af和libavfilter/avfilter.h中定義的avfilter_graph_parse2()函數(shù)的參數(shù)。
為了說(shuō)明可能的情況,我們考慮下?的例?“把視頻的上部分鏡像到下半部分”。
處理流程如下
使?split filter將輸?流分割為兩個(gè)流[main]和[temp]。 其中?個(gè)流[temp]通過(guò)crop filter把下半部分裁剪掉。 步驟2中的輸出再經(jīng)過(guò)vflip filter對(duì)視頻進(jìn)?垂直翻轉(zhuǎn),輸出[flip]。 把步驟3中輸出[flip]疊加到[main]的下半部分。 可以?以下的命令來(lái)實(shí)現(xiàn)這個(gè)流程
ffmpeg
- i INPUT
- vf
"split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip
[flip]; [main][flip] overlay=0:H/2" OUTPUT
1. filter的語(yǔ)法
??個(gè)字符串描述filter的組成,形式如下
[ in_link_1
] …
[ in_link_N
] filter_name
= parameters
[ out_link_1
] …
[ out_link_M
]
1. 參數(shù)說(shuō)明:
[in_link_N]、[out_link_N]:?來(lái)標(biāo)識(shí)輸?和輸出的標(biāo)簽。in_link_N是標(biāo)簽名,標(biāo)簽名可以任意命名,需使??括號(hào)括起來(lái)。在filter_name的前?的標(biāo)簽?于標(biāo)識(shí)輸?,在filter_name后?的?于標(biāo)識(shí)輸出。?個(gè)filter可以有多個(gè)輸?和多個(gè)輸出,沒(méi)有輸?的filter稱(chēng)為source filter,沒(méi)有輸出的filter稱(chēng)為sink filter。對(duì)輸?或輸出打標(biāo)簽是可選的,打上標(biāo)簽是為了連接其他filter時(shí)使?。
filter_name:filter的名稱(chēng)。
“=parameters”:包含初始化filter的參數(shù),是可選的。
“=parameters”有以下?種形式
使?’:'字符分隔的?個(gè)“鍵=值”對(duì)列表。如下所示 ffmpeg
- i input
- vf scale
= w
= iw
/ 2 : h
= ih
/ 2 output
ffmpeg
- i input
- vf scale
= h
= ih
/ 2 : w
= iw
/ 2 output
使?’:'字符分割的“值”的列表。在這種情況下,鍵按照聲明的順序被假定為選項(xiàng)名。例如,scale filter的前兩個(gè)選項(xiàng)分別是w和h,當(dāng)參數(shù)列表為“iw/2:ih/2”時(shí),iw/2的值賦給w,ih/2的值賦給h。如下所示。 ffmpeg
- i input
- vf scale
= iw
/ 2 : ih
/ 2 output
使?’:’ 字符分隔混合“值”和“鍵=值”對(duì)的列表。“值”必須位于“鍵=值”對(duì)之前,并遵循與前?點(diǎn)相同的約束順序。之后的“鍵=值”對(duì)的順序不受約束。如下所示。 ffmpeg
- i input
- vf scale
= iw
/ 2 : h
= ih
/ 2 output
filter類(lèi)定義了filter的特性以及輸?和輸出的數(shù)量,某個(gè)filter的使??式可以通過(guò)以下命令獲知。
ffmpeg - h filter= filter_name
以下是rotate filter的使??式
Filter rotateRotate the input image. slice threading supportedInputs: #0 : default ( video) Outputs: #0 : default ( video)
rotate AVOptions: angle < string > . . FV... . . T set angle ( in radians) ( default "0" ) a < string > . . FV... . . T set angle ( in radians) ( default "0" ) out_w < string > . . FV... ... set output width expression ( default "iw" ) ow < string > . . FV... ... set output width expression ( default "iw" ) out_h < string > . . FV... ... set output height expression ( default "ih" ) oh < string > . . FV... ... set output height expression ( default "ih" ) fillcolor < string > . . FV... ... set background fill color ( default "black" ) c < string > . . FV... ... set background fill color ( default "black" ) bilinear < boolean> . . FV... ... use bilinear interpolation ( default true ) This filter has support for timeline through the 'enable' option.
可以看出它?持slice threading。 Inputs下?定義的是輸?。可以看出rotate filter有?個(gè)輸?,格式為Video。 Outputs下?定義的是輸出。可以看出rotate filter有有?個(gè)輸出,格式為video。 AVOptions下?定義了?持的參數(shù),后?有默認(rèn)值描述。為了簡(jiǎn)化輸?參數(shù),對(duì)?的參數(shù)名提供?個(gè)簡(jiǎn)化的名稱(chēng)。?如rotate filter中,“angle”的簡(jiǎn)化名稱(chēng)是“a” 以下是使?到fiter的標(biāo)簽名的?個(gè)示例:抽取視頻Y、U、V分量到不同的?件
ffmpeg - i input. mp4 - filter_complex "extractplanes=y+u+v[y][u][v]" - m
ap "[y]" input_y. mp4 - map "[u]" input_u. mp4 - map "[v]" input_v. mp4
extractplanes filter指定了三個(gè)輸出,分別是 [y][u][v],抽取后,將不同的輸出保存到不同的?件中。
2. filterchain的語(yǔ)法
??個(gè)字符串描述filterchain的組成,形式如下
"filter1, filter2, ... filterN-1, filterN"
說(shuō)明: 由?個(gè)或多個(gè)filter的連接?成,filter之間以逗號(hào)“,”分隔。 每個(gè)filter都連接到序列中的前?個(gè)filter,即前?個(gè)filter的輸出是后?個(gè)filter的輸?。?如示例 ffmpeg
- i INPUT
- vf
"split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip
[flip]; [main][flip] overlay=0:H/2" OUTPUT
示例說(shuō)明: crop、vflip在同?個(gè)filterchain中
3. filtergraph的語(yǔ)法
??個(gè)字符串描述filtergraph的組成,形式如下
"filterchain1;filterchain2;...filterchainN-1;fiterchainN"
由?個(gè)或多個(gè)filter的組合?成,filterchain之間?分號(hào)";"分隔。 filtergraph是連接filter的有向圖。它可以包含循環(huán),?對(duì)filter之間可以有多個(gè)連接。 當(dāng)在filtergraph中找到兩個(gè)相同名稱(chēng)的標(biāo)簽時(shí),將創(chuàng)建相應(yīng)輸?和輸出之間的連接。 如果輸出沒(méi)有被打標(biāo)簽,則默認(rèn)將其連接到filterchain中下?個(gè)filter的第?個(gè)未打標(biāo)簽的輸?。例如以下filterchain中
nullsrc
, split
[ L1
] , [ L2
] overlay
, nullsink
說(shuō)明:split filter有兩個(gè)輸出,overlay filter有兩個(gè)輸?。split的第?個(gè)輸出標(biāo)記為“L1”,overlay的第?個(gè)輸?pad標(biāo)記為“L2”。split的第?個(gè)輸出將連接到overlay的第?個(gè)輸?。 在?個(gè)filter描述中,如果沒(méi)有指定第?個(gè)filter的輸?標(biāo)簽,則假定為“In”。如果沒(méi)有指定最后?個(gè)filter的輸出標(biāo)簽,則假定為“out”。 在?個(gè)完整的filterchain中,所有沒(méi)有打標(biāo)簽的filter輸?和輸出必須是連接的。如果所有filterchain的所有filter輸?和輸出pad都是連接的,則認(rèn)為filtergraph是有效的 ?如示例
ffmpeg
- i INPUT
- vf
"split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT
其中有三個(gè)filterchain, 分別是: “split [main][tmp]”。它只有?個(gè)filter,即 split,它有?個(gè)默認(rèn)的輸?,即INPUT解碼后的frame。有兩個(gè)輸出, 以 [main], [tmp] 標(biāo)識(shí)。 “[tmp] crop=iw:ih/2:0:0, vflip [flip]”。它由兩個(gè)filter組成,crop和vflip,crop的輸? 為[tmp],vflip的輸出標(biāo)識(shí)為[flip]。 “[main][flip] overlay=0:H/2”。它由?個(gè)filter組成,即overlay。有兩個(gè)輸?,[main]和[flip]。有?個(gè)默認(rèn)的輸出。
3. 基本結(jié)構(gòu)
我們把?整個(gè)濾波的流程稱(chēng)為濾波過(guò)程。下?是?個(gè)濾波過(guò)程的結(jié)構(gòu) 圖中簡(jiǎn)要指示出了濾波所?到的各個(gè)結(jié)構(gòu)體,各個(gè)結(jié)構(gòu)體有如下作?:
名稱(chēng)作用 AVFilterGraph ?于統(tǒng)合這整個(gè)濾波過(guò)程的結(jié)構(gòu)體。 AVFilter 濾波器,濾波器的實(shí)現(xiàn)是通過(guò)AVFilter以及位于其下的結(jié)構(gòu)體/函數(shù)來(lái)維護(hù)的。 AVFilterContext ?個(gè)濾波器實(shí)例,即使是同?個(gè)濾波器,但是在進(jìn)?實(shí)際的濾波時(shí),也會(huì)由于輸?的參數(shù)不同?有不同的濾波效果,AVFilterContext就是在實(shí)際進(jìn)?濾波時(shí)?于維護(hù)濾波相關(guān)信息的實(shí)體。 AVFilterLink 濾波器鏈,作?主要是?于連接相鄰的兩個(gè)AVFilterContext。為了實(shí)現(xiàn)?個(gè)濾波過(guò)程,可能會(huì)需要多個(gè)濾波器協(xié)同完成,即?個(gè)濾波器的輸出可能會(huì)是另?個(gè)濾波器的輸?,AVFilterLink的作?是串聯(lián)兩個(gè)相鄰的濾波器實(shí)例,形成兩個(gè)濾波器之間的通道。 AVFilterPad 濾波器的輸?輸出端?,?個(gè)濾波器可以有多個(gè)輸?以及多個(gè)輸出端?,相鄰濾波器之間是通過(guò)AVFilterLink來(lái)串聯(lián)的,?位于AVFilterLink兩端的分別就是前?個(gè)濾波器的輸出端?以及后?個(gè)濾波器的輸?端?。 buffersrc ?個(gè)特殊的濾波器,這個(gè)濾波器的作?就是充當(dāng)整個(gè)濾波過(guò)程的??,通過(guò)調(diào)?該濾波器提供的函數(shù)(如av_buffersrc_add_frame)可以把需要濾波的幀傳輸進(jìn)?濾波過(guò)程。在創(chuàng)建該濾波器實(shí)例的時(shí)候需要提供?些關(guān)于所輸?的幀的格式的必要參數(shù)(如:time_base、圖像的寬?、圖像像素格式等)。 buffersink ?個(gè)特殊的濾波器,這個(gè)濾波器的作?就是充當(dāng)整個(gè)濾波過(guò)程的出?,通過(guò)調(diào)?該濾波器提供的函數(shù)(如av_buffersink_get_frame)可以提取出被濾波過(guò)程濾波完成后的幀。
4. 創(chuàng)建簡(jiǎn)單的濾波過(guò)程
創(chuàng)建整個(gè)濾波過(guò)程包含以下步驟: ?先需要得到整個(gè)濾波過(guò)程所需的濾波器(AVFilter),其中buffersrc以及buffersink是作為輸?以及輸出所必須的兩個(gè)濾波器。
const AVFilter
* buffersrc
= avfilter_get_by_name ( "buffer" ) ;
const AVFilter
* buffersink
= avfilter_get_by_name ( "buffersink" ) ;
const AVFilter
* myfilter
= avfilter_get_by_name ( "myfilter" ) ;
創(chuàng)建統(tǒng)合整個(gè)濾波過(guò)程的濾波圖結(jié)構(gòu)體(AVFilterGraph)
filter_graph
= avfilter_graph_alloc ( ) ;
創(chuàng)建?于維護(hù)濾波相關(guān)信息的濾波器實(shí)例(AVFilterContext)
AVFilterContext
* in_video_filter
= NULL
;
AVFilterContext
* out_video_filter
= NULL
;
AVFilterContext
* my_video_filter
= NULL
;
avfilter_graph_create_filter ( & in_video_filter
, buffersrc
, "in" , args
, NULL
, filter_graph
) ;
avfilter_graph_create_filter ( & out_video_filter
, buffersink
, "out" , NULL
, NULL
, filter_graph
) ;
avfilter_graph_create_filter ( & my_video_filter
, myfilter
, "myfilter" , NULL
, NULL
, filter_graph
) ;
?AVFilterLink把相鄰的兩個(gè)濾波實(shí)例連接起來(lái)
avfilter_link ( in_video_filter
, 0 , my_video_filter
, 0 ) ;
avfilter_link ( my_video_filter
, 0 , out_video_filter
, 0 ) ;
提交整個(gè)濾波圖
avfilter_graph_config ( filter_graph
, NULL
) ;
5. 創(chuàng)建復(fù)雜的濾波過(guò)程
當(dāng)濾波過(guò)程復(fù)雜到?定程度時(shí),即需要多個(gè)濾波器進(jìn)?復(fù)雜的連接來(lái)實(shí)現(xiàn)整個(gè)濾波過(guò)程,這時(shí)候?qū)τ谡{(diào)?者來(lái)說(shuō),繼續(xù)采?上述?法來(lái)構(gòu)建濾波圖就顯得不夠效率。對(duì)于復(fù)雜的濾波過(guò)程,ffmpeg提供了?個(gè)更為?便的濾波過(guò)程創(chuàng)建?式。 這種復(fù)雜的濾波器過(guò)程創(chuàng)建?式要求?戶以字符串的?式描述各個(gè)濾波器之間的關(guān)系。如下是?個(gè)描述復(fù)雜濾波過(guò)程的字符串的例?:
[ 0 ] trim
= start_frame
= 10 : end_frame
= 20 [ v0
] ; \
[ 0 ] trim
= start_frame
= 30 : end_frame
= 40 [ v1
] ; \
[ v0
] [ v1
] concat
= n
= 2 [ v2
] ; \
[ 1 ] hflip
[ v3
] ; \
[ v2
] [ v3
] overlay
= eof_action
= repeat
[ v4
] ; \
[ v4
] drawbox
= 50 : 50 : 120 : 120 : red
: t
= 5 [ v5
]
以上是?個(gè)連續(xù)的字符串,為了?便分析我們把該字符串進(jìn)?了劃分,每??都是?個(gè)濾波器實(shí)例,對(duì)于??:
開(kāi)頭是?對(duì)中括號(hào),中括號(hào)內(nèi)的是輸?的標(biāo)識(shí)名0。 中括號(hào)后?接著的是濾波器名稱(chēng)trim。 名稱(chēng)后的第?個(gè)等號(hào)后?是濾波器參數(shù)start_frame=10:end_frame=20,這?有兩組參數(shù),兩組參數(shù)?冒號(hào)分開(kāi)。 第?組參數(shù)名稱(chēng)為start_frame,參數(shù)值為10,中間?等號(hào)分開(kāi)。 第?組參數(shù)名稱(chēng)為end_frame,參數(shù)值為20,中間?等號(hào)分開(kāi)。 最后也有?對(duì)中括號(hào),中括號(hào)內(nèi)的是輸出的標(biāo)識(shí)名v0。 如果?個(gè)濾波實(shí)例的輸?標(biāo)識(shí)名與另?個(gè)濾波實(shí)例的輸出標(biāo)識(shí)名相同,則表示這兩個(gè)濾波實(shí)例構(gòu)成濾波鏈。 如果?個(gè)濾波實(shí)例的輸?標(biāo)識(shí)名或者輸出標(biāo)識(shí)名?直沒(méi)有與其它濾波實(shí)例的輸出標(biāo)識(shí)名或者輸?標(biāo)識(shí)名相同,則表明這些為外部的輸?輸出,通常我們會(huì)為其接上buffersrc以及buffersink。 按照這種規(guī)則,上?的濾波過(guò)程可以被描繪成以下濾波圖
ffmpeg提供?個(gè)函數(shù)?于解析這種字符串:avfilter_graph_parse2。這個(gè)函數(shù)會(huì)把輸?的字符串?成如上?的濾波圖,不過(guò)我們需要???成buffersrc以及buffersink的實(shí)例,并通過(guò)該函數(shù)提供的輸?以及輸出接?把buffersrc、buffersink與該濾波圖連接起來(lái)。整個(gè)流程包含以下步驟
創(chuàng)建統(tǒng)合整個(gè)濾波過(guò)程的濾波圖結(jié)構(gòu)體(AVFilterGraph) filter_graph
= avfilter_graph_alloc ( ) ;
解析字符串,并構(gòu)建該字符串所描述的濾波圖 avfilter_graph_parse2 ( filter_graph
, graph_desc
, & inputs
, & outputs
) ;
其中inputs與outputs分別為輸?與輸出的接?集合,我們需要為這些接?接上輸?以及輸出 for ( cur
= inputs
, i
= 0 ; cur
; cur
= cur
- > next
, i
++ ) { const AVFilter
* buffersrc
= avfilter_get_by_name ( "buffer" ) ; avfilter_graph_create_filter ( & filter
, buffersrc
, name
, args
, NULL
, filter_graph
) ; avfilter_link ( filter
, 0 , cur
- > filter_ctx
, cur
- > pad_idx
) ; } avfilter_inout_free ( & inputs
) ; for ( cur
= outputs
, i
= 0 ; cur
; cur
= cur
- > next
, i
++ ) { const AVFilter
* buffersink
= avfilter_get_by_name ( "buffersink" ) ; avfilter_graph_create_filter ( & filter
, buffersink
, name
, NULL
, NULL
, filter_graph
) ; avfilter_link ( cur
- > filter_ctx
, cur
- > pad_idx
, filter
, 0 ) ; } avfilter_inout_free ( & outputs
) ;
提交整個(gè)濾波圖 avfilter_graph_config ( filter_graph
, NULL
) ;
6. 濾波API
上?主要討論了如何創(chuàng)建濾波過(guò)程,不過(guò)要進(jìn)?濾波還需要把幀傳輸進(jìn)?該過(guò)程,并在濾波完成后從該過(guò)程中提取出濾波完成的幀。 buffersrc提供了向?yàn)V波過(guò)程輸?幀的API:av_buffersrc_add_frame。向指定的buffersrc實(shí)例輸?想要進(jìn)?濾波的幀就可以把幀傳?濾波過(guò)程。
av_buffersrc_add_frame ( c
- > in_filter
, pFrame
) ;
buffersink提供了從濾波過(guò)程提取幀的API:av_buffersink_get_frame。可以從指定的buffersink實(shí)例提取濾波完成的幀。
av_buffersink_get_frame ( c
- > out_filter
, pFrame
) ;
當(dāng)av_buffersink_get_frame返回值?于0則表示提取成功。
總結(jié)
以上是生活随笔 為你收集整理的FFmpeg Filter基本使用 的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。