ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

外文视频中文字幕制作全流程:从音频抽取到FFmpeg硬字幕压制

外文视频中文字幕制作全流程:从音频抽取到FFmpeg硬字幕压制 最近拿到一段活动庆功宴的现场视频内容是日语对话目标是在尽量短的时间内产出一版带中文字幕的成片。和身边做内容的朋友聊下来我发现“中字”这件事看起来只和翻译有关真正决定质量和效率的其实是一整条音视频处理链路——音频抽取、语音识别、字幕时间轴、翻译润色、字幕封装、硬字幕压制每一步都可能成为卡点。“salt-ye 中字”这个版本由谁制作并不重要重要的是这类中字视频背后是一套可以被个人开发者完整复用的工程流程。过去要手动听写、一句一句对轴一段 20 分钟的视频可能要耗掉整整一天现在用语音识别模型生成带时间轴的粗稿再在字幕工具里做精修整个流程的耗时可以缩短到原来的三分之一以下而质量的好坏主要取决于你是否理解这条链路里每个环节的原理。这篇文章会从零开始完整拆解“外文视频 → 中文字幕成片”的制作流程覆盖工具选型、环境搭建、语音识别脚本、时间轴校对、字幕格式转换和 FFmpeg 压制。文章尽量照顾到没有音视频处理经验的后端和算法工程师也会指出一些新手最容易踩的坑。认真看完你应该能独立完成一版可用中文字幕视频。1. 这篇文章真正要解决的问题如果你也尝试过给外文视频做中文字幕多半遇到过下面这些情况在线工具能识别语音但导出的字幕没有时间轴或者时间轴错位严重。翻译出的文字是对的但字幕在画面上停留时间太短根本来不及看完。做完字幕之后不知道怎么“贴”到视频里播放器也不认。下载了各种字幕格式搞不清 SRT 和 ASS 有什么区别更不知道什么时候该用哪一种。这些问题的根源不是翻译能力不够而是流程没有打通。字幕制作的核心是“让声音变成可检索、可编辑、可渲染的文字”它至少包含四个独立能力语音转文字、翻译、时间轴控制、字幕渲染与封装。把这四件事分开想每一件都能用成熟工具解决混在一起想就会觉得什么都要自己写最后什么也做不好。这篇文章要处理的就是这条链路的完整打通。我在方案设计上偏重“命令行 脚本”路线而不是只依赖某个图形化软件。原因是图形化软件虽然上手快但无法批量处理也不容易嵌入到自动化流程里而命令行工具只要掌握一次以后处理多集视频、多语言字幕、批量压制都会轻松很多。文章最后会给出一个最小可用的工程方案用 FFmpeg 抽取音频用 faster-whisper 做语音识别生成带时间轴的文本用 Aegisub 修正时间轴和断句并输出 ASS 字幕再用 FFmpeg 将字幕封装进 MKV或者压制成硬字幕 MP4。这套方案特别适合三类读者个人创作者需要给活动录像、课程视频或访谈内容做中文字幕技术运营人员需要批量处理视频素材并生成字幕文件想入门音视频处理或语音识别应用的开发者可以把它当作一个完整的工程示例。2. 字幕制作的核心概念与适用场景在动手操作前先建立几个基本概念。字幕制作并不只是“把文字写上去”它本质上是一个“时间轴 文本 样式”的数据处理问题。2.1 语音识别与时间轴语音识别Automatic Speech RecognitionASR把音频里的语音转换成文字。主流模型在输出文字时还会附带每个片段的时间范围例如“这句话从第 12 秒开始到第 15 秒结束”。这个时间范围就是字幕的“轴”。没有时间轴字幕就不能和声音对应时间轴不准字幕就会“抢拍”或“慢半拍”。判断一个字幕工具是否好用第一看识别准确率第二看时间轴粒度是否够细。现在常用的 Whisper 系列模型输出的时间戳精度已经可以到 100ms 左右基本满足人工校对需求。2.2 SRT 与 ASS字幕格式有很多种但日常见得最多的是 SRT 和 ASS。SRT 是最通用的字幕格式几乎被所有播放器和剪辑软件支持。它的结构非常简单序号、时间段、字幕文本。因为简单它非常适合作为数据交换格式也适合自己用脚本生成。ASSAdvanced SubStation Alpha在 SRT 基础上增加了样式控制能力可以设置字体、字号、颜色、描边、位置、滚动效果等。它适合对画面效果有要求的场景比如日式字幕的“彩色弹幕风”、综艺字幕的“底部大字”效果。特性SRTASS结构复杂度低中高播放器兼容性广泛较广泛但不如 SRT样式控制不支持支持字体/颜色/位置/特效是否适合脚本生成非常适合可以但需要维护样式代码块是否适合嵌入压制可以更适合因为可自定义渲染样式实际项目中建议先由脚本产出 SRT再在 Aegisub 中另存为 ASS 做样式调整。如果只做个人学习用SRT 足够如果要发布到视频平台ASS 能提供更好的观感。2.3 软字幕、内封字幕与硬字幕这三个词描述的是“字幕以什么方式存在”。软字幕字幕是独立文件比如.srt和.ass。播放器可以随时切换开关和样式。内封字幕字幕作为独立轨道封装进 MKV 等容器格式里。播放时可以选择显示或隐藏也可以切换多语言字幕。硬字幕字幕被渲染成画面的一部分重新编码进视频流无法关闭。从制作到发布我的建议流程是先保留 SRT/ASS 源文件再生成一份内封字幕的 MKV 用于本地观看最后在需要上传平台时压制一份硬字幕 MP4。这样既能保留可编辑性也能应对不同发布渠道。2.4 适用场景与不适用场景这套方案最适合“非实时、可校对、有明确授权”的视频内容比如活动录像、访谈、课程、同人翻译等。它不适合实时直播字幕因为实时场景需要流式识别和低延迟输出工具链会完全不同。另外要特别强调一点字幕制作必须基于合法获取的内容。无论是制作还是发布都要遵守版权规则和平台条款不要用这套流程去传播未经授权的作品。3. 环境准备与前置条件下面开始搭建环境。我以 Windows 为示例但命令在 macOS 和 Linux 上基本一致少量路径和安装方式不同。3.1 需要安装的软件建议安装以下工具FFmpeg用于音频抽取、视频编码、字幕封装。Aegisub用于字幕时间轴调整和样式设置。Python 3.10用于运行语音识别脚本。faster-whisper语音识别引擎基于 CTranslate2比原生 Whisper 更快也更省显存。版本请以各自官网当前版本为准本文不固定具体版本重点演示通用思路。3.2 安装 FFmpegWindows 用户推荐从 FFmpeg 官网下载已编译好的 build 文件解压后将bin目录添加到系统环境变量PATH中。也可以在包管理工具中安装。macOS 用户可以使用 Homebrewbrew install ffmpegLinux 用户可以使用 apt 或 yumsudo apt update sudo apt install ffmpeg安装完成后打开终端执行ffmpeg -version能正常显示版本信息表示安装成功。3.3 安装 AegisubAegisub 是一款经典字幕编辑器。它主要用于手动调整时间轴、检查断句、设置 ASS 样式。Windows 用户直接下载安装包即可macOS 和 Linux 可以通过应用商店或源码编译安装也可以使用其他同类字幕工具替代。3.4 创建 Python 虚拟环境建议为字幕项目单独创建虚拟环境避免污染全局 Python。在项目目录下执行mkdir subtitle-project cd subtitle-project python -m venv venvWindows 下激活venv\Scripts\activatemacOS / Linux 下激活source venv/bin/activate然后安装依赖pip install --upgrade pip pip install faster-whisper如果需要在生成字幕后再做进一步处理也可以安装ffmpeg-python但它只是 FFmpeg 命令行的封装不是必须依赖。faster-whisper 首次运行时会从 Hugging Face 下载模型文件。如果你所在网络访问 Hugging Face 较慢可以提前设置镜像环境变量或手动下载模型到本地目录然后再指定模型路径。这部分属于网络环境问题不同人情况不同这里不展开。4. 核心流程拆解从原始视频到带中文字幕的成片完整流程可以拆成六个步骤。4.1 抽取音频视频文件里包含视频流和音频流。语音识别只需要音频因此第一步是把音频抽取出来。如果跳过这一步直接对视频文件做识别也不是不行但视频解码会占用额外资源处理速度更慢。更重要的是单独提取出的音频可以预处理比如降低噪声、调整音量提升识别质量。FFmpeg 命令非常简单ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 audio.wav这里的参数含义是-vn不处理视频流-acodec pcm_s16le输出 PCM 16 位小端编码的 WAV-ar 16000采样率设为 16000 Hz-ac 1转为单声道。很多语音识别模型在 16kHz 单声道音频上效果最好所以这个转换很值得做。4.2 语音识别生成带时间戳文本把 WAV 文件交给 faster-whisper 后模型会返回多个片段segment每个片段都包含开始时间、结束时间和识别文本。这是字幕制作最核心的“粗稿”来源。4.3 清洗与翻译识别结果通常存在两个问题一是断句位置不合适可能一句被切到两行二是识别文本里可能有语气词、重复词。此时需要先按语义重新断句再进行翻译确认中文表达符合观众的阅读习惯。这一步最耗时也最依赖人的判断。我的建议是先让模型生成日语文本再由人工或大语言模型翻译成中文不要直接让模型生成“日译中”的字幕因为多任务同时做准确率不如分开做高。4.4 时间轴校对把清洗后的翻译文本导入 Aegisub把每一条字幕对齐到正确的开始时间和结束时间。语音识别给出的时间戳不是完美的尤其是语速快、背景音嘈杂的片段需要人工微调。这里有一个关键原则字幕显示时间不宜过短也不宜过长。成年人阅读一行 15 到 20 个汉字大约需要 1.5 到 2 秒如果一行字幕只停留 0.8 秒观众根本读不完。4.5 导出 SRT / ASS在 Aegisub 中完成时间轴和样式调整后可以导出 SRT 或 ASS。如果只是做内封字幕ASS 可以直接封装进 MKV如果后续要压制成硬字幕ASS 也是首选因为 FFmpeg 的ass滤镜会按照 ASS 的样式渲染。4.6 合成输出最后一步是把字幕与视频合成为成片。可以选择“内封”或“硬压”。内封速度快因为不需要重新编码视频流硬压需要重新编码但兼容性最好。这一步我们在下一节用完整命令演示。5. 完整示例与代码实现现在用最小项目把上述流程串起来。我们假设项目里已经有一个文件名为input.mp4的视频素材。5.1 抽取音频在项目目录下执行ffmpeg -i input.mp4 -vn -acodec pcm_s16le -ar 16000 -ac 1 audio.wav执行完成后项目目录下会出现audio.wav。可以用ffprobe -v error -show_entries streamcodec_name,sample_rate,channels -of defaultnoprint_wrappers1 audio.wav查看音频参数确认是pcm_s16le、16000 Hz、单声道。5.2 语音识别并生成 SRT在项目目录下新建transcribe.py# 文件路径subtitle-project/transcribe.py from faster_whisper import WhisperModel # 模型名称可选tiny / base / small / medium / large-v3 # 显存充足时建议用 medium 或 large-v3准确率更高CPU 环境建议 small。 model_size small # device 可选 cpu 或 cuda这里以 CPU 为例 model WhisperModel(model_size, devicecpu, compute_typeint8) def format_timestamp(seconds: float) - str: 把秒数转换为 SRT 时间格式00:00:01,234 ms int((seconds - int(seconds)) * 1000) s int(seconds) % 60 m (int(seconds) // 60) % 60 h int(seconds) // 3600 return f{h:02d}:{m:02d}:{s:02d},{ms:03d} def transcribe_to_srt(audio_path: str, output_path: str, language: str ja): segments, info model.transcribe( audio_path, languagelanguage, vad_filterTrue, beam_size5, ) with open(output_path, w, encodingutf-8) as f: index 1 for segment in segments: f.write(f{index}\n) f.write( f{format_timestamp(segment.start)} -- f{format_timestamp(segment.end)}\n ) f.write(f{segment.text.strip()}\n\n) index 1 print(f识别完成字幕文件{output_path}) if __name__ __main__: transcribe_to_srt(audio.wav, raw.srt, languageja)运行python transcribe.py脚本逻辑不复杂核心就三步加载 Whisper 模型对音频做识别获得带时间戳的片段按 SRT 格式写入文件。vad_filterTrue可以过滤掉没有语音的片段减少大量静音时间上的无用字幕。beam_size5是解码束宽数值越大结果往往越稳但速度会变慢。输出文件raw.srt里的文本是日语原文。我们可以先打开看看断句和时间轴是否合理。5.3 为 SRT 生成 ASS 基础模板Aegisub 打开 SRT 后可以设置样式并另存为 ASS。但如果你希望脚本直接生成带基础样式的 ASS可以写一个稍加扩展的脚本。为了控制篇幅这里给出一个最小模板# 文件路径subtitle-project/srt_to_ass.py import re def srt_to_basic_ass(srt_path: str, ass_path: str): with open(srt_path, r, encodingutf-8) as f: content f.read() # 简单解析 SRT把时间轴行转为 ASS 格式 lines content.strip().splitlines() ass_lines [] i 0 while i len(lines): if re.match(r^\d$, lines[i].strip()): timing lines[i 1].strip() text lines[i 2].strip() start_raw, end_raw timing.split( -- ) start start_raw.replace(,, .) end end_raw.replace(,, .) ass_lines.append(fDialogue: 0,{start},{end},Default,,0,0,0,,{text}) i 3 else: i 1 header [Script Info] ScriptType: v4.00 PlayResX: 1920 PlayResY: 1080 [V4 Styles] Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding Style: Default,Microsoft YaHei,72,H00FFFFFF,H000000FF,H00000000,H80000000,-1,0,0,0,100,100,0,0,1,3,0,2,80,80,80,1 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text with open(ass_path, w, encodingutf-8) as f: f.write(header) f.write(\n.join(ass_lines) \n) if __name__ __main__: srt_to_basic_ass(raw.srt, output.ass)这里生成的 ASS 字体设为“Microsoft YaHei”字号为 72字幕默认显示在底部中间。真正的样式调整还是建议在 Aegisub 里可视化操作脚本适合快速生成初稿。5.4 内封字幕到 MKV如果你希望字幕作为独立轨道存在可以用 FFmpeg 把 SRT 或 ASS 封装进 MKV。以 ASS 为例ffmpeg -i input.mp4 -i output.ass -c copy -c:s ass -metadata:s:s:0 languagechi output.mkv解释一下参数-c copy视频流和音频流直接复制不重新编码速度非常快-c:s ass字幕流使用 ASS 编码-metadata:s:s:0 languagechi给第一个字幕流标注语言为中文。这个命令适合保存“带字幕轨道的原画质版本”。MKV 播放器一般都能正常显示字幕轨道。5.5 硬字幕压制到 MP4需要上传到视频平台或发给无法切换字幕轨道的用户时可以压制成硬字幕ffmpeg -i input.mp4 -vf assoutput.ass -c:v libx264 -crf 18 -preset slow -c:a aac -b:a 192k output_hard.mp4参数含义-vf assoutput.ass通过 libass 渲染 ASS 字幕到视频画面-c:v libx264使用 H.264 编码视频-crf 18画质参数数值越小质量越高一般 18 到 23 都可接受-preset slow编码速度与压缩率的权衡slow 压缩效果更好但编码更慢-c:a aac -b:a 192k音频转成 AAC码率 192k。这段命令是本流程里最容易超过预期时间的一步因为它是重新编码不是复制。视频越长、电脑性能越弱耗时越长。建议先压制 30 秒片段测试确认样式和编码效果后再跑全片。6. 运行结果与效果验证做完字幕封装或压制成片后不能只看文件是否生成还要验证三件事字幕是否存在、时间轴是否准确、样式是否符合预期。6.1 验证字幕轨如果输出的是 MKV 内封字幕用 ffprobe 查看ffprobe -v error -show_entries streamindex,codec_name,codec_type:stream_tagslanguage -of defaultnoprint_wrappers1 output.mkv输出里应该能看到三组流视频流、音频流、字幕流。其中字幕流的codec_type为subtitlecodec_name为ass或subriplanguage为chi。如果看不到字幕流说明 FFmpeg 命令没有把字幕封装进去。最常见的原因是用-c copy但输入字幕格式和输出容器不兼容比如把 SRT 直接复制到某些容器时可能没问题但 ASS 在某些播放器上兼容性稍差。6.2 验证时间轴打开raw.srt或 Aegisub 工程随机抽看几条字幕对比对应时间点的语音。重点检查字幕开始时间是否明显早于语音字幕结束时间是否覆盖到说完这句话是否存在一条字幕跨了两句话、而中间有很长停顿的情况。如果发现整段字幕整体偏移比如全部慢了 0.5 秒可以在 Aegisub 里全选字幕整体调整偏移量不需要逐条改。6.3 验证硬字幕效果硬字幕压制完成后用播放器打开片段对比原视频。重点看中文字体是否正常显示有没有变成方块底部字幕是否被视频内容遮挡字幕颜色和描边是否清晰可读。如果字体显示不对检查 ASS 文件里Fontname指定的字体是否存在于系统里。Windows 一般都有“Microsoft YaHei”macOS 建议改为“PingFang SC”Linux 可以改成“Noto Sans CJK SC”。7. 常见问题与排查思路问题现象可能原因排查方式解决方案识别结果为空音频采样率或编码不受支持检查 WAV 参数确认文件是否有声音用 FFmpeg 统一转成 16kHz、单声道、PCM WAV识别时间轴错位严重模型过小、音频噪声大试听原音频检查是否有重音/背景音使用 larger 模型开启 VAD先做音频降噪字幕显示时间过短Whisper 断句过碎检查 SRT 片段密集度在 Aegisub 中合并相邻片段并延长显示时间SRT 内封后播放器不显示播放器对字幕轨兼容性差用 VLC 等播放器测试改用 MKV ASS或直接压制成硬字幕硬字幕出现方块字系统缺少 ASS 指定字体检查 ASS 中 Fontname 与系统字体修改 Fontname 为系统已有中文字体压制速度极慢没有硬件编码编码预设过高查看 CPU 占用和编码日志改用-preset medium或开启 GPU 编码小尺寸视频压制后字幕模糊硬字幕渲染分辨率不足观察视频分辨率在 ASS 里调整 PlayResX/PlayResY匹配视频分辨率模型加载失败网络无法访问模型仓库检查下载日志手动下载模型并指定本地路径如果运行 Python 脚本报错第一步应该看完整堆栈信息而不是只看最后一行。faster-whisper 的报错通常很明确比如模型路径错误、缺少依赖、内存不足等按堆栈找原因即可。8. 最佳实践与工程建议前面完成了整体流程最后补充一些能让工作更稳定、更专业的建议。8.1 先跑 30 秒样例再跑全片无论是语音识别还是硬字幕压制都建议先切出一段 30 秒到 1 分钟的视频做测试。这样可以在短时间内确认模型选择、识别准确率、字幕样式和编码时间是否符合预期。全片跑完了再发现识别质量差返工成本会高很多。切片段可以用ffmpeg -i input.mp4 -ss 00:02:00 -t 00:00:30 sample.mp4-ss表示开始时间-t表示持续时间。这样生成的sample.mp4足够短方便快速验证。8.2 按清晰目录管理素材建议为每个视频建独立目录subtitle-project/ input/ episode01/ input.mp4 audio.wav raw.srt edited.ass output.mkv output_hard.mp4 scripts/ transcribe.py srt_to_ass.py好处是后续再次编辑时不用翻半天找文件。如果做系列视频这种结构可以根据时间版本扩展。8.3 保留 SRT/ASS 工程源文件压制完 MP4 后不要删除字幕原始文件。后续如果要修改措辞、调整样式、翻译成其他语言只要修改 SRT/ASS再执行一次 FFmpeg 就能出新的成片。否则每次都要重新识别和校对时间轴非常浪费。8.4 断句与阅读节奏优于逐字翻译字幕的最终目标是让观众在短时间内看懂而不是做逐字直译。中文字幕每行建议控制在 15 到 20 个字过长容易导致阅读吃力。如果原话太长可以拆成两行但每一行的显示时间都要足够避免出现一屏弹出一大段文字的情况。8.5 用脚本固化重复操作在完成一段视频的流程后可以尝试把“音频抽取 → 识别 → 生成 SRT → 基础 ASS”串成一个脚本例如用 Python 的subprocess调用 FFmpeg再调用transcribe.py。这样做的好处是以后处理多集视频时只需要改文件名不需要重新敲命令。以下是一个简单的批量思路# 文件路径subtitle-project/run_pipeline.py import subprocess def run(cmd: list[str]) - None: print( .join(cmd)) subprocess.run(cmd, checkTrue) video episode01.mp4 audio episode01.wav run([ffmpeg, -y, -i, video, -vn, -acodec, pcm_s16le, -ar, 16000, -ac, 1, audio]) run([python, transcribe.py])实际使用时可以把transcribe.py改成接收参数的模式以便传入不同音频和输出路径。核心思路是“命令可重复执行参数可配置”这是把字幕制作工程化最直接的一步。8.6 明确版权边界与合规意识字幕制作工具本身没有合规问题但使用场景必须考虑版权。对于受版权保护的视频内容制作字幕前要确认是否获得了授权是否允许二次加工和发布。个人学习、本地备份、平台授权许可范围内的二次创作都属于合理使用场景未经授权传播他人内容风险由使用者自行承担。技术文章讲的是流程方法具体使用时请务必遵守平台和版权方规则。8.7 性能与编码建议Whisper 模型在 CPU 上也能运行但大模型和长视频会让识别时间明显变长。有条件的话优先使用带 CUDA 的 GPU 环境并将device设置为cuda。如果只能在 CPU 上运行选择small或base模型同时开启vad_filter减少无效计算。硬字幕压制也一样。libx264是纯 CPU 编码如果电脑支持 NVENC 或 QSV可以换成-c:v h264_nvenc或-c:v h264_qsv速度会快很多。输出文件更大还是更小取决于码率设置这部分需要根据实际效果做权衡。9. 后续可以继续深入的方向把这条链路跑通之后你会发现字幕制作真正耗时的环节已经从“听写”变成“校对和翻译”。如果希望进一步把流程自动化可以研究这几个方向使用更大规模的 Whisper 模型对比不同模型在带噪语音上的识别准确率引入大语言模型对识别文本做自动断句和翻译润色生成更自然的双语字幕编写脚本批量处理整个目录下的视频文件并自动生成逐集字幕清单在 ASS 基础上研究特效标签做出更精致的综艺感和排版效果借助 FFmpeg 的滤镜链把字幕渲染、水印、转场统一到一套自动化脚本里。从个人创作者的角度看“东pa庆功宴”这类中字视频之所以能快速完成关键不在于某个单一工具有多强而在于整条链路里每一个环节都被拆成了可复用、可调试、可以单独优化的模块。下次再拿到一段外文视频你也可以先试着跑一遍这套流程再根据实际效果调整具体环节。
返回列表