下载了外语视频没字幕?用 Whisper 本地部署 AI 语音转字幕,批量生成中文字幕
你下载了一批 YouTube 上的技术演讲,全是英文没字幕,听得一知半解。或者你录了几小时的会议音频,需要整理成文字。传统方案要么花钱(讯飞/阿里云语音识别 API 按分钟计费),要么效果差(免费在线工具的识别准确率惨不忍睹)。OpenAI 开源的 Whisper 模型改变了这个局面——它在本地运行,不花一分钱,识别准确率吊打绝大多数付费服务,而且支持 99 种语言。这篇文章从安装到批量处理,教你用 Whisper 给下载的视频自动生成字幕,包括中英文混合识别、时间轴对齐和字幕格式转换。
TL;DR:Whisper 是 OpenAI 开源的语言识别模型,本地运行、免费、支持 99 种语言。推荐用 faster-whisper(C++ 重写版,速度提升 4 倍,内存减半)。安装:
pip install faster-whisper。核心代码三行:加载模型 →model.transcribe("audio.mp3")→ 输出带时间戳的文本。生成字幕后用 FFmpeg 烧录到视频或导出 SRT 文件。批量处理建议写脚本遍历目录,配合 ffmpeg 先提取音频再识别。
目录
- 一、Whisper 是什么,为什么选它
- 二、安装与模型选择
- 三、基础用法:10 分钟上手
- 四、实战:给视频自动生成字幕
- 五、批量处理脚本
- 六、中英文混合识别的技巧
- 七、字幕后处理:翻译、校对、烧录
- 八、性能优化与硬件选择
- 九、合规与温馨提示
一、Whisper 是什么,为什么选它
1.1 和其他方案对比
| 方案 | 费用 | 准确率 | 语言支持 | 离线运行 | 速度 |
|---|---|---|---|---|---|
| Whisper (large-v3) | 免费 | ⭐⭐⭐⭐⭐ | 99 种 | ✅ | 需要 GPU |
| 讯飞语音识别 | ¥3-8/小时 | ⭐⭐⭐⭐ | 中文为主 | ❌ | 快 |
| 阿里云语音识别 | ¥2-5/小时 | ⭐⭐⭐⭐ | 中英日韩 | ❌ | 快 |
| 剪映自动字幕 | 免费 | ⭐⭐⭐ | 中英 | ❌(需联网) | 快 |
| 网易见外 | 免费 | ⭐⭐ | 中英 | ❌ | 慢 |
| YouTube 自动字幕 | 免费 | ⭐⭐⭐ | 多语言 | ❌ | 快 |
Whisper 的核心优势: - 完全本地运行,隐私安全(你的音频不会上传到任何服务器) - 对带口音的英语、方言中文的识别效果远超商业 API - 开源社区的活跃度极高,各种优化版本层出不穷
1.2 Whisper 的几个版本
| 版本 | 速度 | 准确率 | 显存需求 | 推荐场景 |
|---|---|---|---|---|
| whisper (原版) | 基准 | ⭐⭐⭐⭐ | 10GB (large) | 简单使用 |
| faster-whisper | 4x | ⭐⭐⭐⭐ | 5GB (large) | 推荐 |
| whisper.cpp | 6x | ⭐⭐⭐ | 2GB (medium) | CPU 推理 |
| whisperX | 3x | ⭐⭐⭐⭐⭐ | 8GB | 需要词级时间戳 |
| insanely-fast-whisper | 10x | ⭐⭐⭐⭐ | 6GB | 超长音频 |
推荐 faster-whisper:速度是原版的 4 倍,显存只用一半,准确率几乎没损失。如果只有 CPU,用 whisper.cpp。
二、安装与模型选择
2.1 安装 faster-whisper
# 安装(会自动安装 CUDA 依赖)
pip install faster-whisper
# 如果只用 CPU
pip install faster-whisper
# 运行时指定 device='cpu'
2.2 模型选择
| 模型 | 参数量 | 显存需求 | 磁盘空间 | 英文准确率 | 多语言准确率 | 推荐场景 |
|---|---|---|---|---|---|---|
| tiny | 39M | ~1GB | ~150MB | 低 | 低 | 快速测试 |
| base | 74M | ~1GB | ~300MB | 中 | 中低 | 实时转录 |
| small | 244M | ~2GB | ~1GB | 中高 | 中 | 一般使用 |
| medium | 769M | ~5GB | ~3GB | 高 | 高 | 日常推荐 |
| large-v3 | 1.55B | ~10GB | ~6GB | 极高 | 极高 | 最佳质量 |
| turbo | 809M | ~6GB | ~3GB | 极高 | 高 | 速度质量平衡 |
选择建议:
- 有 NVIDIA 显卡(6GB+ 显存):large-v3-turbo(速度快且质量接近 large-v3)
- 有 NVIDIA 显卡(4GB 显存):medium
- 只有 CPU:small + whisper.cpp(或者用 faster-whisper 的 int8 量化)
- 苹果 M1/M2/M3:large-v3(Metal 加速,速度很快)
2.3 验证安装
from faster_whisper import WhisperModel
# 首次运行会自动下载模型
model = WhisperModel("medium", device="cuda", compute_type="float16")
print("安装成功!")
三、基础用法:10 分钟上手
3.1 识别一个音频文件
from faster_whisper import WhisperModel
# 加载模型(首次运行会自动下载)
model = WhisperModel("medium", device="cuda", compute_type="float16")
# 转录音频
segments, info = model.transcribe("audio.mp3", language="zh")
print(f"检测到语言: {info.language} (概率: {info.language_probability:.2f})")
print(f"音频时长: {info.duration:.0f} 秒")
print()
# 输出带时间戳的文本
for segment in segments:
print(f"[{segment.start:.2f}s → {segment.end:.2f}s] {segment.text}")
输出示例:
检测到语言: zh (概率: 0.99)
音频时长: 120 秒
[0.00s → 5.20s] 大家好 今天我们来聊聊视频编码
[5.50s → 12.30s] 你有没有想过 为什么同一个视频在不同平台上的清晰度不一样
[12.80s → 18.60s] 这背后涉及到编码标准 码率控制还有容器格式的选择
3.2 关键参数
segments, info = model.transcribe(
"audio.mp3",
# 语言设置
language="zh", # 指定语言(不指定则自动检测)
# language=None, # 自动检测
# 识别精度
beam_size=5, # beam search 宽度(越大越准但越慢)
best_of=5, # 多次采样取最佳
# 初始提示(提高专业术语识别率)
initial_prompt="这是一个关于视频编码的演讲,包含术语:H.264, H.265, VP9, AV1, 码率, 帧率",
# VAD 过滤(跳过静音段)
vad_filter=True,
vad_parameters=dict(
min_silence_duration_ms=500, # 最少静音时长
),
# 其他
temperature=0.0, # 0.0=最确定, 1.0=更多样
condition_on_previous_text=False, # 避免幻觉重复
)
四、实战:给视频自动生成字幕
4.1 完整流程
import subprocess
import os
from faster_whisper import WhisperModel
from pathlib import Path
def video_to_subtitle(video_path, output_srt=None, language=None,
model_size="medium"):
"""给视频自动生成字幕(SRT 格式)"""
if output_srt is None:
output_srt = str(Path(video_path).with_suffix('.srt'))
# 1. 从视频中提取音频
audio_path = str(Path(video_path).with_suffix('.wav'))
extract_audio(video_path, audio_path)
# 2. 用 Whisper 识别
print(f"正在识别: {video_path}")
model = WhisperModel(model_size, device="cuda", compute_type="float16")
segments, info = model.transcribe(
audio_path,
language=language,
beam_size=5,
vad_filter=True,
)
print(f"语言: {info.language}, 时长: {info.duration:.0f}s")
# 3. 生成 SRT 字幕文件
with open(output_srt, 'w', encoding='utf-8') as f:
for i, segment in enumerate(segments, 1):
# SRT 时间格式: HH:MM:SS,mmm
start = format_timestamp(segment.start)
end = format_timestamp(segment.end)
text = segment.text.strip()
f.write(f"{i}\n")
f.write(f"{start} --> {end}\n")
f.write(f"{text}\n\n")
# 4. 清理临时音频
os.remove(audio_path)
print(f"字幕已保存: {output_srt}")
return output_srt
def extract_audio(video_path, audio_path):
"""从视频中提取音频(16kHz 单声道 WAV,Whisper 推荐格式)"""
subprocess.run([
'ffmpeg', '-i', video_path,
'-vn', # 不要视频
'-acodec', 'pcm_s16le', # 16-bit PCM
'-ar', '16000', # 16kHz 采样率
'-ac', '1', # 单声道
audio_path,
'-y'
], capture_output=True, check=True)
def format_timestamp(seconds):
"""秒数 → SRT 时间戳格式"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
millis = int((seconds % 1) * 1000)
return f"{hours:02d}:{minutes:02d}:{secs:02d},{millis:03d}"
4.2 生成不同格式的字幕
def generate_vtt(segments, output_path):
"""生成 WebVTT 格式(用于 HTML5 播放器)"""
with open(output_path, 'w', encoding='utf-8') as f:
f.write("WEBVTT\n\n")
for segment in segments:
start = format_timestamp(segment.start).replace(',', '.')
end = format_timestamp(segment.end).replace(',', '.')
f.write(f"{start} --> {end}\n")
f.write(f"{segment.text.strip()}\n\n")
def generate_ass(segments, output_path, title="Whisper 生成"):
"""生成 ASS 格式(用于播放器,支持样式)"""
with open(output_path, 'w', encoding='utf-8') as f:
f.write("[Script Info]\n")
f.write(f"Title: {title}\n")
f.write("ScriptType: v4.00+\n\n")
f.write("[V4+ Styles]\n")
f.write("Format: Name, Fontname, Fontsize, PrimaryColour, "
"OutlineColour, Bold\n")
f.write("Style: Default,Microsoft YaHei,20,&H00FFFFFF,"
"&H00000000,0\n\n")
f.write("[Events]\n")
f.write("Format: Layer, Start, End, Style, Name, "
"MarginL, MarginR, MarginV, Effect, Text\n")
for segment in segments:
start = format_timestamp(segment.start).replace(',', '.')
end = format_timestamp(segment.end).replace(',', '.')
text = segment.text.strip()
f.write(f"Dialogue: 0,{start},{end},Default,,0,0,0,,{text}\n")
五、批量处理脚本
import os
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def batch_generate_subtitles(video_dir, output_dir=None, language=None,
model_size="medium", workers=1):
"""批量给目录下所有视频生成字幕"""
video_exts = {'.mp4', '.mkv', '.webm', '.flv', '.avi', '.mov'}
output_dir = output_dir or video_dir
# 收集待处理视频
tasks = []
for filepath in Path(video_dir).iterdir():
if filepath.suffix.lower() in video_exts:
srt_path = Path(output_dir) / f'{filepath.stem}.srt'
if srt_path.exists():
print(f"跳过(已有字幕): {filepath.name}")
continue
tasks.append(filepath)
if not tasks:
print("没有需要处理的视频")
return
print(f"待处理: {len(tasks)} 个视频")
# 单线程处理(Whisper 本身会充分利用 GPU,多线程反而可能更慢)
for i, video_path in enumerate(tasks, 1):
print(f"\n[{i}/{len(tasks)}] {video_path.name}")
try:
output = str(Path(output_dir) / f'{video_path.stem}.srt')
video_to_subtitle(str(video_path), output, language, model_size)
except Exception as e:
print(f" 失败: {e}")
print(f"\n完成!共处理 {len(tasks)} 个视频")
if __name__ == '__main__':
batch_generate_subtitles(
'./videos/',
language='zh', # 中文视频
model_size='medium',
)
六、中英文混合识别的技巧
6.1 不指定语言(自动检测)
Whisper 的语言自动检测在大多数情况下很准确。但如果视频是中英文混杂(比如中文技术演讲里夹杂英文术语),自动检测可能摇摆:
# 不指定语言,让 Whisper 自动判断
segments, info = model.transcribe("audio.mp3", language=None)
print(f"检测到: {info.language}")
6.2 用 initial_prompt 引导识别
对于专业术语多的视频,用 initial_prompt 能显著提高准确率:
# 技术视频的提示词
prompt = (
"这是一段技术演讲,包含以下术语:"
"API, SDK, Docker, Kubernetes, CI/CD, "
"微服务, 容器化, 负载均衡, 数据库, "
"FFmpeg, H.264, H.265, VP9, AV1"
)
segments, info = model.transcribe(
"audio.mp3",
language="zh",
initial_prompt=prompt,
)
initial_prompt 的工作原理:给模型一个"上下文",让它在解码时倾向于生成这些词。不是强制替换,而是提高概率。
6.3 中英混合字幕的分词优化
Whisper 生成的中文字幕默认没有标点。可以用 punctuation 后处理:
# 安装:pip install zhconv
import re
import zhconv
def post_process_zh(text):
"""中文后处理:添加标点、繁简转换"""
# 繁→简
text = zhconv.convert(text, 'zh-cn')
# 简单的标点修复(空格处添加逗号)
text = re.sub(r'(?<=[\u4e00-\u9fff])\s+(?=[\u4e00-\u9fff])', ',', text)
# 中英文之间加空格
text = re.sub(r'([\u4e00-\u9fff])([a-zA-Z])', r'\1 \2', text)
text = re.sub(r'([a-zA-Z])([\u4e00-\u9fff])', r'\1 \2', text)
return text
七、字幕后处理:翻译、校对、烧录
7.1 机器翻译字幕
Whisper 本身不做翻译(原版 whisper 有 translate 模式但效果差)。如果要翻译,用独立翻译工具:
# 方案 1:使用 translatepy(免费,Google 翻译后端)
# pip install translatepy
from translatepy import Translator
def translate_srt(input_srt, output_srt, target_lang='Chinese'):
"""翻译 SRT 字幕文件"""
translator = Translator()
with open(input_srt, 'r', encoding='utf-8') as f:
content = f.read()
# 只翻译文本行(跳过序号和时间轴)
lines = content.split('\n')
translated_lines = []
for line in lines:
stripped = line.strip()
# 跳过序号、时间轴、空行
if (stripped.isdigit() or
'-->' in stripped or
not stripped):
translated_lines.append(line)
else:
try:
result = translator.translate(
stripped, target_lang=target_lang
)
translated_lines.append(result.result)
except Exception:
translated_lines.append(line)
with open(output_srt, 'w', encoding='utf-8') as f:
f.write('\n'.join(translated_lines))
return output_srt
7.2 烧录字幕到视频
# 烧录 SRT 字幕(硬字幕,不可关闭)
ffmpeg -i input.mp4 -vf "subtitles=subtitle.srt" output.mp4
# 烧录 ASS 字幕(支持样式)
ffmpeg -i input.mp4 -vf "ass=subtitle.ass" output.mp4
# 指定字体
ffmpeg -i input.mp4 \
-vf "subtitles=subtitle.srt:force_style='FontName=Microsoft YaHei,FontSize=20,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000'" \
output.mp4
7.3 添加软字幕(可开关,不重编码)
# MKV 格式(支持 SRT/ASS)
ffmpeg -i input.mp4 -i subtitle.srt \
-c copy -c:s mov_text \
-metadata:s:s:0 language=zh \
output.mp4
# 更推荐:封装为 MKV(原生支持 SRT)
ffmpeg -i input.mp4 -i subtitle.srt \
-c copy output.mkv
八、性能优化与硬件选择
8.1 不同硬件下的速度实测
测试音频:1 小时英文播客,medium 模型
| 硬件 | 处理时间 | 实时倍数 |
|---|---|---|
| NVIDIA RTX 4090 | 45s | 80x |
| NVIDIA RTX 3060 (12GB) | 1m30s | 40x |
| NVIDIA GTX 1060 (6GB) | 3m | 20x |
| Apple M2 Pro | 2m15s | 27x |
| Apple M1 | 4m | 15x |
| Intel i7-13700K (CPU) | 18m | 3.3x |
| AMD Ryzen 5600 (CPU) | 25m | 2.4x |
关键发现:
- GPU 比 CPU 快 6-20 倍
- Apple Silicon 的 Metal 加速很给力,M2 接近 RTX 3060
- 如果只有 CPU,用 compute_type="int8" 量化能再提速 30-50%
8.2 长音频的分段处理
超过 1 小时的音频,建议分段处理以避免 OOM:
def transcribe_long_audio(audio_path, model, segment_duration=600):
"""分段处理超长音频(每 10 分钟一段)"""
import librosa
audio, sr = librosa.load(audio_path, sr=16000)
total_duration = len(audio) / sr
all_segments = []
for start in range(0, int(total_duration), segment_duration):
end = min(start + segment_duration, int(total_duration))
chunk = audio[start * sr:end * sr]
# 保存为临时文件
import tempfile
with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as f:
import soundfile as sf
sf.write(f.name, chunk, sr)
temp_path = f.name
segments, _ = model.transcribe(temp_path)
# 调整时间偏移
for seg in segments:
seg.start += start
seg.end += start
all_segments.append(seg)
os.remove(temp_path)
print(f" 已处理: {start//60}-{end//60} 分钟")
return all_segments
九、合规与温馨提示
- Whisper 是 OpenAI 开源的合法工具(MIT 许可证),可以自由使用
- 本地运行意味着音频不会上传到任何服务器,隐私安全
- 使用 Whisper 转录他人视频内容用于再分发,可能侵犯原作者的著作权
- 生成的字幕文件同样受版权保护——不要批量生成他人视频的字幕并公开发布
- 更多讨论见 下载视频算侵权吗?聊聊个人备份与版权的那条线
Whisper 是我用过最省心的 AI 工具之一——装好之后就是三行代码的事,不用注册账号、不用买 API Key、不用盯着用量配额。我现在的习惯是:下载完外语视频后跑一遍 Whisper,生成中文字幕,然后导入 Jellyfin,全家人都能看懂。如果你有 NVIDIA 显卡,推荐直接上 large-v3-turbo,速度快且准确率很高;如果没有显卡,medium + int8 量化在 CPU 上也能用,就是多等一会儿。
本文由 VidDown 技术博客原创发布。VidDown 桌面客户端内置了 Whisper 字幕生成功能——下载视频后可以一键生成中英文字幕,自动烧录或导出 SRT 文件。访问 VidDown 了解更多。