生活随笔
收集整理的這篇文章主要介紹了
FFmpeg Filter基本使用
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
FFmpeg Filter基本使用
目錄
FFmpeg filter簡介 filter的使??法 filter的語法 filterchain的語法 filtergraph的語法 基本結構 創建簡單的濾波過程 創建復雜的濾波過程 濾波API
ffmpeg中有很多已經實現好的濾波器,這些濾波器的實現位于libavfilter?錄之下,?戶需要進?濾波時,就是是調?這些濾波器來實現的。ffmpeg對于調?濾波器有?整套的調?機制。
1. FFmpeg filter簡介
FFmpeg filter提供了很多?視頻特效處理的功能,?如視頻縮放、截取、翻轉、疊加等。 其中定義了很多的filter,例如以下常?的?些filter。 scale:視頻/圖像的縮放 overlay:視頻/圖像的疊加 crop:視頻/圖像的裁剪 trim:截取視頻的?段 rotate:以任意?度旋轉視頻 ?持的filter的列表可以通過以下命令獲得。
ffmpeg
- filters
以下是filter的?個簡單的應?示例,對視頻的寬和?減半。
ffmpeg
- i input
- vf scale
= iw
/ 2 : ih
/ 2 output
2. filter的使??法
學習filter的使?,先需要了解?下filter的語法。
FFmpeg中filter包含三個層次,filter->filterchain->filtergraph。
具體參考下圖:
說明:
第?層是 filter 的語法 第?層是 filterchain的語法。 第三層是 filtergraph的語法 filtergraph可以??本形式表示,可以作為ffmpeg中的-filter/-vf/-af和-filter_complex選項以及ffplay中的-vf/-af和libavfilter/avfilter.h中定義的avfilter_graph_parse2()函數的參數。
為了說明可能的情況,我們考慮下?的例?“把視頻的上部分鏡像到下半部分”。
處理流程如下
使?split filter將輸?流分割為兩個流[main]和[temp]。 其中?個流[temp]通過crop filter把下半部分裁剪掉。 步驟2中的輸出再經過vflip filter對視頻進?垂直翻轉,輸出[flip]。 把步驟3中輸出[flip]疊加到[main]的下半部分。 可以?以下的命令來實現這個流程
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的語法
??個字符串描述filter的組成,形式如下
[ in_link_1
] …
[ in_link_N
] filter_name
= parameters
[ out_link_1
] …
[ out_link_M
]
1. 參數說明:
[in_link_N]、[out_link_N]:?來標識輸?和輸出的標簽。in_link_N是標簽名,標簽名可以任意命名,需使??括號括起來。在filter_name的前?的標簽?于標識輸?,在filter_name后?的?于標識輸出。?個filter可以有多個輸?和多個輸出,沒有輸?的filter稱為source filter,沒有輸出的filter稱為sink filter。對輸?或輸出打標簽是可選的,打上標簽是為了連接其他filter時使?。
filter_name:filter的名稱。
“=parameters”:包含初始化filter的參數,是可選的。
“=parameters”有以下?種形式
使?’:'字符分隔的?個“鍵=值”對列表。如下所示 ffmpeg
- i input
- vf scale
= w
= iw
/ 2 : h
= ih
/ 2 output
ffmpeg
- i input
- vf scale
= h
= ih
/ 2 : w
= iw
/ 2 output
使?’:'字符分割的“值”的列表。在這種情況下,鍵按照聲明的順序被假定為選項名。例如,scale filter的前兩個選項分別是w和h,當參數列表為“iw/2:ih/2”時,iw/2的值賦給w,ih/2的值賦給h。如下所示。 ffmpeg
- i input
- vf scale
= iw
/ 2 : ih
/ 2 output
使?’:’ 字符分隔混合“值”和“鍵=值”對的列表。“值”必須位于“鍵=值”對之前,并遵循與前?點相同的約束順序。之后的“鍵=值”對的順序不受約束。如下所示。 ffmpeg
- i input
- vf scale
= iw
/ 2 : h
= ih
/ 2 output
filter類定義了filter的特性以及輸?和輸出的數量,某個filter的使??式可以通過以下命令獲知。
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下?定義的是輸???梢钥闯鰎otate filter有?個輸?,格式為Video。 Outputs下?定義的是輸出。可以看出rotate filter有有?個輸出,格式為video。 AVOptions下?定義了?持的參數,后?有默認值描述。為了簡化輸?參數,對?的參數名提供?個簡化的名稱。?如rotate filter中,“angle”的簡化名稱是“a” 以下是使?到fiter的標簽名的?個示例:抽取視頻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指定了三個輸出,分別是 [y][u][v],抽取后,將不同的輸出保存到不同的?件中。
2. filterchain的語法
??個字符串描述filterchain的組成,形式如下
"filter1, filter2, ... filterN-1, filterN"
說明: 由?個或多個filter的連接?成,filter之間以逗號“,”分隔。 每個filter都連接到序列中的前?個filter,即前?個filter的輸出是后?個filter的輸?。?如示例 ffmpeg
- i INPUT
- vf
"split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip
[flip]; [main][flip] overlay=0:H/2" OUTPUT
示例說明: crop、vflip在同?個filterchain中
3. filtergraph的語法
??個字符串描述filtergraph的組成,形式如下
"filterchain1;filterchain2;...filterchainN-1;fiterchainN"
由?個或多個filter的組合?成,filterchain之間?分號";"分隔。 filtergraph是連接filter的有向圖。它可以包含循環,?對filter之間可以有多個連接。 當在filtergraph中找到兩個相同名稱的標簽時,將創建相應輸?和輸出之間的連接。 如果輸出沒有被打標簽,則默認將其連接到filterchain中下?個filter的第?個未打標簽的輸?。例如以下filterchain中
nullsrc
, split
[ L1
] , [ L2
] overlay
, nullsink
說明:split filter有兩個輸出,overlay filter有兩個輸?。split的第?個輸出標記為“L1”,overlay的第?個輸?pad標記為“L2”。split的第?個輸出將連接到overlay的第?個輸?。 在?個filter描述中,如果沒有指定第?個filter的輸?標簽,則假定為“In”。如果沒有指定最后?個filter的輸出標簽,則假定為“out”。 在?個完整的filterchain中,所有沒有打標簽的filter輸?和輸出必須是連接的。如果所有filterchain的所有filter輸?和輸出pad都是連接的,則認為filtergraph是有效的 ?如示例
ffmpeg
- i INPUT
- vf
"split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT
其中有三個filterchain, 分別是: “split [main][tmp]”。它只有?個filter,即 split,它有?個默認的輸?,即INPUT解碼后的frame。有兩個輸出, 以 [main], [tmp] 標識。 “[tmp] crop=iw:ih/2:0:0, vflip [flip]”。它由兩個filter組成,crop和vflip,crop的輸? 為[tmp],vflip的輸出標識為[flip]。 “[main][flip] overlay=0:H/2”。它由?個filter組成,即overlay。有兩個輸?,[main]和[flip]。有?個默認的輸出。
3. 基本結構
我們把?整個濾波的流程稱為濾波過程。下?是?個濾波過程的結構 圖中簡要指示出了濾波所?到的各個結構體,各個結構體有如下作?:
名稱作用 AVFilterGraph ?于統合這整個濾波過程的結構體。 AVFilter 濾波器,濾波器的實現是通過AVFilter以及位于其下的結構體/函數來維護的。 AVFilterContext ?個濾波器實例,即使是同?個濾波器,但是在進?實際的濾波時,也會由于輸?的參數不同?有不同的濾波效果,AVFilterContext就是在實際進?濾波時?于維護濾波相關信息的實體。 AVFilterLink 濾波器鏈,作?主要是?于連接相鄰的兩個AVFilterContext。為了實現?個濾波過程,可能會需要多個濾波器協同完成,即?個濾波器的輸出可能會是另?個濾波器的輸?,AVFilterLink的作?是串聯兩個相鄰的濾波器實例,形成兩個濾波器之間的通道。 AVFilterPad 濾波器的輸?輸出端?,?個濾波器可以有多個輸?以及多個輸出端?,相鄰濾波器之間是通過AVFilterLink來串聯的,?位于AVFilterLink兩端的分別就是前?個濾波器的輸出端?以及后?個濾波器的輸?端?。 buffersrc ?個特殊的濾波器,這個濾波器的作?就是充當整個濾波過程的??,通過調?該濾波器提供的函數(如av_buffersrc_add_frame)可以把需要濾波的幀傳輸進?濾波過程。在創建該濾波器實例的時候需要提供?些關于所輸?的幀的格式的必要參數(如:time_base、圖像的寬?、圖像像素格式等)。 buffersink ?個特殊的濾波器,這個濾波器的作?就是充當整個濾波過程的出?,通過調?該濾波器提供的函數(如av_buffersink_get_frame)可以提取出被濾波過程濾波完成后的幀。
4. 創建簡單的濾波過程
創建整個濾波過程包含以下步驟: ?先需要得到整個濾波過程所需的濾波器(AVFilter),其中buffersrc以及buffersink是作為輸?以及輸出所必須的兩個濾波器。
const AVFilter
* buffersrc
= avfilter_get_by_name ( "buffer" ) ;
const AVFilter
* buffersink
= avfilter_get_by_name ( "buffersink" ) ;
const AVFilter
* myfilter
= avfilter_get_by_name ( "myfilter" ) ;
創建統合整個濾波過程的濾波圖結構體(AVFilterGraph)
filter_graph
= avfilter_graph_alloc ( ) ;
創建?于維護濾波相關信息的濾波器實例(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把相鄰的兩個濾波實例連接起來
avfilter_link ( in_video_filter
, 0 , my_video_filter
, 0 ) ;
avfilter_link ( my_video_filter
, 0 , out_video_filter
, 0 ) ;
提交整個濾波圖
avfilter_graph_config ( filter_graph
, NULL
) ;
5. 創建復雜的濾波過程
當濾波過程復雜到?定程度時,即需要多個濾波器進?復雜的連接來實現整個濾波過程,這時候對于調?者來說,繼續采?上述?法來構建濾波圖就顯得不夠效率。對于復雜的濾波過程,ffmpeg提供了?個更為?便的濾波過程創建?式。 這種復雜的濾波器過程創建?式要求?戶以字符串的?式描述各個濾波器之間的關系。如下是?個描述復雜濾波過程的字符串的例?:
[ 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
]
以上是?個連續的字符串,為了?便分析我們把該字符串進?了劃分,每??都是?個濾波器實例,對于??:
開頭是?對中括號,中括號內的是輸?的標識名0。 中括號后?接著的是濾波器名稱trim。 名稱后的第?個等號后?是濾波器參數start_frame=10:end_frame=20,這?有兩組參數,兩組參數?冒號分開。 第?組參數名稱為start_frame,參數值為10,中間?等號分開。 第?組參數名稱為end_frame,參數值為20,中間?等號分開。 最后也有?對中括號,中括號內的是輸出的標識名v0。 如果?個濾波實例的輸?標識名與另?個濾波實例的輸出標識名相同,則表示這兩個濾波實例構成濾波鏈。 如果?個濾波實例的輸?標識名或者輸出標識名?直沒有與其它濾波實例的輸出標識名或者輸?標識名相同,則表明這些為外部的輸?輸出,通常我們會為其接上buffersrc以及buffersink。 按照這種規則,上?的濾波過程可以被描繪成以下濾波圖
ffmpeg提供?個函數?于解析這種字符串:avfilter_graph_parse2。這個函數會把輸?的字符串?成如上?的濾波圖,不過我們需要???成buffersrc以及buffersink的實例,并通過該函數提供的輸?以及輸出接?把buffersrc、buffersink與該濾波圖連接起來。整個流程包含以下步驟
創建統合整個濾波過程的濾波圖結構體(AVFilterGraph) filter_graph
= avfilter_graph_alloc ( ) ;
解析字符串,并構建該字符串所描述的濾波圖 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
) ;
提交整個濾波圖 avfilter_graph_config ( filter_graph
, NULL
) ;
6. 濾波API
上?主要討論了如何創建濾波過程,不過要進?濾波還需要把幀傳輸進?該過程,并在濾波完成后從該過程中提取出濾波完成的幀。 buffersrc提供了向濾波過程輸?幀的API:av_buffersrc_add_frame。向指定的buffersrc實例輸?想要進?濾波的幀就可以把幀傳?濾波過程。
av_buffersrc_add_frame ( c
- > in_filter
, pFrame
) ;
buffersink提供了從濾波過程提取幀的API:av_buffersink_get_frame??梢詮闹付ǖ腷uffersink實例提取濾波完成的幀。
av_buffersink_get_frame ( c
- > out_filter
, pFrame
) ;
當av_buffersink_get_frame返回值?于0則表示提取成功。
總結
以上是生活随笔 為你收集整理的FFmpeg Filter基本使用 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。