把一段视频或者录音变成可搜索的文字,听起来是个复杂工程,实际上只需要两个开源工具的配合:FFmpeg负责把各种格式的音视频统一处理成Whisper能吃进去的音频,Whisper则负责真正意义上的语音识别。这两个工具都是本地运行,不需要上传任何数据到云端,对于会议记录、播客转写、视频字幕这类对隐私有要求的工作来说非常合适。本文从环境搭建讲到完整的批量处理脚本,把整个链路拆开讲清楚。

为什么FFmpeg是Whisper的黄金搭档
Whisper接受的输入是特定规格的音频:16kHz采样率、单声道、16位PCM编码的WAV文件。但我们实际拿到的素材五花八门,可能是MP4视频、FLAC无损音频、甚至是浏览器录出来的OGG文件。如果手动转换格式,每次都要敲一堆命令行参数,效率很低。FFmpeg的存在就是把这个环节自动化。
FFmpeg本身几乎支持所有已知的音视频格式,它内部包含了解码器、编码器、重采样器和过滤器图系统。一个简单的命令就能完成提取音轨、降采样、转单声道这一整套操作:
ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 output.wav
这条命令里,-vn表示忽略视频流,-acodec pcm_s16le指定输出为16位PCM编码,-ar 16000把采样率降到16kHz,-ac 1合并为单声道。对于常见的MP3、M4A文件,这条命令同样适用,因为FFmpeg会自动识别输入格式。需要注意的是,Whisper对16kHz以下的音频支持有限,如果原始素材是8kHz的电话录音,识别效果会明显下降,这时候可以考虑配合降噪滤镜提升清晰度:
ffmpeg -i call_recording.wav -af "highpass=f=200,lowpass=f=3000,afftdn" cleaned.wav
这里用了高通和低通滤波器把人声频段保留下来,再用afftdn做FFT域降噪。经过这样预处理的音频,Whisper的识别准确率通常能有肉眼可见的提升,尤其是带背景噪音的现场录音。
Whisper的部署与模型选择策略
Whisper是OpenAI在2022年开源的语音识别模型,官方Python包安装非常直接:
pip install openai-whisper # 需要系统已安装FFmpeg # 可选:GPU加速需要安装PyTorch的CUDA版本
Whisper提供了从tiny到large-v3共多个尺寸的模型,参数量从3900万到15亿不等。模型越大识别越准,但速度越慢、显存占用越高。实际选择可以参考这个原则:中文内容建议medium起步,tiny和base对中文的效果比较勉强;纯英文场景base或small就够用;追求极致精度且有显卡资源,直接上large-v3。以medium模型为例,大约需要5GB显存,在普通RTX 3060上转写一小时音频大约需要几分钟。
如果觉得官方包太慢,强烈推荐faster-whisper这个第三方实现。它基于CTranslate2推理引擎,在相同精度下速度能快4倍以上,显存占用也大幅降低:
from faster_whisper import WhisperModel
# 加载模型,device用cpu或cuda,compute_type决定量化精度
model = WhisperModel("medium", device="cuda", compute_type="float16")
# 转写音频,language指定中文可以避免语言自动检测的开销和误判
segments, info = model.transcribe("output.wav", language="zh", vad_filter=True)
for segment in segments:
print(f"[{segment.start:.2f}s -> {segment.end:.2f}s] {segment.text}")代码里的vad_filter=True启用了语音活动检测,会自动跳过静音和纯噪音片段,对长音频的提速非常明显。返回的segments自带时间戳信息,这为后续生成SRT字幕打下了基础。
完整实战:批量把视频转成SRT字幕
把前面讲的两步串起来,就能写出一个实用的批量处理脚本。这个脚本遍历指定目录下的所有视频文件,先交给FFmpeg提取音频,再调用Whisper转写,最后按SRT格式输出字幕文件:
import os
import glob
import subprocess
from faster_whisper import WhisperModel
VIDEO_DIR = r"D:\videos"
TEMP_AUDIO = "temp_audio.wav"
model = WhisperModel("medium", device="cuda", compute_type="float16")
def format_srt_time(seconds):
h = int(seconds // 3600)
m = int(seconds % 3600 // 60)
s = int(seconds % 60)
ms = int((seconds - int(seconds)) * 1000)
return f"{h:02d}:{m:02d}:{s:02d},{ms:03d}"
def process_video(video_path):
# 第一步:FFmpeg提取并重采样音频
subprocess.run([
"ffmpeg", "-y", "-i", video_path,
"-vn", "-acodec", "pcm_s16le",
"-ar", "16000", "-ac", "1", TEMP_AUDIO
], check=True, capture_output=True)
# 第二步:Whisper转写
segments, _ = model.transcribe(TEMP_AUDIO, language="zh", vad_filter=True)
# 第三步:生成SRT字幕
srt_path = os.path.splitext(video_path)[0] + ".srt"
with open(srt_path, "w", encoding="utf-8") as f:
for idx, seg in enumerate(segments, start=1):
f.write(f"{idx}\n")
f.write(f"{format_srt_time(seg.start)} --> {format_srt_time(seg.end)}\n")
f.write(f"{seg.text.strip()}\n\n")
print(f"完成:{srt_path}")
for video in glob.glob(os.path.join(VIDEO_DIR, "*.mp4")):
process_video(video)这段脚本在Windows和Linux上都能直接运行,唯一要注意的是路径里的反斜杠在Windows下需要用原始字符串表示。运行结束后,每个MP4文件旁边都会多出一个同名的SRT字幕文件,可以直接拖进播放器或者剪辑软件使用。
如果要进一步封装成Web服务,可以把Whisper部分包在FastAPI接口里,前端上传文件后异步执行转写任务,用任务队列管理并发。由于Whisper推理是显存密集型操作,多用户并发时建议只加载一个模型实例,通过加锁或队列的方式串行处理请求,避免显存溢出。
性能优化与常见问题排查
实际用下来最容易踩的坑有三个。第一个是CUDA相关报错,多数情况是PyTorch版本与显卡驱动不匹配,可以先用torch.cuda.is_available()验证,返回False就说明GPU没有正确接管,此时faster-whisper会退化到CPU运行,速度慢十几倍。第二个坑是长音频内存暴涨,Whisper默认按30秒窗口处理,遇到几小时的录音,官方包可能会占用大量内存,启用VAD过滤或者用faster-whisper的chunk_length参数分块处理可以有效缓解。
第三个坑和FFmpeg有关:Whisper调用FFmpeg读取输入时,如果系统PATH里找不到ffmpeg命令,会直接抛出FileNotFoundError。Windows用户最简单的办法是从官网下载构建版本,解压后把bin目录加进环境变量,比如放到C:\ffmpeg\bin,然后重启终端生效。验证方式是在命令行里直接敲ffmpeg -version,能正常打印版本号就说明配置成功。
性能方面还有几个小技巧值得尝试。转写中文时显式传入language="zh",既省掉了语言检测的耗时,也避免了长音频开头无人声导致的语种误判;如果CPU资源充裕而显存吃紧,faster-whisper支持compute_type="int8"量化,精度损失很小但显存需求能降到原来的四分之一左右;对于需要输出简体中文的场景,可以配合initial_prompt="以下是普通话简体中文的内容。"引导模型输出简体字。把FFmpeg的预处理、合适的模型规格和这些调优手段组合起来,一套稳定高效的本地语音转文字流水线就搭建完成了。