1. 程式人生 > >FFmpeg-4.0 的filter機制的架構與實現.之二 結構體關係與定義

FFmpeg-4.0 的filter機制的架構與實現.之二 結構體關係與定義

4. Filter的結構體關係圖與定義

4.1 結構體間的關係圖

filter涉及的結構體,主要包括:

> FilterGraph, AVFilterGraph

> InputFilter, InputStream, OutputFilter, OutputStream

> AVFilter, AVFilterContext

> AVFilterLink

> AVFilterPad;

 

它們之間的類關係如下圖所示:

圖5:濾鏡結構體關係圖

 

從上圖可以看到,FFmpeg的濾鏡相關的結構體三層組成:

1) filtergraph層

由結構體 FilterGraph, AVFilterGraph組成;

其中,

FilterGraph, 包含一個InputFilter, 它指示了整個Graph的第一個濾鏡,並指示了InputStream, 從而作為整個Graph的輸入;

包含一個OutputFilter, 它指示了整個Graph的最後一個濾鏡,並指示了OutputStream,從而作為整個Graph的輸出;

包含一個AVFilterGraph的例項,它指示的是組成本graph的filter;

 

2) filterchain層

它由AVFilter, AVFilterContext, AVFilterLink, AVFilterPad組成;

其中,AVFilterContext是AVFilter的例項;

而filter之間是用 AVFilterLink進行連線,意思是,濾鏡之間並不是直接相連的,是通過AVFilterLink進行連線;

AVFilterContext 通過AVFilterLink進行連線後,就組成了Filterchain。

而AVFilterContext與AVFilterLink之間的AVFilterPad是直接相連的,對應的關係是

AVFilterContext的output_pad 連線它下游AVFilterLink的 srcpad;

AVFilterContext的input_pad 連線它上游AVFilterLink的 dstpad;

 

3) filter層

由AVFilterContext, AVFilterPad組成;

其中AVFilterContext是真正進行資料處理的濾鏡實體;

 

AVFilterPad用於AVFilterContext之間的callback(回撥):

第一個AVFilterContext的outputs[0]指標,指向第一個AVFilterLink,這個AVFilterLink的dst指標,指向第二個AVFilterContext。

如果在前一個AVFilterContext呼叫 outputs[0]->dstpad->filter_frame(Frame* input_frame1),

那其實就意味著,第一個過濾器,可以把處理好的一個frame(名字為input_frame1),可以通過這個呼叫,傳遞給第二個過濾器的input_pads的filter_frame函式。

而第二個過濾器,裡面就是使用者自己實現的filter_frame(),以對資料進行處理;

 

 

 

 

以 ./ffmpeg_g -i INPUT.mp4 -vn -acodec libfdk_aac -filter_complex "aresample=osf=s16,denoise" -ar 16000 -ac 1 -y OUTPUT.mp4 為例:

它們的實際資料流程如下圖所示:

 

圖6:-filter_complex "aresample=osf=s16,denoise"的濾鏡例項圖

 

從上圖可以看到,雖然我們只使用了兩個濾鏡,但構建出來的filterchain實際上包含有:五個filter, 和四個link;

是因為ffmpeg系統會自動為使用者設定的濾鏡新增上必要的輸入、輸出濾鏡,並將它們連線起來,組成一個完整的filterchain;

其中,ffmpeg預設是有3個filter的!分別是 "graph_0_in_0_0","format_out_0_0", "out_0_0"

它們對應的濾鏡型別是: “buffersrc”, “format”, “buffersink”。

它們對應的原始碼位於: libavfilter/buffersrc.c libavfilter/vf_format.c(對應視訊格式) libavfilter/format.c(對應音訊格式) , libavfilter/buffersink.c

 

 

上圖中:

藍色和綠色連線 是 AVFilterContext 與 AVFilterLink的連線關係 ;

紅色連線 是 AVFilterPad的連線關係;

灰色連線 是 組成AVFilterGraph的AVFilterContext;

 

上圖中,上半部分是filtergraph層:

