视频字幕自动生成研究
最近「Virgin Punk: Clockwork Girl」蓝光发布,然后我去下载观看,觉得有意思,就去看导演「梅津泰臣」的其他几个作品。
- A Kite (1998)
- Mezzo Forte (2000)
- Kite Liberator (2008)
这些作品资源很难查找,找到之后模糊不清。然后就是没有中文字幕。比如「Mezzo Forte」的 DVD 资源我就尝试使用 Anime4K 项目 Anime4K_Upscale_Denoise_CNN_x2_L.glsl 配合 ffmpeg 滤镜进行放大,发现一点效果都没有,再次感谢网络上那些压制组。
目前最大的问题,就是这些上古资源缺少较好的存储与分发渠道,各种方方面面的因素。
「A Kite」我是下载蓝光资源 https://sukebei.nyaa.si/view/4180043,然后直接播放 00006.m2ts 文件,提取里面英语音频转为 16KHz .wav 格式音频,
接着就是使用 ggml-org/whisper.cpp 识别生成字幕,生成的 .srt 字幕准确率非常高,基本可以直接食用。
不过我还是要转换成为中文字幕,在 Google AI Studio 里面使用 gemini-3.1-pro-preview 模型,60 分钟左右的电影可以在一个上下文内完成翻译而不会爆上下文窗口。感谢那个年代的电影台词都比较少。
另外一个这些模型训练的时候都带有这些视频的数据吧,如果在 prompt 里面明确提及作品的名称是有神秘 buf 加成的。这么做出来的中文字幕,以我喳喳 4 级的水平倒是也没有什么问题,但是比起精校字幕还是有一段差距。
「Kite Liberator」这个有现成资源所以没有折腾。然后就是「Mezzo Forte」我找到的是 DVD 资源 https://sukebei.nyaa.si/view/4105561 。
再次尝试使用 whisper.cpp 生成字幕,使用的 medium 模型,上面识别英语的模型是 base.en ,这里不得不提一下,因为感觉 「A Kite」英语配音是后配音的,声音非常干净和清晰,所以非常好识别。但是这里的日语配音就出现各种问题了。英语配音和日语配音是有出入的,意思就是英语翻译字幕必须配合英语音轨,日语配音配合日语翻译字幕。
这里说一下为什么执着使用 whisper.cpp 而不是其他方案呢?因为在音轨生成字幕还是其他涉及 AI 模型的工具都是 python 工程,python 作为软件工程我一直觉得很狗屎,而且 GPU 加速接口都是 CUDA,对于非 N 卡用户实在不友好。要么跑 CPU,要么 N 卡。whisper.cpp 和 llama.cpp 都支持 Linux Vulkan 接口加速并且非常高效还有稳定。
说回来,日语字幕生成和翻译遇到的问题吧:
- 日语可以识别,不过还是会出现一些没有的句子,但是不多耐心校验一下就搞定
- 时间轴出现偏移,这个很要命,不知道为什么部分字幕出现了 10s 左右的偏移,明明能正确识别了
- 我提取音频,分为两段每段 30 分钟左右,识别翻译最后拼接。使用 Google 计量付费接口,烧了一顿饭钱我有点心疼
我学过一点点日语,直接食用没有什么问题,但是还是影响体验。为了修复时间轴偏移问题,我尝试添加 Silero-VAD ,但是添加之后没法正常工作,简单说就是没有办法开箱即用。
然后,昨天晚上睡觉前搜索一下,感觉是不是可以折腾 Qwen3-ASR ,大家都是 CJK 区的人类,对于日漫支持会比较好吧。
我开始构思这么一个软件或是说处理管道,whisper.cpp 生成字幕并不是底层模型携带的能力,而是软件工程。
- 提取音频,并且转换 16KHz 采样频率
- 使用 VAD 模型对音频进行切片,流行方案是 github.com/snakers4/silero-vad
- 调用 Qwen3-ASR 模型处理输入获得输出,输出没有包含时间信息,需要自己记录时间
- 生成
.srt字幕,这个格式非常简单,字符串拼接就行了
然后我最近又是一直编写 Rust 代码,所以打算使用 Rust 实现。
- 使用 ffmpeg 读取音轨文件
- 使用 hound crate 加载
.wav文件或是通过标准输出从 ffmpeg 读取也行 - 我发现 silero-vad 官方 Rust 例子是使用 ort 加载
.onnx模型,运行在 CPU 上,模型大小 2.2M - Qwen3-ASR 调用方案有两个,一个是用 ort 加载执行。另外一个是使用 tch 加载运行。
- github.com/second-state/qwen3_asr_rs 这个就是使用 tch 加载运行的,我本地运行没啥问题,0.6B 的模型也还行,但是 CPU 端运行感觉效率有点低。
好吧,暂时就先这样吧,等有时间再填坑了。