Python如何调用FFmpeg处理视频?三种方式与实战代码
Python 调用 FFmpeg 是视频处理开发中的高频需求。FFmpeg 本身是命令行工具,Python 通过封装调用可以实现自动化、批量化的视频处理流程。下面从调用方式选择、核心代码示例到生产环境踩坑,逐一讲清楚。
三种调用方式怎么选?
Python 调用 FFmpeg 主要有三种方式,适用场景不同:
1. subprocess 直接调用
最原始的方式,直接拼命令行参数。适合一次性简单任务,缺点是参数容易拼错,路径含空格或中文时容易出问题,错误信息也不好捕获。
pythonimport subprocess result = subprocess.run( ["ffmpeg", "-i", "input.mp4", "-c:v", "libx264", "-preset", "fast", "output.mp4"], capture_output=True, text=True ) if result.returncode != 0: print(f"Error: {result.stderr}")
2. ffmpeg-python 库(推荐)
面向对象的 API 封装,自动处理参数转义和流管理,代码可读性和可维护性都更好。绝大多数场景用这个就够了。
pythonimport ffmpeg (ffmpeg .input("input.mp4") .output("output.mp4", vcodec="libx264", preset="fast") .run())
3. PyAV 库
直接绑定 FFmpeg 的 C 库(libav),能逐帧操作视频数据,适合需要帧级处理的场景(如视频分析、逐帧AI推理)。但安装复杂,Windows 上容易踩坑,非帧级需求不建议用。
pythonimport av container = av.open("input.mp4") for frame in container.decode(video=0): img = frame.to_ndarray(format="rgb24") # 对每一帧做处理
选择建议:日常视频转码、裁剪、合并用 ffmpeg-python;需要逐帧操作用 PyAV;临时一次性任务用 subprocess 也行,但要处理好错误。
视频格式转换
最常见的场景,用 ffmpeg-python 几行代码搞定:
pythonimport ffmpeg # MP4 转 AVI (ffmpeg .input("input.mp4") .output("output.avi", format="avi") .run()) # 转码为 H.264 + AAC,指定码率 (ffmpeg .input("input.mp4") .output("output.mp4", vcodec="libx264", acodec="aac", video_bitrate="1000k", audio_bitrate="128k") .run())
如果只是换容器格式(如 MP4 转 MKV),视频音频流不需要重新编码,用流复制速度极快:
python# 流复制:不重新编码,只是换容器 (ffmpeg .input("input.mp4") .output("output.mkv", vcodec="copy", acodec="copy") .run())
视频裁剪与缩放
裁剪和缩放用 FFmpeg 滤镜实现,ffmpeg-python 通过 filter 或 filter_complex 调用:
pythonimport ffmpeg # 裁剪视频片段(从第10秒开始,持续30秒) (ffmpeg .input("input.mp4", ss=10, t=30) .output("clip.mp4", vcodec="libx264", acodec="copy") .run()) # 画面裁剪:取中心区域 640x360 (ffmpeg .input("input.mp4") .filter_("crop", 640, 360, "(iw-640)/2", "(ih-360)/2") .output("cropped.mp4") .run()) # 缩放到指定分辨率 (ffmpeg .input("input.mp4") .filter_("scale", 1280, 720) .output("resized.mp4") .run())
音频提取与处理
从视频中提取音频是常见需求,比如做语音识别前要先拿音频文件:
pythonimport ffmpeg # 提取音频为 WAV(语音识别常用格式) (ffmpeg .input("input.mp4") .output("audio.wav", acodec="pcm_s16le", ar=16000, ac=1) .run()) # 提取音频为 MP3 (ffmpeg .input("input.mp4") .output("audio.mp3", acodec="libmp3lame", audio_bitrate="192k") .run())
参数说明:ar=16000 采样率 16kHz(语音识别标准),ac=1 单声道。
视频压缩
视频压缩是高频需求,核心是选择编码器和调节码率:
pythonimport ffmpeg # H.264 压缩,CRF 模式(推荐) # CRF 值越大压缩率越高,质量越低,范围 0-51,推荐 18-28 (ffmpeg .input("input.mp4") .output("compressed.mp4", vcodec="libx264", crf=23, preset="medium") .run()) # H.265 压缩,同等质量下文件更小(编码更慢) (ffmpeg .input("input.mp4") .output("compressed_h265.mp4", vcodec="libx265", crf=28, preset="medium") .run())
preset 参数从快到慢:ultrafast > superfast > veryfast > faster > fast > medium > slow > slower > veryslow。越慢压缩率越高,生产环境通常选 medium 或 slow。
批量处理与错误处理
实际项目中往往需要批量处理视频,错误处理必不可少:
pythonimport ffmpeg import os import glob def convert_video(input_path, output_path): try: (ffmpeg .input(input_path) .output(output_path, vcodec="libx264", crf=23, preset="medium") .run(overwrite_output=True, quiet=True)) print(f"OK: {input_path}") except ffmpeg.Error as e: print(f"Failed: {input_path} - {e.stderr.decode()}") # 批量转换目录下所有 AVI 文件 for avi_file in glob.glob("videos/*.avi"): mp4_file = os.path.splitext(avi_file)[0] + ".mp4" convert_video(avi_file, mp4_file)
关键点:overwrite_output=True 避免输出文件已存在时报错,quiet=True 抑制冗余日志。
获取视频信息
处理前通常需要先看视频的元信息(时长、分辨率、编码格式):
pythonimport ffmpeg probe = ffmpeg.probe("input.mp4") video_info = next(s for s in probe["streams"] if s["codec_type"] == "video") print(f"分辨率: {video_info["width"]}x{video_info["height"]}") print(f"编码: {video_info["codec_name"]}") print(f"时长: {float(probe["format"]["duration"]):.1f}秒")
生产环境注意事项
路径安全:拼接路径时用 os.path.join,不要手动拼字符串,防止路径注入和跨平台兼容问题。
依赖管理:ffmpeg-python 只是 Python 封装,系统必须安装 FFmpeg 本体。Docker 部署时在 Dockerfile 里装:
dockerfileFROM python:3.11-slim RUN apt-get update && apt-get install -y ffmpeg && rm -rf /var/lib/apt/lists/* RUN pip install ffmpeg-python
性能调优:大文件处理用 -preset slow 换压缩率;并行任务用 multiprocessing 开多进程,但注意控制并发数,FFmpeg 本身就很吃 CPU 和内存。
资源控制:长时间运行的转码任务建议加超时和内存限制,避免一个异常文件把整个服务拖垮:
pythonimport subprocess try: subprocess.run( ["ffmpeg", "-i", "input.mp4", "-c:v", "libx264", "output.mp4"], timeout=3600, # 1小时超时 capture_output=True ) except subprocess.TimeoutExpired: print("转码超时,终止进程")
输入校验:处理用户上传的文件时,先 ffmpeg.probe 检查文件是否合法,拒绝异常文件(如伪装为视频的恶意文件)。
以上覆盖了 Python 调用 FFmpeg 的主流方式和常见场景。日常开发中,ffmpeg-python 能满足绝大多数需求,重点记住三点:流复制比重新编码快得多、CRF 比固定码率更智能、批量任务必须有错误处理和资源控制。