5月28日 00:16
FFmpeg的filter机制是怎样的?如何应用于实际场景?
FFmpeg 的 filter 机制是基于 libavfilter 库实现的音视频帧处理框架,通过 filtergraph(滤镜图)组织数据流,支持链式串联多个处理单元完成转码、特效、混流等操作。
核心概念
FFmpeg filter 机制包含三个层次:filter(滤镜)→ filterchain(滤镜链)→ filtergraph(滤镜图)。
- filter:最小处理单元,如 scale、crop、overlay,每个 filter 接收输入帧、执行变换、输出帧。
- filterchain:多个 filter 以逗号串联,形成线性处理流水线。例如
scale=1280:720,crop=1200:680。 - filtergraph:由一条或多条 filterchain 组成,chain 之间用分号分隔,通过标签(方括号)连接数据流。支持分支和合并。
filter 按数据流向分为三类:
- source filter:只有输出无输入,如 buffersrc、mptestsrc,用于产生数据流。
- sink filter:只有输入无输出,如 buffersink,用于消费数据流。
- 常规 filter:有输入有输出,如 scale、volume。
命令行通过 -vf(视频滤镜)指定简单 filtergraph(单输入单输出),通过 -filter_complex 或 -lavfi 指定复杂 filtergraph(多输入多输出)。
核心工作流程
- 输入解析:demuxer 解封装得到编码包,decoder 解码为原始帧(YUV/PCM)。
- 滤镜处理:帧进入 filtergraph,沿 filterchain 依次处理,filtergraph 解析描述字符串动态构建处理图。
- 输出编码:处理后的帧经 encoder 编码、muxer 封装写入目标。
关键设计:filtergraph 在运行时解析字符串描述自动构建图结构并优化数据流传输,无需预编译。
常见应用场景
视频处理
分辨率适配:scale 滤镜缩放,pad 滤镜补黑边保持比例。
bashffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2" output.mp4
水印叠加:overlay 滤镜实现图层合成。
bashffmpeg -i video.mp4 -i logo.png -filter_complex "overlay=10:10" output.mp4
音频处理
音量与淡入淡出:volume + afade 组合。
bashffmpeg -i audio.mp3 -af "volume=0.5,afade=t=in:st=0:d=2" output.mp3
多轨混音:amix 混合多路音频。
bashffmpeg -i a1.mp3 -i a2.mp3 -filter_complex "amix=inputs=2:duration=longest" output.mp3
复杂滤镜图
经典示例:输入分为两路,一路裁剪翻转后叠加回原画面。
bashffmpeg -i INPUT -vf "split[main][tmp];[tmp]crop=iw:ih/2:0:0,vflip[flip];[main][flip]overlay=0:H/2" OUTPUT
语法要点:逗号分隔同一链内 filter,分号分隔不同 chain,方括号标签连接 chain 间的数据流。
实时流处理
bashffmpeg -re -i rtsp://input -vf "scale=1280:720" -c:v libx264 -preset fast -f rtsp rtsp://output
性能优化要点
- 最小化 filter 数量:避免冗余 filter(如重复 scale),减少帧拷贝开销。
- force_original_aspect_ratio:缩放时使用
decrease参数防止失真。 - 线程控制:
-threads限制并发数,避免 CPU 争抢。 - 基准测试:
-benchmark评估 filterchain 效率。
底层实现
libavfilter 的核心数据结构:
AVFilter:滤镜描述符,定义滤镜名称、参数、初始化/处理函数。AVFilterContext:滤镜实例,运行时状态。AVFilterLink:连接相邻滤镜的数据链路,协商格式和缓冲区。AVFilterPad:滤镜的输入/输出端口。
处理模型为"拉取"式:sink filter 向上游请帧,帧沿 filterchain 依次处理后返回。这种模型避免了上游过度生产导致的内存膨胀。