左邊連線的是InputFilter,用來引入filtergraph的輸入流;

右邊連線的是OutputFilter,用來匯出filtergraph的輸出流;

並且指示了組成本filtergraph的所有filter;

 

上圖中,下半部分是filterchain層:

AVFilterContext與AVFilterLink是一種雙向連結串列指標的關係,見圖左的藍色和綠色連線所示;

即 AVFilterContext的 outputs 指向 它的下游 AVFilterLink;

而 下游的AVFilterLink的 src 批向它上游的 AVFilterContext;

 

4.2 FilterGraph 濾鏡圖結構體定義

typedef struct FilterGraph {
    int            index;
    const char    *graph_desc;

    AVFilterGraph *graph;                // 指向它的例項
    int reconfiguration;

    InputFilter   **inputs;
    int          nb_inputs;
    OutputFilter **outputs;
    int         nb_outputs;
} FilterGraph;

 

4.3 AVFilterGraph 濾鏡圖結構體定義

 

typedef struct AVFilterGraph {
    const AVClass *av_class;
    AVFilterContext **filters;                      // 本 濾鏡圖 包含的所有 filter, 包括系統自生成的
    unsigned              nb_filters;            

    char *scale_sws_opts;                            ///< sws options to use for the auto-inserted scale filters
#if FF_API_LAVR_OPTS
    attribute_deprecated char *resample_lavr_opts;   ///< libavresample options to use for the auto-inserted resample filters
#endif

    /**
     * Type of multithreading allowed for filters in this graph. A combination
     * of AVFILTER_THREAD_* flags.
     *
     * May be set by the caller at any point, the setting will apply to all
     * filters initialized after that. The default is allowing everything.
     *
     * When a filter in this graph is initialized, this field is combined using
     * bit AND with AVFilterContext.thread_type to get the final mask used for
     * determining allowed threading types. I.e. a threading type needs to be
     * set in both to be allowed.
     */
    int thread_type;

    /**
     * Maximum number of threads used by filters in this graph. May be set by
     * the caller before adding any filters to the filtergraph. Zero (the
     * default) means that the number of threads is determined automatically.
     */
    int nb_threads;

    /**
     * Opaque object for libavfilter internal use.
     */
    AVFilterGraphInternal *internal;

    /**
     * Opaque user data. May be set by the caller to an arbitrary value, e.g. to
     * be used from callbacks like @ref AVFilterGraph.execute.
     * Libavfilter will not touch this field in any way.
     */
    void *opaque;

    /**
     * This callback may be set by the caller immediately after allocating the
     * graph and before adding any filters to it, to provide a custom
     * multithreading implementation.
     *
     * If set, filters with slice threading capability will call this callback
     * to execute multiple jobs in parallel.
     *
     * If this field is left unset, libavfilter will use its internal
     * implementation, which may or may not be multithreaded depending on the
     * platform and build options.
     */
    avfilter_execute_func *execute;

    char *aresample_swr_opts;                    ///< swr options to use for the auto-inserted aresample filters, Access ONLY through AVOptions

    /**
     * Private fields
     *
     * The following fields are for internal use only.
     * Their type, offset, number and semantic can change without notice.
     */

    AVFilterLink **sink_links;
    int                   sink_links_count;

    unsigned disable_auto_convert;
} AVFilterGraph;

4.4. 視訊濾鏡型別的巨集定義

/**
 * 濾鏡輸入源的個數不能單由成員變數 AVFilter.inputs 來確定。
 * 即依賴於 options 的支援與否,這個濾鏡在初始化時可以新增額外的輸入源;
 */
#define AVFILTER_FLAG_DYNAMIC_INPUTS        (1 << 0)
/**
 * 濾鏡輸出目的的個數不能單由成員變數 AVFilter.outputs來確定。
 * 即依賴於 options 的支援與否,這個濾鏡在初始化時可以新增額外的輸出目的
 */
#define AVFILTER_FLAG_DYNAMIC_OUTPUTS       (1 << 1)
/**
 * 這個濾鏡通過將一幀劃分成多個部分,然後使用多執行緒來並行處理它們;
 */
