我7月底刚接触翻译和字幕工作时,认识到做字幕第一步是调时间轴。不过,第一次用Aegisub打开视频时,我就注意到右上角似乎已经把视频分好段了:
如果直接使用这些分段,是不是就不用调时间轴了呢?
(资料图片仅供参考)
经过研究,Aegisub会自动将视频的关键帧标注在时间轴上。简要介绍一下,关键帧(keyframe)是视频压缩的核心原理之一。基于视频是每一帧连续变化的特点,即帧与帧之间的图像差别一般较小,只要适当地间隔选取一些帧完整记录下来,其他帧只需记录与前一帧的差别,就可以缩小视频体积,播放时也能复原出视频。
对于静画为主的MMD视频,画面多数时候是完全不变、一旦变化就是突变,因此关键帧的选取一般为突变后的第一帧,对于时间轴的调整帮助很大。Video选项卡中,可以直接导出关键帧:
保存的文件为纯文本,格式如下:
有了关键帧,就能据此初步做一个自动时间轴的程序。当时我直接采用最简单的字幕格式srt:
使用我最熟悉的C++写了一个简单的转换程序。输入文件中,把前三行去掉。Aegisub的这个功能有bug无法识别帧率(fps),因此要手动看一下。
生成的srt字幕效果如下:
但是仔细一看,字幕分开的地方是正确的,但是很多地方没有分开。比如18话,制作完成后,从131行字幕增加至251行。
原因在于,每一幅图片,都可能对应两三句台词。在说这两三局台词时,画面主体没变,只有下方的字幕改变了,因此基本不会被记录作关键帧。在实际翻译时,还要手动将这些台词分开。
不过,这样已经能够节省大约一半的时间轴工作量了。由于不了解视频格式和视频处理,当时我也只是顺手做一下节约体力的事,之后就暂时利用这个方法制作了几个视频。
方法改进的思路也很简单,就是使用程序检测出所有的突变并记录下来,代替视频自带的关键帧。只是涉及知识技术比较多,之前暂时没有学着做。
昨天去亲戚家吃饭的时候,由于没有事做,就开始着手学习使用c++的视频处理的技术。刚开始时毫无头绪,“简中互联网”的搜索引擎搜出来全是卖课程的,各种网站抄来抄去还抄不全。回家之后,看了一些日文网站和英文网站,决定使用FFmpeg的方法库,但刚理解了原理,还是难以下手。不过,偶然发现了已故大神雷霄骅2013年的博客:
链接: http://t.csdn.cn/HkZQk
系列教程循循善诱、深入浅出。阅读之后,真是醍醐灌顶,豁然开朗。并且,附带的工程样例也是简洁精炼,读懂代码也很容易。今天早晨起来之后,我直接在大神的播放器工程的基础上,去掉播放部分,加上简单的判断部分,实现了判断突变帧的功能,功能代码如下:
具体思路如下:
1. 在以静画为主的视频中,也有连续变化的部分,如淡入淡出。此时,需要判断视频是否处在连续变化之中,连续变化的部分只取开头,避免每一帧都分一段。
2. 由于视频压缩是有损的,因此看上去不变的画面,在压缩之后可能会出现部分变化。因此,不能简单地判断画面有无变化,我的初步解决方案是设定一个阈值(threshold),统计改变的像素数量超过阈值时,就判定画面发生变化。对于720p(1280*720)的视频,我设置为12800,即画面的1/72,使用24话试验(见头图),取得了很好的效果。
另外,输出格式对应之前的转换程序。
这个程序的缺点很明确,逐帧逐像素对比的土方法效率过低,使用i5-11400单线程处理10min 720p@30fps的视频需要十几秒(TLE)(迫真);使用内存也达到了约500M(MLE);阈值是我随便设的,这次效果很好,但下次可能会漏一些地方(WA)。改进的思路有:只对比视频的字幕部分、模糊比对、随机采样等等,有机会可能也会试验一下其他类型的视频。既然已经满足了需求,暂时就放在这里。
总之是现学现卖写出来的破烂。程序就我自用了,仅分享一下思路,如果有大佬可以改进,或者向我介绍一下有没有现成的轮子,非常感谢~
最后,感谢已故雷霄骅大神对音视频处理技术的无私分享,也怀念过去的中文互联网。虽然我很多时候倾向于在油管看视频、在其他国外平台学习知识,但毕竟是真真正正的国人,希望自己的微小的工作能让明天会更好。