1 命令行解析
1.1 命令行例子
- 命令行包括三個部分:輸入?yún)?shù),輸出參數(shù)凳宙,和全局選項儿捧。
- -i /home/ron/music/avm.mp4是輸入?yún)?shù),a.mp4是輸出參數(shù)上遥。輸入/輸出參數(shù)可以有專屬的選項,這些選項應(yīng)該緊挨著放在輸入輸出參數(shù)前面争涌。如-vf “split [main][tmp]...[main][flip]”就是輸出參數(shù)a.mp4的選項粉楚。
- 全局選項的位置不需要限定,因為選項是以選項名字查找的。
- 可以有多組輸入?yún)?shù)和多組輸出參數(shù)模软。
1.2 解析命令行
split_commandline()負責(zé)解析命令行伟骨。
int split_commandline(OptionParseContext *octx, int argc, char *argv[],
const OptionDef *options,
const OptionGroupDef *groups, int nb_groups);
解析的結(jié)果保存在OptionParseContext中燃异。解析時需要參考OptionDef和OptionGroupDef携狭。OptonDef[]是支持ffmpeg的選項列表,OptionGroupDef[]是支持的組列表回俐,包括輸入類和輸出類逛腿,前者以-i開頭,加上設(shè)備名仅颇。后者只有文件名单默。
下面的類圖顯示了涉及的類:
- OptionGroup保存一個輸入(或輸出)和它的選項列表。Option表示一個選項忘瓦。
- OptionParseContext中包括多個OptionGroup搁廓。全局選項保存在global_opts中。所有輸入設(shè)備的選項保存在一個OptionGroupList實例中耕皮,所有輸出設(shè)備的選項保存在另一個實例中境蜕。兩者合起來組成數(shù)組groups.
1.3 split_commandline()
split_commandline()在一個循環(huán)中解析命令行,主要涉及如下函數(shù)凌停。
函數(shù) | 功能 |
---|---|
find_option() | 查詢支持的option列表粱年,檢查當(dāng)前元素是否一個option |
add_option() | 將option加入一個臨時組。(因為option先于group出現(xiàn)罚拟,還不知道應(yīng)該加入到哪個組逼泣。) |
match_group_separator() | 查詢支持的group列表,檢查當(dāng)前元素是否是一個Group |
finish_group() | 設(shè)置臨時組的參數(shù)舟舒,并用它填充OptionParseContext.groups(現(xiàn)在知道應(yīng)該加入哪個組了) |
1.4 parse_optgroup()
parse_optgroup()負責(zé)將OptionGroup轉(zhuǎn)換成OptionsContext。
int parse_optgroup(void *optctx, OptionGroup *g)嗜憔;
- OptionGroup保存的選項值是字符串秃励,而OptionsContext保存的值是由OptionDef定義的實際類型。parse_optgroup()的第一個參數(shù)optctx實際上是OptonsContext吉捶。
下面的類圖顯示了涉及的類:
- SpecifierOpt保存實際類型的選項夺鲜。OptionsContext有若干個SpecifierOpt數(shù)組的成員。每個specfier數(shù)組保存一類選項呐舔。如filters保存”filter”選項币励。但filter可以是”filter:v”,屬于video珊拼,也可以是“filter:a”食呻,屬于audio。SpecifierOpt.specifier成員就是用來標(biāo)記這個選項應(yīng)該屬于誰的。對于”filter:v”仅胞,SpecifierOpt.specifier就是”v”每辟。
- 這里順便提一下AVDictionary。解析過程沒有用到它干旧。用戶設(shè)置的選項可能不成功渠欺,而選項的最終值會保存在這里。用av_dict_set()函數(shù)設(shè)置它椎眯。
1.5 parse_optgroup()
parse_optgroup()函數(shù)遍歷OptonGroup中的Option挠将,調(diào)用write_option()將其寫入OptionsContext。
- 對于基本的選項编整,它的OptionDef中定義了它在OptionsContext的偏移舔稀,所以將字符串轉(zhuǎn)化后,直接寫入就好了闹击。比如”filter:v”镶蹋。
- 有的選項可能是其他選項的別名。這時它的OptionDef指定了一個回調(diào)函數(shù)赏半。這個函數(shù)會重定向到所指向的選項上去贺归。如”vf”就是”filter:v”的別名,它的OptionDef指定了回調(diào)函數(shù)opt_video_filter()断箫。這個函數(shù)會調(diào)用parse_option()和find_option()查找”filter:v”對應(yīng)的OptionDef拂酣,并再次調(diào)用write_option()。
- 全局選項仲义。它的OptionDef也定義了一個回調(diào)函數(shù)婶熬。這個函數(shù)直接設(shè)置全局變量。如loglevel埃撵,它的OptionDef定義了opt_loglevel()赵颅。這個函數(shù)調(diào)用av_log_set_level()設(shè)置日志輸出等級。
1.6 MATCH_PER_XXX_OPT()
宏MATCH_PER_TYPE_OPT()和MATCH_PER_STREAM_OPT()用于從OptionsContext讀值暂刘。
- 前者指定參數(shù)mediatype饺谬,用它跟OptionsContext.spcifier比較,找出option并讀出谣拣。后者指定參數(shù)AVStream募寨,調(diào)用check_stream_specifier(),用AVStream的屬性與OptionContext.specifier匹配森缠,找出option并讀出拔鹰。
2 vf選項解析
2.1 avfilter_graph_parse2()
avfilter_graph_parse2()負責(zé)解析vf選項內(nèi)容。
int avfilter_graph_parse2 (AVFilterGraph *graph,
const char *filters,
AVFilterInOut **inputs,
AVFilterInOut **outputs);
輸入?yún)?shù)filters是vf選項內(nèi)容贵涵。輸出參數(shù)Inputs是導(dǎo)出的輸入接口列肢,outputs是filters導(dǎo)出的輸出接口恰画。
2.2 filters
如下是filters的一個例子。它來自ffmpeg的文檔:
http://ffmpeg.org/ffmpeg-filters.html#Filtergraph-description
ffmpeg -i INPUT -vf "split [main][tmp]; [tmp] crop=iw:ih/2:0:0, vflip [flip]; [main][flip] overlay=0:H/2" OUTPUT
對應(yīng)FilterGraph的結(jié)構(gòu)示意圖如下例书。 矩形框內(nèi)是vf的內(nèi)容對應(yīng)的部分锣尉。其中split應(yīng)該導(dǎo)出到inputs中,overlay應(yīng)該導(dǎo)出到outputs中决采。
2.3 vf術(shù)語
描述vf的解析過程需要使用一些術(shù)語自沧。其中一部分是關(guān)于vf語法的,另外一部分是關(guān)于生成的FilterGraph結(jié)構(gòu)的树瞭。
上圖標(biāo)出了vf語法的術(shù)語拇厢。
- 過濾器。過濾器用紅色標(biāo)出晒喷,包括它的名字和參數(shù)孝偎。如”split”,只有名字凉敲。又如”overlay=0:H/2”衣盾,overlay是名字,”0:H/2”是參數(shù)爷抓。名字和參數(shù)用 = 連接副女。
- 位置點霉祸。有兩類位置點歉眷,有名的和無名的缭裆。有名位置點用綠色標(biāo)出,名字用 [] 包住渤昌,如main, flip, tmp虽抄。無名位置點不必標(biāo)出。
- 路徑独柑。路徑是一條從位置點開始迈窟,中間過濾器和位置點交錯,在位置點結(jié)束的處理流程忌栅。多條路徑組成整個filtergraph菠隆。中間的位置點都是無名的,開始和結(jié)束的位置點應(yīng)該是有名的狂秘,除非這條路徑在filtergraph的開始和結(jié)束位置。路徑之間用 ; 隔開躯肌。如 [tmp] crop=iw:ih/2:0:0, vflip [flip]者春。以tmp開始,中間包括crop和vflip和一個無名位置點清女,在flip結(jié)束钱烟。有名位置點是該路徑與其他路徑的連接點,所以需要有一個名字來標(biāo)記,而無名位置點只存在該路徑內(nèi)部的兩個過濾器之間拴袭,是隱含的读第,所以不需要名字。
下圖是FilterGraph的結(jié)構(gòu)圖拥刻。
- FilterGraph是由一系列的過濾器怜瞒,Pad和Pad Link構(gòu)成的。
- 過濾器來自FilterGraph語法中的過濾器般哼,它有一組In Pad和一組OutPad, Pad與語法中的位置點對應(yīng)吴汪。過濾器之間通過Pad聯(lián)系,Pad Link用來將一個In Pad連接到一個OutPad蒸眠。Pad Link沒有對應(yīng)的語法元素漾橙。
- Input/Output用于解析過程,也用于保存整個解析的結(jié)果楞卡,以返回給調(diào)用者霜运。open_inputs標(biāo)記當(dāng)前還沒有解析(與其他OutPad連接)的InPad,open_outputs標(biāo)記當(dāng)前還沒有解析的OutPad蒋腮,curr_inputs標(biāo)記當(dāng)前將要解析的InPad淘捡。
2.4 avfilter_graph_parse2()
avfilter_graph_parse2()主要調(diào)用四個函數(shù)進行解析。
函數(shù) | 功能 |
---|---|
parse_input() | 選取若干open_outputs徽惋,以更新curr_inputs |
parse_filter() | 解析過濾器 |
link_filter_inouts() | 將新的過濾器連入當(dāng)前的curr_inputs案淋,并更新curr_inputs |
parse_output() | 結(jié)束當(dāng)前的curr_inputs,加入open_outputs险绘。 |
2.5 解析過程
下面的圖描述了上述語法的解析過程踢京。圖上部的xxx()是當(dāng)前步驟調(diào)用的函數(shù),下面的字符串是語法宦棺,當(dāng)前變色的部分是正在解析的部分瓣距。
- 解析split
- 將split連入curr_inputs,當(dāng)前的curr_inputs原來為空代咸,所以更新為split的兩個out pads蹈丸。Pads的數(shù)量可以來自split class指定的默認(rèn)值,或者split的參數(shù)呐芥。這里是前者逻杖。
- 給split的outpads命名,以便后面引用思瘟。
- 從open_outputs中選取tmp位置開始一段分支路徑荸百。將tmp標(biāo)記為curr_inputs。
- 解析crop滨攻。
- 將crop連入curr_inputs够话。更新curr_inputs蓝翰,指向crop的out pads。
- 解析vflip女嘲。
- 將vflip連入curr_inputs畜份。
- 給vflip的out pads命名為flip,以便后面引用欣尼。當(dāng)前分支路徑結(jié)束爆雹。
- 從open_outputs中選取main和flip,開始新路徑媒至。
- 解析overlay顶别。Overlay的pads來自overlay class的默認(rèn)值。
- 將overlay連入curr_inputs拒啰。
- 沒有更多的語法元素了驯绎,結(jié)束前將curr_inputs標(biāo)記為open_outputs。注意split的in pads一直沒有解析谋旦,所以它是open_inputs剩失。將open_inputs和open_outputs返回調(diào)用者。
2.6 FilterGraph類
下面的類圖顯示了FilterGraph各元素對應(yīng)的類册着。
- AVFilterContext表示過濾器拴孤。AVFilter是它的屬性類。
- AVFilterPad是Pad類甲捏。一個AVFilterContext實例包括AVFilterPad的一組In Pad實例和一組Out Pad實例演熟。AVFilterLink是Pad Link類,它連接兩個AVFilterPad實例司顿。
- AVFilterLink有一個FFFrameQueue芒粹,用于保存過濾的中間結(jié)果。這時一個frame的數(shù)據(jù)通道大溜。
- AVFilterContext有一個空間化漆,用于保存該特定類型Filter的私有信息,可以是CropContext钦奋,SplitContext或其他filter的一種座云。
- AVFilterInOut用于解析過程標(biāo)記open_iputs, open_ouputs和curr_inputs。它沒有直接引用AVFilterPad付材,而是引用AVFilterContext朦拖,和用序號間接指向AVFilterPad。
- AVFilterGraph和FilterGraph是代表整個FilterGraph的容器類厌衔。
2.7 avfilter_graph_parse2()
下圖是avfilter_graph_parse2()的函數(shù)調(diào)用關(guān)系贞谓。
相關(guān)鏈接
FFMPEG 3.4.2 - ffmpeg源代碼分析 (一)
FFMPEG 3.4.2 - ffmpeg源代碼分析 (二)
FFMPEG 3.4.2 - ffmpeg源代碼分析 (三)
FFMPEG 3.4.2 - ffmpeg源代碼分析 (四)- x264
FFMPEG 3.4.2 - ffplay源代碼分析 (一)
FFMPEG 3.4.2 - ffplay源代碼分析 (二)
FFMPEG 3.4.2 - ffplay源代碼分析 (三)