最近學習了ffmpeg關於filter過濾器的開發,關於中間的幾個相關概念,我們先放在簡單介紹一下:
AVFilterGraph:幾乎完全等同與directShow中的fitlerGraph,代表一串連接起來的filter們.
AVFilter:代表一個filter.
AVFilterPad:代表一個filter的輸入或輸出口,等同於DShow中的Pin.只有輸出pad的filter叫source,只有輸入pad的tilter叫sink.
AVFilterLink:代表兩個連接的fitler之間的粘合物.
然后分別看下各自的結構定義
1,過濾器結構體定義:
1 struct AVFilter{ 2 const char * name;//過濾器名稱。 3 4 const char * description;//過濾器說明。 5 6 const AVFilterPad * inputs;//輸入列表,由零元素終止。 7 8 const AVFilterPad * outputs;//輸出列表,由零元素終止。 9 10 const AVClass * priv_class;//私有數據類,用於聲明過濾器私有AVOptions。 11 12 int flags; //AVFILTER_FLAG_ *的組合。 13 14 int(* init )(AVFilterContext *ctx);//過濾初始化函數。 15 16 //應該通過想要將AVOptions的字典傳遞給在init中分配的嵌套上下文的過濾器來設置而不是init。 17 int(* init_dict )(AVFilterContext *ctx, AVDictionary **options); 18 19 //過濾器在其輸入和輸出上支持的查詢格式 20 void(* uninit )(AVFilterContext *ctx); 21 22 //要為過濾器分配的私有數據的大小 23 int priv_size; 24 25 //avfilter的附加標志僅供內部使用。 26 int flags_internal; 27 28 // 由過濾器注冊系統使用。 29 struct AVFilter * next; 30 31 // 使過濾器實例處理一個命令。 32 int(* process_command )(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags); 33 34 //過濾初始化函數,替代init()回調。 35 int(* init_opaque )(AVFilterContext *ctx, void *opaque); 36 37 //過濾器激活函數。 38 int(* activate )(AVFilterContext *ctx); 39 }
2,過濾器輸入輸出pad結構體AVFilterPad介紹
1 struct AVFilterPad { 2 //過濾器pad名稱 3 const char *name; 4 //pad元素的媒體類型,音頻或者視頻 5 enum AVMediaType type; 6 7 //獲取視頻緩存幀數據的回調函數,只能用於input video pad,如果這個用戶沒有定義,就會指派一個默認的回調函數 ff_default_get_video_buffer(). 8 AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h); 9 10 //獲取音頻緩存幀數據的回調函數,只能用於input audio pad,如果這個用戶沒有定義,就會指派一個默認的回調函數 ff_default_get_audio_buffer(). 11 AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples); 12 13 //過濾器回調函數,這個是當一個過濾器收到一個音頻或者視頻幀數據,然后調用這個回調函數進行處理 14 int (*filter_frame)(AVFilterLink *link, AVFrame *frame); 15 16 //僅用於output pad的poll回調函數,這將返回立即可用的示例的數量。如果下一個request_frame()保證返回一個幀,那么它應該返回一個正值 17 int (*poll_frame)(AVFilterLink *link); 18 19 //僅用於output pad,幀請求回調函數, 20 int (*request_frame)(AVFilterLink *link); 21 22 23 //link配置回調函數,對於input pad,它主要是做一些link的屬性檢查,已經更新一些過濾器內部狀態,例如自己定義的結構體狀態初始化等,可以在這個函數里面做一些必要的操作,而對於ouput pad,他應該會設置width/height信息 24 int (*config_props)(AVFilterLink *link); 25 26 int needs_fifo; 27 28 int needs_writable; 29 }
3,過濾器實例上下文結構體AVFilterContext介紹
1 struct AVFilterContext{ 2 const AVClass * av_class;//需要av_log()和過濾常用選項 3 const AVFilter * filter;// AVFilter的一個實例 4 char * name; //此過濾器實例的名稱 5 AVFilterPad * input_pads;//數組輸入板 6 AVFilterLink ** inputs;//指向輸入鏈接的指針數組 7 unsigned nb_inputs;//輸入板數 8 AVFilterPad * output_pads;//輸出板陣列 9 unsigned nb_outputs;//輸出板數量 10 void * priv; //過濾器使用的私人數據 11 struct AVFilterGraph * graph;//filtergraph this filter belongs to 12 int thread_type;//允許/使用的多線程類型。 13 AVFilterInternal * internal;//libavfilter內部使用的不透明結構。 14 struct AVFilterCommand * command_queue; 15 char * enable_str;//啟用表達式字符串 16 void * enable;// 解析的表達式(AVExpr *) 17 double * var_values;//啟用表達式的變量值 18 int is_disabled;//從最后的表達式評估啟用狀態 19 20 //對於將創建硬件框架的過濾器,設置過濾器應在其中創建的設備。 21 AVBufferRef * hw_device_ctx; 22 int nb_threads;//此過濾器實例允許的最大線程數。 23 unsigned ready;//過濾器的就緒狀態 24 }
對於他們的關系,我們借用一下別人畫的這個圖:

結合這個圖,我們來分析一下,過濾器直接的數據傳遞是怎么樣的,什么樣的過濾器需要在AVFilterPad結構體里面定義filter_frame函數來做過濾器應該做的事情,什么時候更加適合考慮把過濾器處理數據的事情放到AVFilter的activate函數里面。
先說一下我個人的理解:針對只有一個輸入流的過濾器,直接對過濾器中的唯一的一個幀原始數據進行處理的,例如scale這種的過濾器,我們更加合適把過濾器的事情放到pad里面的filter_frame函數中來處理,而對於將多個輸入流的數據進行處理的過濾器,例如overlay(它必須有兩個輸入數據,main,overlay兩層),他更加適合將數據放到處理過程放入到avfilter的activate函數里面,通過它來調用ff_framesync_activate函數,從而調用FFFrameSync中的on_event處理。