在转码的应用场景中,有时候我们非常在意目标文件的大小,在这个前提之下,再力求画质的完美。希望通过一种方法能够“精确”计算关键的编码参数,而不想一次一次的试。有办法吗?
答案是肯定的。这里可以用到二次编码(two-pass encoding)的技术。关于二次编码,上是这么说的:
二次编码VBR, (2-pass VBR), 在第一次其实是检测收集运动啊亮度等相关数据,这样在第二次编码的时候就会针对不同的场景来进行动态的压缩编码。
在视频转换时我们会用到一次编码(CBR)或二次编码(VBR)。
一次编码CBR(固定码率):保持码率基本维持在平均码率。实现简单,对复杂场景会因码率不足造成马赛克现象,对于简单场景则不能充分利用编码空间。(这里讲的复杂场景是指细节/边缘丰富以及快速变化场景)。
二次编码比一次编码质量要好一些的。但是编码时间也会增加不少。使用二次编码可以把变化不大的画面转换时码率低一些(如静态画面),而变化大的码率高一些(如打斗动作部分),这样码率是变化的,可以使整部影片的清晰度比较均匀。
假设我们有一个源视频文件D:src.mov,大小为46.3 MB,时长33秒。现在想把它转成一个10 MB的文件。通过执行ffprobe D:src.mov命令,可以发现原始音频的码率是62 kpbs。
可以这么来计算:
目标文件的整体比特率:10 x 1024 x 8 / 33= 2482 kbps
如果保持音频流原样拷贝,则目标文件的视频比特率应该是:2482- 62 = 2420 kbps
执行第一次编码
ffmpeg -i D:src.mov -c:v libx264 -preset slow -b:v 2420k -pass 1 -an -f mp4 -y NUL
因为只需要分析视频数据,这里我们使用了-an参数来抑制音频的输出。另外,我们只需要得到统计信息——在ffmpeg.exe所在的目录下,会生成ffmpeg2pass-0.log和ffmpeg2pass-0.log.mbtree这两个文件——因此,使用NUL,就不会在硬盘上输出视频文件了。
执行第二次编码
将上述命令行-pass参数后面的数值改成2,指定好目标文件路径,然后再执行一遍:
ffmpeg -i D:src.mov -c:v libx264 -preset slow -b:v 2420k -pass 2 -c:a copy D:dest6.mp4
生成的dest6.mp4大小为9.87 MB,非常接近10 MB。完美!
==========================================
ps.当然,如果想把音频做一次转码,也是可以的,如下:
ffmpeg -i D:src.mov -c:v libx264 -preset slow -b:v 2354k -pass 2 -c:a aac -b:a 128kD:dest7.mp4
有兴趣的话,还可以删除ffmpeg2pass-0.log和ffmpeg2pass-0.log.mbtree这两个文件,去掉-pass参数,一次性编码生成目标文件。命令行如下:
ffmpeg -i D:src.mov -c:v libx264 -preset slow -b:v 2420k -c:a copy D:dest8.mp4
然后分别播放dest6.mp4和dest8.mp4,对比一下“一次编码”与“二次编码”的效果差异。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/292512.html