#define AVFILTER_FLAG_SLICE_THREADS         (1 << 2)
/**
 *  有些濾鏡支援一個一般意義上的"enable"表示式選項。它可以用來在時間軸上開啟或關閉濾鏡。
 * 如果濾鏡支援這個選項就是設定這個標誌。
 * 當 enable 表示式為假時,預設的無操作的 filter_frame()函式將被呼叫,它會替換掉在每個輸入pad上定義的回撥函式 filter_frame(); 
 * 因此,這一幀不做任何處理地透傳到下一個濾鏡;
 */
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC  (1 << 16)
/**
 * 和 AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC一樣,
 *  有些濾鏡希望在 enable表示式為假時,呼叫自己的 filter_frame()回撥函式。
 *  例如,依據AVFilterCOntext->is_disable值,這個濾鏡會使用它自己的filter_frame()回撥來關閉它的處理。
*/
#define AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL (1 << 17)
/**
 * 用來測試濾鏡是否支援時間軸功能(internally or generically)的掩碼
 */
#define AVFILTER_FLAG_SUPPORT_TIMELINE (AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL)

4.5. AVFilter 結構體定義詳解

 

/**
 * 濾鏡定義。
 * 它定義了濾鏡與外部進行互動的pad(管腳,這個概念來自整合電腦,表示濾鏡和外部互動的介面),
 * 以及和本濾鏡進行互動的所有回撥函式;
 */
