通過函數split_commandline解析指令行參數并儲存在OptionParseContext結構體中。
然後通過函數parse_optgroup将OptionParseContext結構體中的資料解析到OptionsContext結構體中。
OptionsContext結構體中各個字段是最終控制ffmpeg行為的。
parse_optgroup代碼如下:
函數循環周遊OptionGroup中的每個Option,并調用write_option将結果寫到OptionsContext對應的結構體成員中。
write_option有點抽象,我們重點分析下,
我們先看函數的前半部分,是解析包含OPT_SPEC标記選項的,具有OPT_SPEC标記的選項會在OptionsContext結構體中對應一個SpecifierOpt指針成員以及一個表示SpecifierOpt大小的int型變量,比如
我們以codec_names成員的指派為例:
codec_names是SpecifierOpt結構體指針變量,它會指向一個或者多個SpecifierOpt變量,相當于SpecifierOpt數組;緊接着的變量nb_codec_names表示數組的大小。
SpecifierOpt結構體如下:
從預定義的OptionDef數組options可以得知,指令行中出現-c / -c:v / -c:a / -codec時,都會将後面的值儲存在codec_names中。
.off = OFFSET(codec_names) 在選項定義的時候會計算出codec_names成員在OptionsContext結構體中的偏移量,在write_option中根據結構體首位址以及成員偏移量可以得到成員的通路位址:
void *dst = po->flags & (OPT_OFFSET | OPT_SPEC) ?
(uint8_t *)optctx + po->u.off : po->u.dst_ptr;
codec_names是SpecifierOpt指針變量,dst指向的是codec_names的通路位址,是以dst相當于是指向SpecifierOpt指針的指針
SpecifierOpt **so = dst;
optctx是ptr0,dst是ptr5。
dstcount = (int *)(so + 1);
(so + 1)相當于是(dst + sizeof(SpecifierOpt *)),得到的是ptr6,即nb_codec_names變量的通路位址。
*so = grow_array(*so, sizeof(**so), dstcount, *dstcount + 1);
通過grow_array向codec_names數組中添加一個SpecifierOpt變量,并把nb_codec_names加1。
(*so)[*dstcount - 1].specifier = str;
将-c或者-c:後面的值指派給新添加的SpecifierOpt變量的specifier字段.
dst = &(*so)[*dstcount - 1].u;
将SpecifierOpt的union成員位址指派給dst。
if (po->flags & OPT_STRING) {
// ...
*(char **)dst = str;
}
如果選項後跟一個string類型的值,将string值指派給union成員中的str字段。
以下列指令行為例:
ffmpeg -i input.mp4 -c:v mpeg4 -c:a aac output.mp4
parse_optgroup執行完成後OptionsContext中nb_codec_names和codec_names的值如上圖所示。