本文分享了作者用FFmpeg压缩视频的故事,通过测试不同的-ctf参数,将200多MB的视频文件压缩到不到10MB,画质没有明显下降。原文如下:
昨天,有个朋友给我出了个难题:他手上有一个视频,1080P的,49秒,200多兆;要求在确保质量的情况下把文件压缩到10M以内。这是什么概念呢?按照文件大小10M来计算,码率是:10x 8 / 49 = 1.6 Mbps。也就比VCD的质量略好一点(注:VCD的标准码率是1150Kbps)。谈何“确保质量”?missionimpossible啊!咱还是现实一点吧。在不明显损失画质的前提下,看看使用FFmpeg能够帮到多少忙。用iPhone拍了一个1920x 1080的视频,33秒,46.3MB,编码格式是H.264。考虑到H.264目前尚是主流的视频格式,为了播放的兼容性,我们在使用FFmpeg转码时同样选择H.264。
命令行参数-crf
在优先保证画面质量(也不太在乎转码时间)的情况下,使用-crf参数来控制转码是比较适宜的。这个参数的取值范围为0——51,其中0为无损模式,数值越大,画质越差,生成的文件却越小。从主观上讲,18——28是一个合理的范围。18被认为是视觉无损的(从技术角度上看当然还是有损的),它的输出视频质量和输入视频相当。
我们的策略是,在保证可接受视频画质的前提下,选择一个最大的crf值——如果输出视频质量很好,那就尝试一个更大的值;如果看起来很糟,那就尝试一个小一点的值。
让我们先执行下面这条命令:
ffmpeg -i D:src.mov -c:v libx264 -preset veryslow -crf 18 -c:acopy D:dest1.mp4
意思是:将D盘的源文件src.mov,以“非常慢”的速度重新编码成H.264格式,保存为D:dest1.mp4。其中,-preset指定的编码速度越慢,获得的压缩效率就越高。而-c:acopy又是什么意思呢?因为音频的码率一般都比较小,我们就不折腾它了,况且解码后重新编码也会损害音质,于是,就将音频数据从源文件中以原有编码格式直接拷入目标文件吧。
小提示:想知道-c:v 后面的参数值怎么填吗?或者说FFmpeg到底支持哪些音视频编码格式?执行ffmpeg–encoders看一下吧。另外,执行:
ffmpeg -i D:src.mov -c:v libx264 -preset -tuneD:dummy.mp4
可以看到-preset参数的取值范围。
有个小疑问:既然不在乎等待时间,为什么不给-preset指定一个最慢的placebo呢?那是因为:与veryslow相比,placebo以极高的编码时间为代价,只换取了大概1%的视频质量提升。这是一种收益递减准则:slow 与medium相比提升了5%——10%;slower 与 slow相比提升了5%;veryslow 与slower相比提升了3%。
另外,针对特定类型的源内容(比如电影、动画等),还可以使用-tune参数进行特别的优化。但如果你不确定该用哪个选项,还是忽略这个参数吧。
对比效果
执行完一条转码命令之后,调整-crf参数值,分别设为19、20、28、51,重新转码输出为不同的MP4文件。记录数据,对比如下:
源 文件大小 缩减比率
crf = 18 46.3 21%
crf = 19 36.7 33%
crf = 20 31.2 43%
crf = 28 26.5 83%
crf = 51 1.25 97%
尝试播放这些文件。发现crf取值为18——28的情况下生成的文件,其画质没有明显的差异,而以-crf51生成的视频画质已经惨不忍睹了!在实际应用中,多试几个crf值,在画质和压缩比之间找到一个你能接受的平衡点即可。