typedef struct AVFilter {
    /* 濾鏡名。必須是非空且唯一的; */
    const char *name;

    /* 濾鏡的描述,可以為空。 */
    const char *description;

    /**
     *  Pad :  輸入Pad列表,以零元素結束, 它是和它的上一個AVFilterLink的 dstpad 相連的;
     *  如果沒有(靜態的)輸入,則將其設定為空。
     *  如果濾鏡是  AVFILTER_FLAG_DYNAMIC_INPUTS  型別的例項,則在這個列表中可能有多個輸入
     */
    const AVFilterPad *inputs;
    /**
     * Pad :  輸出Pad列表,以零元素結束, 它是和它的下一個AVFilterLink的  srcpad 相連的;
     *  如果沒有(靜態的)輸出,則將其設定為空。
     *  如果濾鏡是 AVFILTER_FLAG_DYNAMIC_OUTPUTS 型別的例項,則在這個列表中可能有多個輸出
     */
    const AVFilterPad *outputs;

    /**
     *  私有資料類,用於宣告濾鏡私有的 AVoptions 結構體;
     *  如果濾鏡沒有任何可選項則將這個值初始化為NULL;
     *  如果這個值不為空,那麼濾鏡私有資料的第一個成員變數必須是 AVClass指標;
     */
    const AVClass *priv_class;

    /**
     * 濾鏡型別標誌  , 其值為 AVFILTER_FLAG_*   巨集定義
     */
    int flags;

    /*****************************************************************
     *  下面的變數不是公開的API,它們不能被libavfilter的外部使用
     *****************************************************************/

    /**
     *   回撥函式: 濾鏡預初始化函式
     *   當濾鏡的 context 被分配後,將立即呼叫這個回撥函式,來分配空間和初始化子物件。
     *  如果 這個回撥函式不為空, 當遇到空間分配失敗時將呼叫  uninit 回撥函式;
     *   返回值: 0, 表示成功
     *                  AVERROR,表示失敗,但是這個錯誤碼會被刪除,並被呼叫程式碼視為 ENOMEM 。
     */
    int (*preinit)(AVFilterContext *ctx);

    /**
     *   回撥函式: 濾鏡初始化函式
     *   在濾鏡的整個生命週期中,這個回撥函式只會在  所有可選項被設定後,濾鏡鏈建立及格式協調之前 被呼叫 一次。
     *   濾鏡本身的基本初始化可以放在這裡,
     *   ----- 意思是隻是初始化濾鏡本身的狀態,結構體,及本濾鏡專用的引數(如輸入引數再計算得到的引數)可以放在這裡;
     *          如果 這些初始化需要使用到本濾鏡外的(如上下游濾鏡,系統)引數,則需要把這樣的初始化放在 config_input()中;
     *          NOTE:輸入引數的預設值是在 static const AVOption xxxx_options[] 中設定的,不需要再單獨設定;
     * 
     *   如果濾鏡是多輸入/輸出型別的,那麼應該在這裡基於提供的可選項建立這些 inputs/outputs。
      *  對於濾鏡來說,當這個回撥被呼叫後,就不能再有濾鏡的inputs/outputs的改變了。
     *
      *  這個回撥函式它假設濾鏡鏈是有效的,或者幀引數是有效的
      *  AVFilter.uninit 指標指向的 uninit  函式  保證了即使初始化失敗時 ,這個函式將會被呼叫 , 因此失敗時這個回撥函式不需要清空
      *
      *  返回值: 0, 表示成功; 負數AVERROR,  表示失敗。
     
     */
    int (*init)(AVFilterContext *ctx);

    /**
     * Should be set instead of @ref AVFilter.init "init" by the filters that
     * want to pass a dictionary of AVOptions to nested contexts that are
     * allocated during init.
     *
     * On return, the options dict should be freed and replaced with one that
     * contains all the options which could not be processed by this filter (or
     * with NULL if all the options were processed).
     *
     * Otherwise the semantics is the same as for @ref AVFilter.init "init".
     *   回撥函式: 這個變數是被濾鏡設定,用來代替 AVFilter.init "init"  回撥函式,
     *           它會傳遞一個 AVOptions的字典 給 巢狀的 context (它是在初始化進分配的) 
     *  返回時,這個字典選項應當被釋放,且被一個包含所有選項的
     */
    int (*init_dict)(AVFilterContext *ctx, AVDictionary **options);

    /**
     * 回撥函式:  濾鏡釋放函式 , 它必須在濾鏡釋放前僅呼叫一次。
     *  在這個回撥函式中,應當釋放濾鏡的所有申請的記憶體,指標引用等。
     *  但它不需要去釋放 AVFilterContext.priv 記憶體空間本身;
     *  即便 AVFilter.init "init" 函式沒有被呼叫或呼叫失敗,這個函式也可能會被呼叫。
     *  因此,它必須能處理這種情況
     */
    void (*uninit)(AVFilterContext *ctx);

    /**
     *  回撥函式: 檢查本濾鏡輸入列表和輸出列表支援的格式。
     *  它是在濾鏡初始化後(這時輸入列表和輸出列表都固定了),格式協商之前被呼叫。它可以被呼叫多次。
     *
     *  在這個回撥函式中, 必須對每一個輸入link 設定  AVFilterLink.out_formats, 對每一個輸出link 設定 AVFilterLink.in_formats,
     *  列出這個濾鏡的link 支援的 畫素/樣本格式列表。
     * 對於音訊 link, 這個濾鏡還需要設定的引數有:  
     *             @ref AVFilterLink.in_samplerates "in_samplerates" /
     *             @ref AVFilterLink.out_samplerates "out_samplerates" and
     *             @ref AVFilterLink.in_channel_layouts "in_channel_layouts" /
     *             @ref AVFilterLink.out_channel_layouts "out_channel_layouts"
     * 
     *   如果濾鏡只有一個輸入,那這個回撥函式可以設定為空,
     *  在這種情況下, libavfilter假設它支援所有的輸入格式,並在輸出時保留它們
     * 
     *   返回值:  0, 表示成功; 負數,對應為AVERROR 碼
     */
    int (*query_formats)(AVFilterContext *);

    int priv_size;            ///<   濾鏡分配的私有資料的大小

    int flags_internal;     ///<  avfilter內部使用的額外的標誌

    /**
     *  它是被濾鏡註冊系統使用的,任何其它程式碼都不需要去操作它
     */
    struct AVFilter *next;

    /**
     *   讓濾鏡例項執行一個命令;
     *  引數: cmd   ,   要執行的命令,為簡化處理,所有命令必須僅為字母數字;
     *              arg   ,    命令的引數
     *             res    ,    大小為 res_size的buffer, 用於存放濾鏡的返回。當命令不支援時,不需要改變它。
     *            flags  ,     如果設定為 AVFILTER_CMD_FLAG_FAST, 且這個命令是有時間消耗的時,這個濾鏡將會不執行命令
     *  返回值:  >=0, 表示成功。   否則為錯誤碼,其中,AVERROR(ENOSYS) 為濾鏡不支援這個命令
     */
    int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags);

    /**
     *  回撥函式: 濾鏡初始化函式,它用來替代   init()回撥函式。
     *   引數中可以包含使用者提供的引數  :  opaque是用於傳輸二進位制資料
     */
    int (*init_opaque)(AVFilterContext *ctx, void *opaque);

    /**
     * Filter activation function.
     *
     * Called when any processing is needed from the filter, instead of any
     * filter_frame and request_frame on pads.
     *
     * The function must examine inlinks and outlinks and perform a single
     * step of processing. If there is nothing to do, the function must do
     * nothing and not return an error. If more steps are or may be
     * possible, it must use ff_filter_set_ready() to schedule another
     * activation.
     *  回撥函式: 濾鏡啟用函式
     *  當有處理需要這個濾鏡時,就會呼叫這個函式。
     */
    int (*activate)(AVFilterContext *ctx);
} AVFilter;

