天天看點

ffmpeg指令行參數解析-write_option函數

通過函數split_commandline解析指令行參數并儲存在OptionParseContext結構體中。

然後通過函數parse_optgroup将OptionParseContext結構體中的資料解析到OptionsContext結構體中。

OptionsContext結構體中各個字段是最終控制ffmpeg行為的。

parse_optgroup代碼如下:

ffmpeg指令行參數解析-write_option函數

函數循環周遊OptionGroup中的每個Option,并調用write_option将結果寫到OptionsContext對應的結構體成員中。

write_option有點抽象,我們重點分析下,

ffmpeg指令行參數解析-write_option函數

我們先看函數的前半部分,是解析包含OPT_SPEC标記選項的,具有OPT_SPEC标記的選項會在OptionsContext結構體中對應一個SpecifierOpt指針成員以及一個表示SpecifierOpt大小的int型變量,比如

ffmpeg指令行參數解析-write_option函數

我們以codec_names成員的指派為例:

codec_names是SpecifierOpt結構體指針變量,它會指向一個或者多個SpecifierOpt變量,相當于SpecifierOpt數組;緊接着的變量nb_codec_names表示數組的大小。

SpecifierOpt結構體如下:

ffmpeg指令行參數解析-write_option函數

從預定義的OptionDef數組options可以得知,指令行中出現-c / -c:v / -c:a / -codec時,都會将後面的值儲存在codec_names中。

ffmpeg指令行參數解析-write_option函數

.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;           
ffmpeg指令行參數解析-write_option函數

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           
ffmpeg指令行參數解析-write_option函數

parse_optgroup執行完成後OptionsContext中nb_codec_names和codec_names的值如上圖所示。