faster-whisper输出格式定制:SRT/VTT字幕文件生成
你是否在寻找高效生成多格式字幕的解决方案?是否因现有工具格式单一而无法满足多平台发布需求?本文将系统介绍如何基于faster-whisper实现SRT(SubRip Subtitle)和VTT(Web Video Text Tracks)两种主流字幕格式的定制化生成,通过完整代码示例和参数调优指南,帮助你一站式解决音频转字幕的格式适配问题。读完本文你将掌握:
- SRT/VTT字幕格式的技术规范与实现差异
- faster-whisper转录结果的结构化处理方法
- 带时间戳校准的字幕生成完整代码实现
- 多场景下的字幕格式定制与优化技巧
字幕格式技术规范对比
字幕文件本质是包含时间戳与文本内容的结构化数据,不同格式在时间戳表示、换行规则和元数据处理上存在显著差异。以下是SRT与VTT格式的核心技术规范对比:
| 特性 | SRT格式规范 | VTT格式规范 |
|---|---|---|
| 文件扩展名 | .srt | .vtt |
| 时间戳分隔符 | --> (箭头两侧有空格) | --> (箭头两侧无空格) |
| 时间格式 | 时:分:秒,毫秒 (逗号分隔毫秒) | 时:分:秒.毫秒 (点分隔毫秒) |
| 序号要求 | 必须包含递增序号 (1, 2, 3...) | 可选,可省略序号 |
| 头部标识 | 无特殊头部 | 必须以WEBVTT开头 |
| 空行规则 | 段落间必须有空行分隔 | 段落间可有空行,也可紧密排列 |
| 支持的样式 | 不支持内联样式 | 支持基础CSS样式 (通过::cue伪类) |
| 换行表示 | \n 或实际换行 | \n 或实际换行 |
SRT格式示例
1
00:01:23,456 --> 00:01:25,789
这是SRT格式的字幕示例
2
00:01:26,123 --> 00:01:28,456
支持多行显示
通过空行分隔段落
VTT格式示例
WEBVTT
00:01:23.456 --> 00:01:25.789
这是VTT格式的字幕示例
00:01:26.123 --> 00:01:28.456
支持基础样式
<span style="color:red">红色文本</span>
faster-whisper转录结果结构解析
faster-whisper的转录结果包含丰富的时间戳信息,这些信息是生成字幕的基础。从transcribe.py源码分析可知,转录返回的Segment对象包含以下关键属性:
@dataclass
class Segment:
id: int # 段落序号
seek: int # 音频偏移量
start: float # 开始时间(秒)
end: float # 结束时间(秒)
text: str # 段落文本内容
tokens: List[int] # 分词标识
avg_logprob: float # 平均对数概率(置信度)
compression_ratio: float # 压缩比
no_speech_prob: float # 非语音概率
words: Optional[List[Word]] # 单词级时间戳
当启用word_timestamps=True参数时,每个Segment还会包含Word对象列表,提供单词级精度的时间戳:
@dataclass
class Word:
start: float # 单词开始时间(秒)
end: float # 单词结束时间(秒)
word: str # 单词内容
probability: float # 单词置信度
关键时间戳转换逻辑
faster-whisper返回的时间戳以秒为单位的浮点数(如start=123.456表示123秒456毫秒),需要转换为字幕格式要求的时:分:秒,毫秒格式。utils.py中提供的format_timestamp函数实现了基础转换:
def format_timestamp(
seconds: float,
always_include_hours: bool = False,
decimal_marker: str = ".",
) -> str:
milliseconds = round(seconds * 1000.0)
hours = milliseconds // 3_600_000
milliseconds -= hours * 3_600_000
minutes = milliseconds // 60_000
milliseconds -= minutes * 60_000
seconds = milliseconds // 1_000
milliseconds -= seconds * 1_000
hours_marker = f"{hours:02d}:" if always_include_hours or hours > 0 else ""
return f"{hours_marker}{minutes:02d}:{seconds:02d}{decimal_marker}{milliseconds:03d}"
该函数可通过decimal_marker参数控制毫秒分隔符(逗号或点),满足不同格式需求。
字幕生成器实现方案
基于faster-whisper的转录结果,我们可以设计一个通用的字幕生成器,支持SRT和VTT两种格式的输出。实现架构如下:
核心实现代码
以下是完整的字幕生成器实现,包含格式转换、时间戳处理和文件写入等核心功能:
from dataclasses import asdict
from typing import List, TextIO, Union
from faster_whisper.transcribe import Segment
from faster_whisper.utils import format_timestamp
class SubtitleGenerator:
def __init__(self, segments: List[Segment]):
"""
字幕生成器初始化
Args:
segments: faster-whisper返回的转录结果列表
"""
self.segments = segments
def _convert_timestamp(self, seconds: float, format_type: str) -> str:
"""
将秒转换为指定格式的时间戳字符串
Args:
seconds: 时间(秒)
format_type: 格式类型,'srt'或'vtt'
Returns:
格式化的时间戳字符串
"""
if format_type == 'srt':
return format_timestamp(seconds, decimal_marker=',')
elif format_type == 'vtt':
return format_timestamp(seconds, decimal_marker='.')
raise ValueError(f"不支持的格式类型: {format_type}")
def generate_srt(self, output_file: Union[str, TextIO]) -> None:
"""
生成SRT格式字幕
Args:
output_file: 输出文件路径或文件对象
"""
is_file_object = hasattr(output_file, 'write')
if not is_file_object:
file = open(output_file, 'w', encoding='utf-8')
else:
file = output_file
try:
for i, segment in enumerate(self.segments, 1):
# 写入序号
file.write(f"{i}\n")
# 写入时间戳
start_time = self._convert_timestamp(segment.start, 'srt')
end_time = self._convert_timestamp(segment.end, 'srt')
file.write(f"{start_time} --> {end_time}\n")
# 写入文本内容
file.write(f"{segment.text.strip()}\n")
# 写入段落分隔空行
file.write("\n")
finally:
if not is_file_object:
file.close()
def generate_vtt(self, output_file: Union[str, TextIO]) -> None:
"""
生成VTT格式字幕
Args:
output_file: 输出文件路径或文件对象
"""
is_file_object = hasattr(output_file, 'write')
if not is_file_object:
file = open(output_file, 'w', encoding='utf-8')
else:
file = output_file
try:
# 写入VTT头部标识
file.write("WEBVTT\n\n")
for segment in self.segments:
# 写入时间戳
start_time = self._convert_timestamp(segment.start, 'vtt')
end_time = self._convert_timestamp(segment.end, 'vtt')
file.write(f"{start_time}--> {end_time}\n") # VTT箭头两侧无空格
# 写入文本内容
file.write(f"{segment.text.strip()}\n")
# 写入段落分隔空行
file.write("\n")
finally:
if not is_file_object:
file.close()
def generate(self, output_file: str, format_type: str) -> None:
"""
生成指定格式的字幕
Args:
output_file: 输出文件路径
format_type: 格式类型,'srt'或'vtt'
"""
if format_type == 'srt':
self.generate_srt(output_file)
elif format_type == 'vtt':
self.generate_vtt(output_file)
else:
raise ValueError(f"不支持的格式类型: {format_type}")
完整应用示例:音频转字幕工作流
以下是使用faster-whisper进行音频转录并生成字幕文件的完整工作流程示例。我们将实现一个命令行工具,支持指定输出格式、调整字幕时长阈值等高级功能。
1. 安装必要依赖
# 安装faster-whisper
pip install faster-whisper
# 如需处理音频文件,可能需要额外依赖
pip install ffmpeg-python
2. 完整应用代码实现
import argparse
from faster_whisper import WhisperModel
from subtitle_generator import SubtitleGenerator # 导入上面实现的字幕生成器
def main():
parser = argparse.ArgumentParser(description='音频转字幕工具')
parser.add_argument('audio_path', help='音频文件路径')
parser.add_argument('-o', '--output', help='输出文件路径(不带扩展名)')
parser.add_argument('-f', '--format', choices=['srt', 'vtt'], default='srt',
help='输出格式(srt或vtt),默认srt')
parser.add_argument('-m', '--model', default='base',
help='模型大小(tiny, base, small, medium, large等)')
parser.add_argument('-l', '--language', default=None,
help='指定语言(如zh, en),默认自动检测')
parser.add_argument('-t', '--threshold', type=float, default=0.8,
help='字幕最小置信度阈值,低于此值的段落将被过滤')
parser.add_argument('--word_timestamps', action='store_true',
help='启用单词级时间戳(实验性功能)')
args = parser.parse_args()
# 设置输出文件名
output_path = args.output if args.output else args.audio_path.rsplit('.', 1)[0]
output_file = f"{output_path}.{args.format}"
# 加载模型
print(f"加载模型: {args.model}")
model = WhisperModel(args.model, device="cpu", compute_type="int8")
# 转录音频
print(f"正在转录音频: {args.audio_path}")
segments, info = model.transcribe(
args.audio_path,
language=args.language,
word_timestamps=args.word_timestamps,
# 设置其他参数
beam_size=5,
log_prob_threshold=args.threshold, # 过滤低置信度结果
no_speech_threshold=0.6 # 过滤非语音段落
)
print(f"检测到语言: {info.language} (置信度: {info.language_probability:.2f})")
print(f"生成{args.format}格式字幕: {output_file}")
# 转换为列表以便后续处理
segments = list(segments)
# 生成字幕
generator = SubtitleGenerator(segments)
generator.generate(output_file, args.format)
print(f"字幕生成完成,共{len(segments)}个段落")
if __name__ == "__main__":
main()
3. 命令行使用示例
# 基本用法:生成SRT字幕
python audio_to_subtitle.py audio.mp3 -o output_subtitle -f srt
# 高级用法:使用medium模型,指定中文,生成VTT字幕
python audio_to_subtitle.py meeting.mp3 -m medium -l zh -f vtt -t 0.7
# 启用单词级时间戳(实验性)
python audio_to_subtitle.py speech.mp3 --word_timestamps
高级定制技巧与优化策略
1. 字幕内容优化
过滤低质量字幕段落
可以基于avg_logprob(平均对数概率)过滤低质量的转录结果,通常建议阈值设为-1.0到-0.5之间:
# 过滤低置信度段落
filtered_segments = [
seg for seg in segments
if seg.avg_logprob > -0.8 # 调整此阈值
]
合并短段落
对于过短的字幕段落(如单个单词),可以合并相邻段落提升可读性:
def merge_short_segments(segments, min_duration=1.0):
"""合并短于指定时长的段落"""
merged = []
current_segment = None
for seg in segments:
if current_segment is None:
current_segment = seg
else:
# 检查当前段落是否过短
if (seg.end - current_segment.start) < min_duration:
# 合并段落
current_segment = Segment(
id=current_segment.id,
seek=current_segment.seek,
start=current_segment.start,
end=seg.end,
text=f"{current_segment.text.strip()} {seg.text.strip()}",
tokens=current_segment.tokens + seg.tokens,
avg_logprob=(current_segment.avg_logprob + seg.avg_logprob) / 2,
compression_ratio=(current_segment.compression_ratio + seg.compression_ratio) / 2,
no_speech_prob=(current_segment.no_speech_prob + seg.no_speech_prob) / 2,
words=current_segment.words + (seg.words or []) if current_segment.words else None
)
else:
merged.append(current_segment)
current_segment = seg
if current_segment:
merged.append(current_segment)
return merged
2. 时间戳校准与调整
全局时间偏移
有时需要整体调整字幕时间(如音频与视频不同步),可添加全局偏移量:
def adjust_timestamps(segments, offset_seconds):
"""
调整所有时间戳
Args:
segments: 段落列表
offset_seconds: 偏移量(秒),正数表示延后,负数表示提前
"""
adjusted = []
for seg in segments:
# 创建新的段落对象,调整时间戳
adjusted_seg = Segment(
id=seg.id,
seek=seg.seek,
start=max(0, seg.start + offset_seconds), # 确保不小于0
end=seg.end + offset_seconds,
text=seg.text,
tokens=seg.tokens,
avg_logprob=seg.avg_logprob,
compression_ratio=seg.compression_ratio,
no_speech_prob=seg.no_speech_prob,
words=[
Word(
start=max(0, word.start + offset_seconds),
end=word.end + offset_seconds,
word=word.word,
probability=word.probability
) for word in seg.words
] if seg.words else None
)
adjusted.append(adjusted_seg)
return adjusted
3. 多格式批量转换
对于需要同时生成多种格式字幕的场景,可以扩展字幕生成器,实现批量转换:
def generate_all_formats(self, base_path: str) -> None:
"""生成所有支持的格式字幕"""
self.generate_srt(f"{base_path}.srt")
self.generate_vtt(f"{base_path}.vtt")
# 可以添加更多格式支持
# self.generate_ass(f"{base_path}.ass") # ASS格式
# self.generate_sbv(f"{base_path}.sbv") # YouTube SBV格式
常见问题解决方案
1. 时间戳不准确问题
如果生成的字幕时间戳与音频不同步,可能的原因和解决方案:
- 模型精度不足:尝试使用更大的模型(如medium或large)
- 音频采样率问题:确保音频采样率为16kHz(faster-whisper默认采样率)
- VAD参数调整:调整语音活动检测参数,如增加
min_silence_duration_ms
# 调整VAD参数示例
segments, info = model.transcribe(
audio_path,
vad_filter=True,
vad_parameters=dict(
min_silence_duration_ms=200, # 最小静音时长(毫秒)
speech_pad_ms=30 # 语音前后填充时长(毫秒)
)
)
2. 中文分词问题
中文转录时可能出现分词不连贯问题,可通过以下方法优化:
- 使用针对中文优化的模型(如
large-v3对多语言支持更好) - 调整语言参数为
zh,避免自动检测错误 - 使用
initial_prompt提供中文语境提示
# 提供中文语境提示示例
segments, info = model.transcribe(
audio_path,
language="zh",
initial_prompt="以下是中文语音转文字,内容为技术讲座,包含专业术语。"
)
3. 长音频处理优化
对于长音频(如超过1小时),建议使用以下策略优化性能:
- 使用
chunk_length参数分块处理:chunk_length=30(30秒一块) - 启用
log_progress=True显示处理进度 - 使用GPU加速:
device="cuda"(如可用)
总结与扩展展望
本文详细介绍了基于faster-whisper生成SRT和VTT字幕的完整方案,从格式规范解析到实际代码实现,再到高级定制技巧。通过本文的方法,你可以轻松将音频内容转换为各种平台兼容的字幕格式。
未来可以进一步探索的方向:
- 多语言字幕同步生成:同时生成多种语言的字幕文件
- 字幕样式定制:扩展VTT格式支持更多CSS样式
- 字幕翻译集成:结合翻译API实现自动翻译字幕
- OCR字幕对齐:与视频OCR结合,优化已有字幕的时间戳
希望本文提供的方案能帮助你高效解决字幕生成需求。如果觉得有用,请点赞收藏,并关注获取更多faster-whisper高级应用技巧!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