4.6 AVFilterContext 濾鏡例項的結構體

/** An instance of a filter */
struct AVFilterContext {
    const AVClass *av_class;                       ///< needed for av_log() and filters common options

    const AVFilter *filter;                              ///<  指明本例項是哪個AVFilter的例項

    char *name;                                          ///< 當前濾鏡例項的名稱 

    AVFilterPad   *input_pads;                    ///< 輸入Pad的陣列             array of input pads
    AVFilterLink  **inputs;                            ///< 輸入link的指標陣列       array of pointers to input links
    unsigned         nb_inputs;                          ///< 輸入Pad的個數             number of input pads

    AVFilterPad   *output_pads;                ///< 輸出Pad的陣列              array of output pads
    AVFilterLink **outputs;                        ///< 輸出link的指標陣列         array of pointers to output links
    unsigned        nb_outputs;                     ///<  輸出Pad的個數              number of output pads

    void *priv;                                          ///< 本濾鏡使用的私有資料    private data for use by the filter

    struct AVFilterGraph *graph;            ///< 指明本濾鏡是屬於哪個filtergraph 

    /**
     * Type of multithreading being allowed/used. A combination of
     * AVFILTER_THREAD_* flags.
     *
     * May be set by the caller before initializing the filter to forbid some
     * or all kinds of multithreading for this filter. The default is allowing
     * everything.
     *
     * When the filter is initialized, this field is combined using bit AND with
     * AVFilterGraph.thread_type to get the final mask used for determining
     * allowed threading types. I.e. a threading type needs to be set in both
     * to be allowed.
     *
     * After the filter is initialized, libavfilter sets this field to the
     * threading type that is actually used (0 for no multithreading).
     */
    int thread_type;

    /**
     * An opaque struct for libavfilter internal use.
     */
    AVFilterInternal *internal;

    struct AVFilterCommand *command_queue;

    char *enable_str;                      ///< enable expression string
    void *enable;                            ///< parsed expression (AVExpr*)
    double *var_values;                 ///< variable values for the enable expression
    int is_disabled;                        ///< the enabled state from the last expression evaluation

    /**
     * For filters which will create hardware frames, sets the device the
     * filter should create them in.  All other filters will ignore this field:
     * in particular, a filter which consumes or processes hardware frames will
     * instead use the hw_frames_ctx field in AVFilterLink to carry the
     * hardware context information.
     */
    AVBufferRef *hw_device_ctx;

    /**
     * Max number of threads allowed in this filter instance.
     * If <= 0, its value is ignored.
     * Overrides global number of threads set per filter graph.
     */
    int nb_threads;

