(原)ffmpeg過濾器開發和理解


最近學習了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處理。
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM