本系列文章居於FFMpeg源碼4.1版本,因此,有些流程和老版本會有稍微差別(源碼我做了詳細註釋,有需要請在下方評論留言,寫明郵箱,我會統一發給你們)。
上一節說了過濾器涉及到的主要結構說明,這一節我們介紹下FFMpeg中過濾器涉及到的主要函數說明,把結構和函數講完後,後面會從過濾器整體的機構來講解,因此,這兩節如果看不明白,只需要看個大概就行,後面說整體流程時會繼續介紹其在整個流程中的位置和功能。
1) ff_filter_alloc
此函數通過傳入的AVFilter和對應的名稱生成AVFilterContext,ACFilterContext記錄了AVFilter的詳細信息,加入我們定義如下:
AVFilter* filter;
ACFilterContext* filterCtx;
那麼filterCtx中的nb_inputs表示了filter中的inputs數組中元素個數,filterCtx中的input_pads就是filter裏的inputs;對應的ouputs也是這樣賦值的。
這個函數最後會調用AVFilter的preinit函數來對過濾器做預初始化。
注意:對於buffer過濾器,其priv_class被定義爲buffer_class,最後這個buffer過濾器的私有數據會賦值給AVFilterContext的priv屬性(大家可以看下buffersrc.c文件實現,因爲buffer是ffmpeg過濾器的第一個,就是source filter,用於緩存AVFrame)。
下面是buffer過濾器的AVFilter定義:
AVFilter ff_vsrc_buffer = {
.name = "buffer",
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them accessible to the filterchain."),
.priv_size = sizeof(BufferSourceContext),
.query_formats = query_formats,
.init = init_video,
.uninit = uninit,
.inputs = NULL,
.outputs = avfilter_vsrc_buffer_outputs,
.priv_class = &buffer_class,
};
從上面結構可以看到,buffer過濾器是沒有實現preinit函數的,而且其只有outputs,說明buffer過濾只能是源(source)。
2) avfilter_graph_alloc_filter
此函數首先通過ff_filter_alloc創建AVFilter對應的上下文結構AVFilterContext,然後把創建的AVFilterContext加入AVFilterGraph的列表filters的末尾,同時nb_filters的值加1(就是AVFilter的個數加1)。
3)avfilter_graph_create_filter
此函數通過傳入的AFFilter信息(過濾器結構、名稱、參數等)創建一個過濾器的上下結構對象AVFilterContext,並把AVFilterContext加入負責管理過濾器的AVFilterGraph中,並設置過濾器的屬性參數。
4)avfilter_link
這個函數主要就是創建AVFilterLink結構,來把兩個過濾器給串聯起來,其屬性src表示上一個AVFilterContext,dst表示下一個AVFilterContext,srcpad表示src中output_pads指定索引的AVFilterPad,dstpad表示dst中output_pads指定索引的AVFilterPad,其中type就是srcpad.type的值;format初始化爲-1。
這個函數裏還有一個比較關鍵的點,那就是初始化AVFilterLink的fifo隊列,這個隊列被初始化爲ff_framequeue_init(&link->fifo, &src->graph->internal->frame_queues);
創建的這個AVFilterLink結構其實就是當前AVFilter和下一個AVFilter的連接器,它被保存在當前AVFilter的outputs中和下一個AVFilter的inputs中,這表示當前AVFilter的輸出就是下一個AVFilter的輸入。
因此這個AVFilterLink保存有當前AVFilter和下一個AVFilter的所有信息。
5)ff_filter_frame
這個函數在源AVFilter處理完幀後調用,然後把處理後的AVFrame放入AVFilterLink的fifo隊列,同時設置下一個AVFilter的ready優先級(必須大於0,這裏設置的是300、200等),當AVFilterGraph再次進行調度時會取出優先級最高的AVFilter來進行處理。
6)avfilter_graph_alloc
分配AVFilterGraph對象,此對象負責管理加入的所有過濾器。
7)avfilter_graph_free
是否過濾器管理對象。
8)av_buffersrc_add_frame
把需要處理的幀加入到buffer過濾器,注意,buffer過濾器是AVFilterGraph中第一個過濾器,其只有輸出沒有輸入。
9)av_buffersink_get_frame_flags
獲取從AVFilterGraph管理的過濾器對象處理的幀AVFrame,此過程會經過所有的過濾器處理,最終處理的結果放入buffersink過濾器裏的,因此這個buffersink過濾器是AVFilterGraph管理的過濾器中最後的一個過濾器,其只有輸入,沒有輸出。
10)get_frame_internal
由av_buffersink_get_frame_flags調用獲取最終處理好的AVFrame。
11)ff_filter_graph_run_once
這個函數主要是從AVFilterGraph中找到優先級最大的一個AVFilterContext過濾器,然後使用此過濾器處理幀。
12)ff_filter_activate
此函數一般由ff_filter_graph_run_once調用,因爲ff_filter_graph_run_once負責找到優先級最大的過濾器,然後傳給這個函數,然後此函數依次調用其輸入inputs的filter_frame對輸入的AVFrame進行處理,如果沒有輸入數據處理了,則調用其outputs的request_frame來把其處理後的幀交給下一個過濾器處理。
13)ff_filter_activate_default
如果我們沒有定義過濾器激活函數,則使用這個默認的激活函數來調用激活當前過濾器對數據進行處理。
14)ff_filter_frame_to_filter ff_filter_frame_framed
這個函數主要處理過濾器的輸入數據,如果過濾器實現了filter_frame,則調用filter_frame處理輸入的幀,否則直接把輸入的幀交給下一個過濾器(調用默認實現)。
15)ff_request_frame_to_filter
此函數主要處理過濾器的輸出數據(已經調用了ff_filter_frame_framed處理了輸入數據),其調用request_frame來做預處理,比如設置下一個過濾器的優先級(設置一個大於0的數,表示過濾器下一步需要激活),如果沒有實現request_frame,則調用默認實現函數ff_request_frame處理。
本系列文章均爲原創,主要總結作者多年在軟件行業的一些經驗,和大家共同學習、進步,轉載請註明出處,謝謝!