ffmpeg-AVFilter 和 Filter Graph 使用指南

发布于:2025-08-14 ⋅ 阅读:(25) ⋅ 点赞:(0)

FFmpeg 的 libavfilter 是一个强大的多媒体滤镜处理框架,允许你对音视频流进行各种处理(如缩放、裁剪、格式转换、混音等)。以下是关于 AVFilter 和 Filter Graph 的核心用法。

1. 基本概念

  • AVFilter: 单个滤镜(如 scaletrimoverlay

  • 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. 常见问题

  1. 滤镜图配置失败:检查滤镜名称是否正确,参数格式是否合法

  2. 帧处理错误:确保输入帧的格式与滤镜源配置一致

  3. 内存泄漏:确保正确释放所有分配的资源

  4. 性能问题:复杂的滤镜图可能影响性能,尽量简化或分步处理

9. 实用技巧

  • 使用 avfilter_graph_dump() 可以打印滤镜图结构,便于调试

  • FFmpeg 命令行工具中的滤镜语法与代码中的基本一致

  • 参考 ffmpeg_filter.c 等官方示例代码

通过灵活使用 AVFilter,你可以实现各种复杂的音视频处理效果,而无需自己编写底层算法。


网站公告

今日签到

点亮在社区的每一天
去签到