一、操作背景
这篇基于 video-srt 开源工程进行改进,实现从视频到字幕的全自动流程。
二、代码开发
以下代码为核心思路示意,为突出逻辑主线进行了精简。完整工程(含异常处理、日志、配置管理等)见 附录 的 GitHub 链接。
三、步骤一:格式判断与音频准备
录音文件识别直接支持以下格式,无需 ffmpeg 转换:
wav、mp3、m4a、flv、mp4、wma、3gp、amr、aac、ogg-opus、flac。
如果输入文件是上述格式之一(如 mp4),直接上传到 COS 获取 URL 即可。如果是不支持的格式(如 mkv、avi、rmvb),则先用 ffmpeg 转为 wav:
# 录音文件识别直接支持的格式SUPPORTED_FORMATS = {'.wav', '.mp3', '.m4a', '.flv', '.mp4', '.wma', '.3gp', '.amr', '.aac', '.ogg', '.flac'}file_ext = os.path.splitext(input_path)[1].lower()if file_ext in SUPPORTED_FORMATS: # 直接上传,无需转换 upload_file(input_path, cos_file_path)else: # 不支持的格式,用 ffmpeg 转为 wav extract_audio(input_path, audio_path) upload_file(audio_path, cos_file_path)
ffmpeg 提取音频的命令(仅不支持格式时使用):
# 使用参数列表 + shell=False,避免路径含空格/特殊字符导致的注入风险 subprocess.run( ["ffmpeg", "-i", video_path, "-vn", "-ar", "16000", audio_path], shell=False, check=True, )
参数说明:
| 参数 | 说明 |
| -i | 输入文件 |
| -vn | 禁用视频流(只抽音频) |
| -ar 16000 | 采样率设为 16kHz(录音文件识别推荐采样率) |
四、步骤二:创建识别任务
调用 CreateRecTask 接口,关键参数如下:
req = models.CreateRecTaskRequest()params = { "ChannelNum": 1, "ResTextFormat": 3, # 按标点分段,字幕场景专用 "SentenceMaxLength": 15, # 单行字幕最大字数 "SourceType": 0, # URL 方式 "ConvertNumMode": 1 # 智能数字转换}req._deserialize(params)req.EngineModelType = "16k_zh"req.Url = audio_cos_urlresp = client.CreateRecTask(req)task_id = resp.Data.TaskId
ResTextFormat=3 与 SentenceMaxLength 的配合:
·ResTextFormat=3:服务端按标点符号(句号、逗号、问号等)对识别结果进行分段。
·SentenceMaxLength=15:如果某段超过 15 个字,服务端会自动在合适的位置拆分,确保每行不超限。
这两个参数配合,服务端完成了所有断句工作,客户端不再需要任何分行逻辑。
五、步骤三:查询识别结果
轮询 DescribeTaskStatus 接口,等待识别完成:
while True: resp = client.DescribeTaskStatus(req) status = resp.Data.StatusStr if status == "success": result_detail = resp.Data.ResultDetail break elif status == "failed": print(f"失败: {resp.Data.ErrorMsg}") return time.sleep(5)
六、步骤四:解析结果生成 SRT
识别成功后,ResultDetail 是一个 SentenceDetail 数组,每条直接对应一行字幕:
[ { "FinalSentence": "大家好,欢迎来到今天的课程。", "StartMs": 500, "EndMs": 3200, "SpeakerId": 0, "SpeechSpeed": 4.2 }, { "FinalSentence": "今天我们要讲的主题是机器学习。", "StartMs": 3500, "EndMs": 6800, "SpeakerId": 0, "SpeechSpeed": 4.5 }]
字幕生成只需关注三个字段:
| 字段 | 说明 |
| FinalSentence | 字幕文本 |
| StartMs | 开始时间(毫秒) |
| EndMs | 结束时间(毫秒) |
生成 SRT 的代码非常简洁:
def to_srt(result_detail): srt_lines = [] for i, sentence in enumerate(result_detail, 1): start_time = ms_to_srt_time(sentence["StartMs"]) end_time = ms_to_srt_time(sentence["EndMs"]) text = sentence["FinalSentence"] srt_lines.append(f"{i}\\n{start_time} –> {end_time}\\n{text}\\n") return "\\n".join(srt_lines)def ms_to_srt_time(ms): """毫秒转 SRT 时间格式 (HH:MM:SS,mmm)""" hours = ms // 3600000 minutes = (ms % 3600000) // 60000 seconds = (ms % 60000) // 1000 millis = ms % 1000 return f"{hours:02d}:{minutes:02d}:{seconds:02d},{millis:03d}"
生成结果示例:
100:00:00,500 –> 00:00:03,200大家好,欢迎来到今天的课程。200:00:03,500 –> 00:00:06,800今天我们要讲的主题是机器学习。
七、步骤五:加载字幕
将生成的 .srt 文件与视频文件放在同一目录,名称保持一致(如 video.mp4 + video.srt),使用 VLC、PotPlayer 等播放器打开视频即可自动加载字幕。
八、效果调优
| 场景 | 建议 |
| 字幕单行太长 | 调小 SentenceMaxLength(推荐 15-25) |
| 字幕太碎、频繁换行 | 调大 SentenceMaxLength(如 30-40) |
| 需要中英混合字幕 | 引擎改为 16k_zh_en |
| 需要过滤语气词(“嗯”“啊”) | 请求参数加 FilterModal=1 |
| 视频有背景音乐 | 尽量在剪辑阶段降低背景音乐音量 |
| 文件超过 1GB | URL 方式最大支持 1GB / 5 小时,超过需先分割 |
九、完整工程结构
video-srt/├── main.py # 主入口:格式判断 + 流程串联├── common/│ ├── config.py # 输出路径配置│ └── logger.py # 日志模块├── cos/│ ├── config.py # COS 配置(密钥、桶名、区域)│ └── cos_cli.py # COS 客户端(上传、获取URL)├── ffmpeg/│ └── ffmpeg.py # FFmpeg 音频提取(仅不支持格式时使用)├── tencent/│ ├── config.py # ASR 配置(密钥、引擎)│ └── tencent_cli.py # ASR 客户端(创建任务、轮询结果)└── tool/ ├── time_format.py # 时间格式化(毫秒→SRT时间) └── to_srt.py # SRT 生成(遍历结果输出字幕)
十、相关链接
·录音文件识别请求 API 文档
·识别结果数据结构
·工程代码地址