本文详细讲解了要创建简单和复杂两种滤波器的过程,所用到的api。重点了解如何用字符串创建复杂滤波器.
1.创建简单的滤波过程
第一步:得到所需的滤波器(AVFilter),buffer和buffersink作为输入、输出的滤波器。
avfilter_get_by_name()根据名字搜索对应滤波器
c
const AVFilter *buffersrc = avfilter_get_by_name("buffer");
const AVFilter *buffersink = avfilter_get_by_name("buffersink");
const AVFilter *myfilter = avfilter_get_by_name("myfilter");
第二步:声明整个滤波过程的滤波图结构体
c
filter_graph = avfilter_graph_alloc();
第三步:创建滤波器实例(AVFilterContext)
c
AVFilterContext *in_video_filter = NULL;
AVFilterContext *out_video_filter = NULL;
AVFilterContext *my_video_filter = NULL;
avfilter_graph_create_filter(&in_video_filter, buffersrc, "in", args,NULL, filter_graph);
avfilter_graph_create_filter(&out_video_filter, buffersink, "out", NULL, NULL, filter_graph);
avfilter_graph_create_filter(&my_video_filter, myfilter, "myfilter",NULL, NULL, filter_graph);
第四步:⽤AVFilterLink把相邻的两个滤波实例连接起来,注意函数输入里的0,表示通道,可以创建多个通道。
c
avfilter_link(in_video_filter, 0, my_video_filter, 0);
avfilter_link(my_video_filter, 0, out_video_filter, 0);
第五步:最后一定要提交整个滤波图,这样才会生效
c
avfilter_graph_config(filter_graph, NULL);
2.创建复杂的滤波过程
复杂的滤波过程,采取前一小节创建方式效率不高,需采用字符串进行描述。
c
[0]trim=start_frame=10:end_frame=20[v0];\
[0]trim=start_frame=30:end_frame=40[v1];\
[v0][v1]concat=n=2[v2];\
[1]hflip[v3];\
[v2][v3]overlay=eof_action=repeat[v4];\
[v4]drawbox=50:50:120:120:red:t=5[v5]
整体过程和前一小节类似进行创建:
第一步:声明整个滤波过程的滤波图结构体
c
filter_graph = avfilter_graph_alloc();
第二步:把输入和过滤器命令的参数打印到filter_args里。
第一种写法:输入输出定义好
cpp
snprintf(filter_args, sizeof(filter_args),
"buffer=video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d[v0];" // Parsed_buffer_0
"[v0]trim=start_frame=10:end_frame=20[v1];" // Parsed_trim_1
"[v0]trim=start_frame=30:end_frame=40[v2];" // Parsed_trim_2
"[v1][v2]concat=n=2[v3];"// Parsed_concat_3
"[v2]hflip[v4];"// Parsed_gflip_4
"[v3][v4]overlay=eof_action=repeat[v5];"// Parsed_overlay_5
"[v5]drawbox=50:50:120:120:red:t=5[v6];"// Parsed_drawbox_6
"[v6]buffersink", // Parsed_buffersink_7
width, height, format, 1, 25, 1, 1);
)
第二种,不写输入输出
c
snprintf(filter_args, sizeof(filter_args),
"[v0]trim=start_frame=10:end_frame=20[v1];" // Parsed_trim_1
"[v0]trim=start_frame=30:end_frame=40[v2];" // Parsed_trim_2
"[v1][v2]concat=n=2[v3];"// Parsed_concat_3
"[v2]hflip[v4];"// Parsed_gflip_4
"[v3][v4]overlay=eof_action=repeat[v5];"// Parsed_overlay_5
"[v5]drawbox=50:50:120:120:red:t=5[v6]"// Parsed_drawbox_6);
)
第三步:对前面字符串进行解析,并构建滤波图。
第一种:
c
avfilter_graph_parse2(filter_graph, graph_desc, &inputs, &outputs);
在该例子中已经写好了输入Buffer和输出buffersink,所以之后直接提交过滤器就可以。建议使用第一种
第二种没写输入输出,如下:
其中,inputs和outputs为输入、输出的接口集合。
c
for (cur = inputs, i = 0; cur; cur = cur->next, i++) {
const AVFilter *buffersrc = avfilter_get_by_name("buffer");
avfilter_graph_create_filter(&filter, buffersrc, name, args, NULL, filter_graph);
avfilter_link(filter, 0, filter_graph, cur->pad_idx);
}
avfilter_inout_free(&inputs);
for (cur = outputs, i = 0; cur; cur = cur->next, i++) {
const AVFilter *buffersink = avfilter_get_by_name("buffersink");
avfilter_graph_create_filter(&filter, buffersink, name, NULL, NULL, filter_graph);
avfilter_link(filter_graph, cur->pad_idx, filter, 0);
}
avfilter_inout_free(&outputs);
第三步:提交整个滤波图,这样才会生效
avfilter_graph_config(filter_graph, NULL);
3.帧的传入传出
传入:向指定的buffersrc实例输⼊想要进⾏滤波的帧。
c
av_buffersrc_add_frame(c->in_filter, pFrame);
传出:从指定的buffersink实例提取滤波完成的帧
c
av_buffersink_get_frame(c->out_filter, pFrame);
av_buffersink_get_frame返回值⼤于0则表示提取成功。