x265无损压缩

2022-03-24 08:41:32 浏览数 (1)

今天接到一个需求,需要把YUV序列转换为无损的MP4。一开始准备是用x264编码,把QP设置为0。但这样压缩后,我比较了一下,发现实际上还是有损的。而且QP设置为0后,普通的播放器根本不能打开,只能用基于ffmpeg的播放器才能正常播放。后来想到265有Transform Quantizer Bypass(TQB)技术,本身就就支持无损编码,遂进行了尝试。

ffmpeg把YUV无损转换为MP4的命令行代码:

代码语言:javascript复制
ffmpeg -s 1920x1080 -pix_fmt yuv420p -r 60 -i .BallUnderWater_1920x1080_60fps.yuv 
-c:v libx265 -preset ultrafast -x265-params lossless=1 output_265.mp4

主要在x265指定了lossless=1(开始无损压缩)参数。

现在我们虽然得到了转换后的MP4文件,但是我想进一步验证得到的文件到底是不是无损的。在查询官方文档的时候我看了官方给出了两种验证方式:

  1. 在转换完成后,命令行中最后一行只要出现lossless compression ratio就表明是无损压缩
  2. 可以通过计算原始YUV的hash值和转换为MP4视频后的hash。若hash值一致,则说明是无损转换。这里是计算整个视频的hash值的例子和单独对每一个视频单独帧计算hash值例子。

通过计算hash和framehash,发现原始视频的hash和frame与转换后得到的MP4文件的hash和framehash值完全一致。着说明确实是无损压缩。

更进一步,既然是无损压缩,那么把MP4文件转换为YUV(我们叫做新YUV),再计算原始YUV和新YUV的PSNR,那么每一帧的PSNR肯定都是无穷大。为啥是先把MP4文件转换为YUV呢?这是因为MP4文件的timebase和原始YUV的timebase不一致,那么两者的每一帧不能一一对应,其计算出的PSNR就不准确了。 话不多说,开动!

  1. 把MP4文件转换为YUV
代码语言:javascript复制
 ffmpeg -i .BallUnderWater_1920x1080_60fps.mp4  newyuv.yuv
  1. 计算两个YUV文件的PSNR
代码语言:javascript复制
 ffmpeg -s 1920x1080 -pix_fmt yuv420p -r 60 -i .BallUnderWater_1920x1080_60fps.yuv -s 1920x1080 
-pix_fmt yuv420p -r 60 -i .newyuv.yuv  -lavfi psnr=stats_file=psnr_logfile.txt -f null -    

最终的PSNR结果如下面两张图,可以看出PNSR确实为无穷大。

平均PNSR

每一帧的PSNR

0 人点赞