ffmpeg的filter⽤起来是和Gstreamer的plugin是⼀样的概念,通过avfilter_link,将各个创建好的filter按
⾃⼰想要的次序链接到⼀起,然后avfilter_graph_config之后,就可以正常使⽤。
⽐较常⽤的滤镜有:scale、trim、overlay、rotate、movie、yadif。scale 滤镜⽤于缩放,trim 滤镜⽤
于帧级剪切,overlay 滤镜⽤于视频叠加,rotate 滤镜实现旋转,movie 滤镜可以加载第三⽅的视频,
yadif 滤镜可以去隔⾏
1、主要结构体和API介绍
1.1 AVFilterGraph-对filters系统的整体管理
AVFilterGraph是FFmpeg中用于管理音视频滤镜的数据结构。它表示一个完整的滤镜图,可以包含多个输入输出,并通过连接不同的滤镜节点来实现各种音视频处理操作。
AVFilterGraph提供了创建、配置和管理滤镜的接口,允许用户构建复杂的滤镜拓扑结构,以实现音视频的处理和编辑。通AVFilterGraph,用户可以添加各种滤镜(如变换、剪切、合并、调节等)并将它们连接起来,最终实现所需的音视频处理效果。
在使用AVFilterGraph时,通常的流程包括创建滤镜图、添加输入输出流、添加滤镜节点、连接滤镜节点、设置参数等。一旦完成了滤镜图的构建,就可以将音视频帧送入滤镜图进行处理,最终得到处理后的输出。
**重点
struct AVFilterGraph
{
AVFilterContext filters;
unsigned nb_filters;
}
1.2 AVFilter-定义filter本身的能⼒
AVFilter 是 FFmpeg 中用于实现音视频滤镜的基本单位。它代表了一个特定的音视频处理功能,比如色彩转换、尺寸调整、去噪等。AVFilter 可以单独使用,也可以通过 AVFilterGraph 组合成复杂的滤镜链。
AVFilter 结构的作用主要是定义了一个滤镜的基本属性和行为,以及提供了滤镜初始化、销毁、格式查询等相关的回调函数接口。通过这些接口,用户可以对滤镜进行初始化配置,并将其应用到音视频流数据上,实现各种音视频处理效果。
在使用 AVFilter 时,通常的步骤包括:
- 创建 AVFilterContext 对象,表示一个具体的 AVFilter 实例。
- 设置滤镜参数和选项,可以通过 priv_class定义的私有类进行配置。
- 连接输入输出端口,将 AVFilterContext 对象连接到其他滤镜或音视频流中。
- 将音视频帧数据送入滤镜进行处理,得到处理后的输出数据。
重点
**const char *name; // overlay
const AVFilterPad inputs;
const AVFilterPad outputs;
cpp
typedef struct AVFilter {
const char *name; //滤镜的名称,用于唯一标识滤镜。
const char *description; //对滤镜功能的文字描述。
const AVFilterPad *inputs; //
const AVFilterPad *outputs;
const AVClass *priv_class; //用于指定滤镜的私有类,定义了滤镜的参数和选项。
int flags;
int (*preinit)(AVFilterContext *ctx);
int (*init)(AVFilterContext *ctx); //用于初始化滤镜的回调函数,可以在滤镜被创建时执行一些初始化操作。
int (*init_dict)(AVFilterContext *ctx, AVDictionary **options);
void (*uninit)(AVFilterContext *ctx); //用于销毁滤镜的回调函数,在滤镜不再需要时执行清理操作。
int (*query_formats)(AVFilterContext *); //用于查询支持的输入输出格式的回调函数。
int priv_size; //滤镜私有数据的大小,用于分配存储私有数据的内存空间。
int flags_internal; ///< Additional flags for avfilter internal use only.
struct AVFilter *next;
int (*process_command)(AVFilterContext *, const char *cmd, const char *arg, char *res, int res_len, int flags);
int (*init_opaque)(AVFilterContext *ctx, void *opaque);
int (*activate)(AVFilterContext *ctx);
} AVFilter;
1.3 AVFilterContext-filter实例,管理filter与外部的联系
AVFilterContext 是 FFmpeg 中用于表示一个特定 AVFilter 实例的数据结构。它包含了一个 AVFilter 的所有信息和状态,以便在音视频处理中对该滤镜进行配置、连接和处理。
AVFilterContext 结构的作用是管理一个 AVFilter 实例的输入输出端口,通过输入端口接收数据并经过滤镜处理后输出到输出端口。它还负责与滤镜图(AVFilterGraph)进行交互,将滤镜上下文与其他滤镜连接起来以实现复杂的音视频处理链。
在使用 AVFilterContext 时,通常的步骤包括:
- 创建 AVFilterContext 对象,可以通过 avfilter_alloc_context() 函数创建。
- 配置 AVFilterContext 的输入输出端口,可以通过 avfilter_link() 函数连接输入输出端口。
- 设置滤镜参数和选项,可以通过 AVFilterContext 的属性进行配置。
- 将音视频帧数据送入 AVFilterContext 进行处理,得到处理后的输出数据。
**重点
struct AVFilterContext
{
const AVFilter *filter;
char *name;
AVFilterPad *input_pads;
AVFilterLink **inputs;
unsigned nb_inputs
AVFilterPad *output_pads;
AVFilterLink *outputs;
unsigned nb_outputs;
struct AVFilterGraph graph; // 从属于哪个AVFilterGraph
}
1.4 AVFilterLink-定义两个filters之间的联接
AVFilterLink用于连接滤镜图中两个滤镜之间的输入和输出。它包含了连接两个滤镜所需的所有信息,例如输入和输出的样本格式、缓冲区、时间戳等等。AVFilterLink还包含了有关滤镜链中帧的信息,如PTS(Presentation Time Stamp,显示时间戳)和DTS(Decoding Time Stamp,解码时间戳)。通过AVFilterLink,不同的滤镜可以在滤镜图中相互连接,从而实现视频和音频处理的各种功能。
**重点
struct AVFilterLink
{
AVFilterContext *src;
AVFilterPad *srcpad;
AVFilterContext *dst;
AVFilterPad dstpad;
struct AVFilterGraph graph;
}
1.5 AVFilterPad-定义filter的输⼊/输出接⼝
AVFilterPad是FFmpeg中的结构,用于描述滤镜的输入或输出端口。滤镜可以有多个输入和输出端口,每个端口都由一个AVFilterPad结构表示。该结构包含了端口的名称、类型(输入或输出)、滤镜所支持的样本格式、是否支持多通道等信息。
在滤镜图中,滤镜之间的连接通过连接它们的输入和输出端口来实现。因此,AVFilterPad在滤镜之间建立连接时起到了关键的作用。通过AVFilterPad,FFmpeg能够正确地识别滤镜之间的连接,从而实现音视频数据的流动和处理。
**重点
struct AVFilterPad
{
const char *name;
AVFrame *(*get_video_buffer)(AVFilterLink *link, int w, int h);
AVFrame *(*get_audio_buffer)(AVFilterLink *link, int nb_samples);
int (*filter_frame)(AVFilterLink *link, AVFrame *frame);
int (request_frame)(AVFilterLink link);
}
1.6AVFilterInOut-过滤器链输⼊/输出的链接列表
在AVFilter模块中定义了AVFilter结构,很个AVFilter都是具有独⽴功能的节点,如scale filter的作⽤就是进⾏图像尺⼨变换,overlay filter的作⽤就是进⾏图像的叠加。
这⾥需要重点提的是两个特别的filter,⼀个是buffer,⼀个是buffersink,
- 滤波器buffer代表filter graph中的源头,原始数据就往这个filter节点输⼊的;
- ⽽滤波器buffersink代表filter graph中的输出节点,处理完成的数据从这个filter节点输出。
cpp
typedef struct AVFilterInOut {
/** unique name for this input/output in the list */
char *name;
/** filter context associated to this input/output */
AVFilterContext *filter_ctx;
/** index of the filt_ctx pad to use for linking */
int pad_idx;
/** next input/input in the list, NULL if this is the last */
struct AVFilterInOut *next;
} AVFilterInOut;
2、函数使用
2.1 获取指定名称的滤镜--avfilter_get_by_name
// 获取FFmpeg中定义的filter,调⽤该⽅法前需要先调⽤avfilter_register_all();进⾏滤波器注册
AVFilter avfilter_get_by_name(const char name);
如果找到了指定名称的滤镜,该函数将返回一个指向对应AVFilter结构体的指针。如果未找到匹配的滤镜,函数将返回NULL。
2.2 向FFmpeg中的缓冲源滤镜(Buffer Source Filter)添加视频帧或音频帧--av_buffersrc_add_frame
cpp
/*
*参数ctx是指向Buffer Source Filter的AVFilterContext结构体指针,通过它可以访问和控制Buffer Source Filter的属性和状态。
*参数frame是要添加到Buffer Source Filter中的AVFrame结构体指针,它包含了要添加的视频帧或音频帧的数据和相关信息。
*函数返回一个整数值,表示操作是否成功。如果成功添加帧数据,则返回0;如果发生错 误,则返回负值。
*/
int av_buffersrc_add_frame(AVFilterContext ctx, AVFrame frame);
通过调用av_buffersrc_add_frame函数,你可以将视频帧或音频帧添加到Buffer Source Filter中,从而使得该帧数据成为滤镜链的输入。
2.3 从缓冲汇滤镜(Buffer Sink Filter)中获取输出帧数据--
av_buffersink_get_frame
cpp
/*
*参数 ctx 是指向 Buffer Sink Filter 的 AVFilterContext 结构体指针,通过它可以访问和控制 Buffer Sink Filter 的属性和状态。
*函数返回一个指向 AVFrame 结构体的指针,该结构体包含了从 Buffer Sink Filter 中获取的输出帧数据。如果没有可用的输出帧数据,函数将返回 NULL。
*/
int av_buffersink_get_frame(AVFilterContext ctx, AVFrame frame);
2.4 分配并初始化一个空的滤镜图--avfilter_graph_alloc
cpp
//分配并初始化一个空的滤镜图`在这里插入代码片`
AVFilterGraph *avfilter_graph_alloc(void);
在使用滤镜图进行音视频处理时,首先需要通过 avfilter_graph_alloc 分配一个滤镜图,然后在该滤镜图上添加各种滤镜节点,构建滤镜链,最后配置和链接这些滤镜节点,从而完成音视频处理任务。
2.5 在滤镜图中创建一个新的滤镜--avfilter_graph_create_filter
cpp
/*
* filt_ctx: 指向指针的指针,用于返回创建的滤镜实例的 AVFilterContext 结构体指针。
* filt: 要创建的滤镜的 AVFilter 结构体指针。
* name: 滤镜实例的名称。
* args: 滤镜实例的参数,可以是滤镜实例初始化时需要的参数字符串。
* opaque: 不透明指针,可以传递给滤镜的初始化函数。
* graph_ctx: 滤镜图的上下文 AVFilterGraph 结构体指针,表示滤镜实例将要被添加到的滤镜图。
* 该函数返回一个整数值,表示操作是否成功。如果成功创建滤镜实例并将其添加到滤镜图中,则返回0;如果发生错误,则返回负值。
*/
int avfilter_graph_create_filter(AVFilterContext **filt_ctx,
const AVFilter *filt,const char name,
const char args, void *opaque,
AVFilterGraph *graph_ctx);
avfilter_graph_create_filter函数用于在滤镜图中创建一个新的滤镜实例,并将其添加到滤镜链中。通过调用 avfilter_graph_create_filter 函数,可以在滤镜图中创建一个指定类型的滤镜实例,并配置其参数。
2.6 在滤镜图中连接两个滤镜--avfilter_link
cpp
/*
* src: 源滤镜的 AVFilterContext 结构体指针,表示连接的起始滤镜。
* srcpad: 源滤镜的输出端口索引,表示连接的起始滤镜的输出端口。
* dst: 目标滤镜的 AVFilterContext 结构体指针,表示连接的目标滤镜。
* dstpad: 目标滤镜的输入端口索引,表示连接的目标滤镜的输入端口。
* 该函数返回一个整数值,表示连接是否成功。如果成功连接两个滤镜,则返回0;如果发生错误,则返回负值。
*/
int avfilter_link(AVFilterContext *src, unsigned srcpad,AVFilterContext *dst, unsigned dstpad);
通过调用 avfilter_link 函数,可以在滤镜图中连接两个滤镜,从而构建滤镜链。连接的源滤镜的输出端口将与目标滤镜的输入端口相连。连接后,数据将从源滤镜流向目标滤镜,进行进一步的处理。
3、 AVFilter主体框架流程
在利⽤AVFilter进⾏⾳视频数据处理前先将在进⾏的处理流程绘制出来,现在以FFmpeg filter官⽅⽂档中的⼀个例⼦为例进⾏说明。
这个例⼦的处理流程如上所示,⾸先使⽤split滤波器将input流分成两路流(main和tmp),然后分别对两路流进⾏处理。对于tmp流,先经过crop滤波器进⾏裁剪处理,再经过flip滤波器进⾏垂直⽅向上的翻转操作,输出的结果命名为flip流。再将main流和flip流输⼊到overlay滤波器进⾏合成操作。上图的input就是上⾯提过的buffer源滤波器,output就是上⾯的提过的buffersink滤波器。上图中每个节点都是⼀个AVFilterContext,每个连线就是AVFliterLink。所有这些信息都统⼀由AVFilterGraph来管理。