    /**
     * Ready status of the filter.
     * A non-0 value means that the filter needs activating;
     * a higher value suggests a more urgent activation.
     */
    unsigned ready;

    /**
     * Sets the number of extra hardware frames which the filter will
     * allocate on its output links for use in following filters or by
     * the caller.
     *
     * Some hardware filters require all frames that they will use for
     * output to be defined in advance before filtering starts.  For such
     * filters, any hardware frame pools used for output must therefore be
     * of fixed size.  The extra frames set here are on top of any number
     * that the filter needs internally in order to operate normally.
     *
     * This field must be set before the graph containing this filter is
     * configured.
     */
    int extra_hw_frames;
};

4.7 AVFilterLink : 連結結構體定義

libavfilter/avfilter.h
/**
 *  兩個濾鏡之間的連結;
 *  如果兩個濾鏡是有連結的,則這個連結結構體包含有指向源濾鏡與目的濾鏡的指標,
 *  及 源濾鏡的輸出Pad,  和 目的濾鏡的輸入Pad 指標;
 *  另外,這個連結還包含有這個兩個濾鏡經過協商並匹配成功的引數,如影象的解析度,格式等;
 *
 *  應用程式不能直接去訪問連結結構體,而是使用 buffersrc   和  buffersink API 來訪問,如:
 *  
 */
struct AVFilterLink {
    AVFilterContext *src;                                  ///<  指向和它相連的上游的源濾鏡
    AVFilterPad *srcpad;                                  ///<  源Pad ,  和上游源濾鏡的 output_pad  相連

    AVFilterContext *dst;                                 ///< 指向和它相連的下游的目的濾鏡
    AVFilterPad *dstpad;                                ///<  目的Pad,    和下游目目的濾鏡的  innput_pad  相連 

    enum AVMediaType type;                        ///< Link的媒體型別   

    /*  視訊相關引數 */
    int w;                                                        ///< agreed upon image width
    int h;                                                        ///< agreed upon image height
    AVRational sample_aspect_ratio;            ///< agreed upon sample aspect ratio
    /* 音訊相關引數 */
    uint64_t channel_layout;                         ///< channel layout of current buffer (see libavutil/channel_layout.h)
    int sample_rate;                                      ///< samples per second

    int format;                                               ///< 協商後並匹配成功的媒體格式 ID 

    /**
     *  定義將通過此連結的 幀/樣本的PTS表示用的 時鐘基, 
     *  在配置階段,每個濾鏡應當只能改變輸出的時鐘基,而輸入的時鐘基是不可以更改的
     */
    AVRational time_base;

    /*****************************************************************
     *  下面的所有成員屬性與函式都不是公開API,它們不能被 libavfilter的外部使用
     *****************************************************************
     */
    /**
     *  輸入濾鏡與輸出濾鏡支援的格式、通道佈局、取樣率列表,這些列表用是用於實際的格式協商。
     *  當協商成功後,匹配的格式與通道佈局將會更新上面的 format 、channel_layout 、sample_rate 成員屬性;
     */
    AVFilterFormats                        *in_formats;
    AVFilterFormats                        *out_formats;

    AVFilterFormats                        *in_samplerates;
    AVFilterFormats                        *out_samplerates;

    struct AVFilterChannelLayouts  *in_channel_layouts;
    struct AVFilterChannelLayouts  *out_channel_layouts;

    /**
     *  僅用於音訊;
     *  輸出濾鏡會設定它為一個非零值,用於請求將有設定數量的樣本緩衝區傳送給它。
     *  此時,對應輸入Pad的 AVFilterPad.needs_fifo  也要做設定;
     *  EOF之前的最後一個buffer將會使用靜音資料填充;
     */
    int request_samples;

    /** stage of the initialization of the link properties (dimensions, etc) */
    enum {
        AVLINK_UNINIT = 0,        ///< not started
        AVLINK_STARTINIT,        ///< started, but incomplete
        AVLINK_INIT                    ///< complete
    } init_state;

