1. 核心组件关系
PyAV 的滤镜系统是对 FFmpeg libavfilter 的封装,采用图(Graph)模型:
Graph (滤镜图容器)
├── FilterContext (滤镜实例节点)
│ ├── FilterPad (输入/输出端口定义)
│ └── FilterLink (节点间连接线)
└── Buffer/BufferSink (数据入口/出口)
💡 核心原则:视频帧通过
vpush()进入 Graph,经过一系列 FilterContext 处理后,通过vpull()取出。Graph 必须先configure()才能推拉数据。
2. Graph:视频滤镜图操作
构建与配置
graph = av.filter.Graph()
# 1. 添加视频缓冲入口(必须指定尺寸和格式)
buffer = graph.add_buffer(width=1920, height=1080, format='yuv420p', time_base=Fraction(1, 30))
# 2. 添加视频滤镜节点
scale = graph.add('scale', '640:360')
fps = graph.add('fps', fps=25)
# 3. 添加视频缓冲出口
sink = graph.add('buffersink')
# 4. 连接节点(简洁链式写法)
graph.link_nodes(buffer, scale, fps, sink)
# 5. 配置图(验证连接、协商格式)
graph.configure()
核心方法速查
⚠️ vpush/vpull 使用要点
vpull()可能返回None:某些滤镜(如 fps、overlay)需要累积多帧才输出一帧vpush()后应循环vpull()直到返回None,避免帧积压图未
configure()前调用 push/pull 会抛异常
3. FilterContext:滤镜节点管理
手动连接(复杂拓扑)
当 link_nodes 无法满足需求时(如多输入 overlay、分支图):
# 手动连接:src 的输出端口 → dst 的输入端口
src.link_to(dst, output_idx=0, input_idx=0)
# overlay 示例:base 连 pad 0,overlay 连 pad 1
base_ctx.link_to(overlay_ctx, output_idx=0, input_idx=0)
logo_ctx.link_to(overlay_ctx, output_idx=0, input_idx=1)
节点属性
4. Filter:滤镜描述符查询
在构建图之前查询滤镜能力,避免运行时错误:
f = av.filter.Filter('overlay')
print(f.inputs) # [FilterPad(name='main', type='video'), FilterPad(name='overlay', type='video')]
print(f.dynamic_inputs) # False
print(f.timeline_support) # True → 可用 enable='between(t,1,5)'
5. FilterPad & FilterLink
FilterPad(端口定义)
FilterContextPad(运行时端口)
FilterLink(连接)
💡 调试技巧:遍历
context.inputs检查pad.linked可快速定位未连接的断点。
6. 视频滤镜常见工作流
缩放 + 帧率转换
graph = av.filter.Graph()
buf = graph.add_buffer(template=input_frame)
scale = graph.add('scale', '1280:720:flags=bilinear')
fps = graph.add('fps', fps=30)
sink = graph.add('buffersink')
graph.link_nodes(buf, scale, fps, sink)
graph.configure()
graph.vpush(input_frame)
while (out := graph.vpull()) is not None:
process(out)
视频叠加(Overlay)
graph = av.filter.Graph()
base_buf = graph.add_buffer(template=base_frame, name='base_in')
logo_buf = graph.add_buffer(template=logo_frame, name='logo_in')
overlay = graph.add('overlay', '10:10:enable=between(t,0,5)')
sink = graph.add('buffersink')
base_buf.link_to(overlay, 0, 0) # base → overlay.main
logo_buf.link_to(overlay, 0, 1) # logo → overlay.overlay
overlay.link_to(sink, 0, 0)
graph.configure()
动态参数调整
# 仅当 filter.command_support == True 时可用
# 通过 FilterContext 发送运行时命令(具体API依FFmpeg版本而定)
7. ⚠️ 开发排查备忘
💡 最佳实践总结
入口必设格式:
add_buffer必须明确 width/height/format,否则协商可能失败类型安全推拉:视频处理始终用
vpush/vpull,避免意外混入音频帧先查后用:构建图前用
Filter描述符确认端口数和类型循环拉取:每次 push 后循环 pull 至 None,防止内部缓冲溢出
auto_buffer:生产环境建议开启,让 FFmpeg 自动插入 format/scale 适配节点