ffmpeg-AVFilter 和 Filter Graph 使用指南
FFmpeg 的 libavfilter
是一个强大的多媒体滤镜处理框架,允许你对音视频流进行各种处理(如缩放、裁剪、格式转换、混音等)。以下是关于 AVFilter 和 Filter Graph 的核心用法。
1. 基本概念
AVFilter: 单个滤镜(如
scale
、trim
、overlay
)AVFilterContext: 滤镜实例
AVFilterGraph: 滤镜图,包含多个滤镜和它们的连接关系
AVFilterInOut: 表示滤镜图的输入/输出
2. 基本使用流程
2.1 创建滤镜图
c
AVFilterGraph *filter_graph = avfilter_graph_alloc(); if (!filter_graph) {// 错误处理 }
2.2 创建并添加滤镜
c
AVFilterContext *src_ctx; AVFilterContext *sink_ctx; AVFilter *src_filter = avfilter_get_by_name("buffer"); AVFilter *sink_filter = avfilter_get_by_name("buffersink");// 创建源滤镜(输入) char args[512]; snprintf(args, sizeof(args),"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d",width, height, pix_fmt,time_base.num, time_base.den,sar.num, sar.den);avfilter_graph_create_filter(&src_ctx, src_filter, "in", args, NULL, filter_graph);// 创建接收滤镜(输出) avfilter_graph_create_filter(&sink_ctx, sink_filter, "out", NULL, NULL, filter_graph);
2.3 创建并连接滤镜链
c
AVFilterContext *scale_ctx; AVFilter *scale_filter = avfilter_get_by_name("scale");// 创建缩放滤镜 avfilter_graph_create_filter(&scale_ctx, scale_filter, "scale", "w=640:h=480", NULL, filter_graph);// 连接滤镜 avfilter_link(src_ctx, 0, scale_ctx, 0); avfilter_link(scale_ctx, 0, sink_ctx, 0);
2.4 配置滤镜图
c
if (avfilter_graph_config(filter_graph, NULL) < 0) {// 配置失败处理 }
3. 字符串方式配置滤镜图
FFmpeg 也支持用字符串描述滤镜图,更简洁:
c
char *filter_descr = "scale=w=640:h=480,format=yuv420p"; AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc();// 设置输入输出 outputs->name = av_strdup("in"); outputs->filter_ctx = src_ctx; outputs->pad_idx = 0; outputs->next = NULL;inputs->name = av_strdup("out"); inputs->filter_ctx = sink_ctx; inputs->pad_idx = 0; inputs->next = NULL;if (avfilter_graph_parse_ptr(filter_graph, filter_descr,&inputs, &outputs, NULL) < 0) {// 错误处理 }avfilter_inout_free(&inputs); avfilter_inout_free(&outputs);
4. 使用滤镜图处理帧
4.1 向滤镜图输入帧
c
AVFrame *frame = av_frame_alloc(); // 填充frame数据...if (av_buffersrc_add_frame(src_ctx, frame) < 0) {// 错误处理 } av_frame_free(&frame);
4.2 从滤镜图获取处理后的帧
c
AVFrame *filtered_frame = av_frame_alloc(); int ret = av_buffersink_get_frame(sink_ctx, filtered_frame); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {// 需要更多输入或已结束 } else if (ret < 0) {// 错误处理 } else {// 使用处理后的帧// ...av_frame_unref(filtered_frame); } av_frame_free(&filtered_frame);
5. 音频滤镜示例
c
// 创建音频源滤镜 snprintf(args, sizeof(args),"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64,1, sample_rate, sample_rate,av_get_sample_fmt_name(sample_fmt), channel_layout); avfilter_graph_create_filter(&src_ctx, avfilter_get_by_name("abuffer"), "in", args, NULL, filter_graph);// 创建音频接收滤镜 enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }; avfilter_graph_create_filter(&sink_ctx, avfilter_get_by_name("abuffersink"),"out", NULL, NULL, filter_graph); av_opt_set_int_list(sink_ctx, "sample_fmts", sample_fmts, AV_SAMPLE_FMT_NONE, AV_OPT_SEARCH_CHILDREN);
6. 复杂滤镜图示例
c
// 画中画效果 char *filter_descr = "[in1]scale=w=320:h=240[scaled];""[in2][scaled]overlay=x=main_w-overlay_w-10:y=main_h-overlay_h-10[out]";// 分屏效果 char *filter_descr = "[in1]scale=w=iw/2:h=ih[left];""[in2]scale=w=iw/2:h=ih[right];""[left][right]hstack[out]";
7. 清理资源
c
avfilter_graph_free(&filter_graph);
8. 常见问题
滤镜图配置失败:检查滤镜名称是否正确,参数格式是否合法
帧处理错误:确保输入帧的格式与滤镜源配置一致
内存泄漏:确保正确释放所有分配的资源
性能问题:复杂的滤镜图可能影响性能,尽量简化或分步处理
9. 实用技巧
使用
avfilter_graph_dump()
可以打印滤镜图结构,便于调试FFmpeg 命令行工具中的滤镜语法与代码中的基本一致
参考
ffmpeg_filter.c
等官方示例代码
通过灵活使用 AVFilter,你可以实现各种复杂的音视频处理效果,而无需自己编写底层算法。