本系列文章居于FFMpeg源码4.1版本,因此,有些流程和老版本会有稍微差别(源码我做了详细注释,有需要请在下方评论留言,写明邮箱,我会统一发给你们)。
上一节说了过滤器涉及到的主要结构说明,这一节我们介绍下FFMpeg中过滤器涉及到的主要函数说明,把结构和函数讲完后,后面会从过滤器整体的机构来讲解,因此,这两节如果看不明白,只需要看个大概就行,后面说整体流程时会继续介绍其在整个流程中的位置和功能。
此函数通过传入的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)。
此函数首先通过ff_filter_alloc创建AVFilter对应的上下文结构AVFilterContext,然后把创建的AVFilterContext加入AVFilterGraph的列表filters的末尾,同时nb_filters的值加1(就是AVFilter的个数加1)。
此函数通过传入的AFFilter信息(过滤器结构、名称、参数等)创建一个过滤器的上下结构对象AVFilterContext,并把AVFilterContext加入负责管理过滤器的AVFilterGraph中,并设置过滤器的属性参数。
这个函数主要就是创建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的所有信息。
这个函数在源AVFilter处理完帧后调用,然后把处理后的AVFrame放入AVFilterLink的fifo队列,同时设置下一个AVFilter的ready优先级(必须大于0,这里设置的是300、200等),当AVFilterGraph再次进行调度时会取出优先级最高的AVFilter来进行处理。
分配AVFilterGraph对象,此对象负责管理加入的所有过滤器。
是否过滤器管理对象。
把需要处理的帧加入到buffer过滤器,注意,buffer过滤器是AVFilterGraph中第一个过滤器,其只有输出没有输入。
获取从AVFilterGraph管理的过滤器对象处理的帧AVFrame,此过程会经过所有的过滤器处理,最终处理的结果放入buffersink过滤器里的,因此这个buffersink过滤器是AVFilterGraph管理的过滤器中最后的一个过滤器,其只有输入,没有输出。
由av_buffersink_get_frame_flags调用获取最终处理好的AVFrame。
这个函数主要是从AVFilterGraph中找到优先级最大的一个AVFilterContext过滤器,然后使用此过滤器处理帧。
此函数一般由ff_filter_graph_run_once调用,因为ff_filter_graph_run_once负责找到优先级最大的过滤器,然后传给这个函数,然后此函数依次调用其输入inputs的filter_frame对输入的AVFrame进行处理,如果没有输入数据处理了,则调用其outputs的request_frame来把其处理后的帧交给下一个过滤器处理。
如果我们没有定义过滤器激活函数,则使用这个默认的激活函数来调用激活当前过滤器对数据进行处理。
这个函数主要处理过滤器的输入数据,如果过滤器实现了filter_frame,则调用filter_frame处理输入的帧,否则直接把输入的帧交给下一个过滤器(调用默认实现)。
此函数主要处理过滤器的输出数据(已经调用了ff_filter_frame_framed处理了输入数据),其调用request_frame来做预处理,比如设置下一个过滤器的优先级(设置一个大于0的数,表示过滤器下一步需要激活),如果没有实现request_frame,则调用默认实现函数ff_request_frame处理。
本系列文章均为原创,主要总结作者多年在软件行业的一些经验,和大家共同学习、进步,转载请注明出处,谢谢!