    /**
     * 濾鏡所屬的濾鏡圖;
     */
    struct AVFilterGraph *graph;

    /**
     * 本連結的當前時間戳,由最近的幀定義,單位是 上面的 time_base;
     */
    int64_t current_pts;

    /**
     *  本連結的當前時間戳,由最近的幀定義,單位是 AV_TIME_BASE (即ffmpeg內部使用的時鐘基)
     */
    int64_t current_pts_us;

    /**
     * Index in the age array.
     */
    int age_index;

    /**
     * 本濾鏡鏈的流的幀率,當幀率是未知或可變時,設為 {1/0}; 
     * 如果設定為 {0/0}, 將會自動從源濾鏡的輸入複製得到;
     *
     * 源濾鏡應當將其設定為實際幀率的最佳估值。
     *  如果源濾鏡幀率是未知或是可變的,則將其設定為 {1/0}.
     *  如果有必要,濾鏡應當在它的處理函式中更新這個值;
     *  Sink型濾鏡可以用它來設定預設的輸出幀率;
      * 它和 AVStream中 的 r_frame_rate 類似;
     */
    AVRational frame_rate;

    /**
     * Buffer partially filled with samples to achieve a fixed/minimum size.
     *   
     */
    AVFrame *partial_buf;

    /**
     * Size of the partial buffer to allocate.Must be between min_samples and max_samples.
     * 
     */
    int partial_buf_size;

    /**
     *  濾鏡一次能處理的最小樣本數。
     *  如果呼叫  filter_frame() 函式  時 的樣本數小於這個值時,那這個函式將會在 partial_buf中將這些樣本累積起來。
     *  這個屬性值 及 相關的屬性在濾鏡初始化完成後就不能再更改了;
     *  如果設定為零,則所有相關的屬性都被忽略;
     */
    int min_samples;

    /**
     *  濾鏡一次能處理的最大樣本數。
     *  如果呼叫 filter_frame() 函式時的 樣本數大於這個值時,那這個函式要將樣本切分後再處理;
     */
    int max_samples;

    /**
     * 音訊通道的個數
     */
    int channels;

    /**
     * Link processing flags.  連結處理標誌
     */
    unsigned flags;

    /**
     *  通過連結的輸入的幀數,輸出的幀數;
     */
    int64_t frame_count_in, frame_count_out;

    /**
     * A pointer to a FFFramePool struct.
     */
    void *frame_pool;

    /**
     * True if a frame is currently wanted on the output of this filter.
     * Set when ff_request_frame() is called by the output,
     * cleared when a frame is filtered.
     *  如果當前幀希望從濾鏡輸出,則此值為真。
     */
    int frame_wanted_out;

    /**
     * For hwaccel pixel formats, this should be a reference to the
     * AVHWFramesContext describing the frames.
     */
    AVBufferRef *hw_frames_ctx;

#ifndef FF_INTERNAL_FIELDS

    /**
     * Internal structure members.
     * The fields below this limit are internal for libavfilter's use
     * and must in no way be accessed by applications.
     */
    char reserved[0xF000];

#else /* FF_INTERNAL_FIELDS */

    /**
     * Queue of frames waiting to be filtered.
     */
    FFFrameQueue fifo;

    /**
     * If set, the source filter can not generate a frame as is.
     * The goal is to avoid repeatedly calling the request_frame() method on
     * the same link.
     */
    int frame_blocked_in;

    /**
     * Link input status.
     * If not zero, all attempts of filter_frame will fail with the
     * corresponding code.
     */
    int status_in;

    /**
     * Timestamp of the input status change.
     */
    int64_t status_in_pts;

    /**
     * Link output status.
     * If not zero, all attempts of request_frame will fail with the
     * corresponding code.
     */
    int status_out;

#endif /* FF_INTERNAL_FIELDS */

};

4.8. AVFilterPad結構體定義

/**
 * @addtogroup lavu_media Media Type
 * @brief Media Type
 */

enum AVMediaType {
    AVMEDIA_TYPE_UNKNOWN = -1,  ///< Usually treated as AVMEDIA_TYPE_DATA
    AVMEDIA_TYPE_VIDEO,
    AVMEDIA_TYPE_AUDIO,
    AVMEDIA_TYPE_DATA,          ///< Opaque data information usually continuous
    AVMEDIA_TYPE_SUBTITLE,
    AVMEDIA_TYPE_ATTACHMENT,    ///< Opaque data information usually sparse
    AVMEDIA_TYPE_NB
};


/**
  *  一個 filter pad 就是一個濾鏡的輸入/輸出埠
 */
struct AVFilterPad {
    /**
     *  Pad名稱, 在輸入列表,或輸出列表內部必須是唯一的,但輸入列表,輸出列表之間可以重名。
     *  如果 這個 Pad  不會被以名稱引用,則其值可以為NULL。
     */
    const char *name;

    /**
     * AVFilterPad 型別 
     */
    enum AVMediaType type;

    /**
     *  獲得一個視訊 buffer的回撥函式,如果為空,則濾鏡系統會使用預設的  ff_default_get_video_buffer(); 
     *   只對輸入的視訊 Pad 有效
     */
    AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);

    /**
     *  獲得一個音訊 buffer的回撥函式,如果為空,則濾鏡系統會使用預設的 ff_default_get_audio_buffer(); 
     * 只對輸入的 音訊 Pad 有效
     */
    AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
    /**
     *  呼叫濾鏡進行處理的回撥函式:當濾鏡收到一幀 音訊/視訊 資料時,就要呼叫它進行處理。
     *  它是濾鏡處理的真正入口 , 只在輸入 pad中使用;
     *
     *  返回值: >=0, 表示成功,負數,為AVERROR的錯誤。
    *  這個函式必須確保 當濾鏡的處理出現錯誤時未被不合適地引用,且不會將錯誤傳遞到下一個濾鏡
     */
    int (*filter_frame)(AVFilterLink *link, AVFrame *frame);

    /**
     * Frame poll callback. This returns the number of immediately available
     * samples. It should return a positive value if the next request_frame()
     * is guaranteed to return one frame (with no delay).
     *
     * Defaults to just calling the source poll_frame() method.
     *   
     * Output pads only.
     *  回撥函式: 幀輪詢的回撥函式, 它返回當前有效的樣本個數;  只對輸出Pad有效;
     *  如果下一個 request_frame()函式是有幀資料返回,則它應該返回一個正數值;
     */
    int (*poll_frame)(AVFilterLink *link);

    /**
     * Frame request callback. A call to this should result in some progress
     * towards producing output over the given link. This should return zero
     * on success, and another value on error.
     *
     * Output pads only.
     *   回撥函式: 幀請求回撥函式。只對輸出Pad有效;
     *   如果呼叫 了這個回撥函式,應當在給定的link上生成經過處理後的輸出資料;
     *   返回值: 0,表示成功;否則為錯誤值;
     */
    int (*request_frame)(AVFilterLink *link);

    /**
     *   回撥函式:  用於link的配置的回撥函式
     *   對於 輸出 Pad, 它應當設定 link的屬性,如  width/height等。
     *   不要在這裡設定 格式 屬性;
     *   因為格式屬性是由濾鏡系統呼叫這個回撥函式之前,呼叫query_formats() 回撥函式在濾鏡間進行協調得到的。
     *   對於輸入 pad, 這個回撥函式是用檢查 link的屬性,並由此更新濾鏡內部的相關狀態;
     *  
     *  對於既有輸入,又有輸出的濾鏡,這個回撥函式在成功時返回零,其它返回值為出錯。
     */
    int (*config_props)(AVFilterLink *link);

    /**
     * 這個濾鏡需要有一個 FIFO插入它的輸入link,通常是因為這個濾鏡會有一個延遲的動作。
     *   只在輸入pad中使用
     */
    int needs_fifo;

    /**
     * 這個濾鏡需要從它的輸入 link中得到一個可寫的幀,如果有需要,會複製資料buffer
     *  只在輸入pad中使用
     */
    int needs_writable;
};