【发布时间】:2020-11-08 10:55:07
【问题描述】:
我一直在使用ffmpeg 和其他压缩工具来比较 YUV420 重采样视频的速率失真曲线。
在这些比较中,ffmpeg 的结果始终较差,PSNR 值低 0.5-1.0 dB。
我跟踪到ffmpeg在RGB和YUV420之间的转换问题。
为简化起见,让我们假设“无损压缩”,因此只考虑 RGB -> YUV420 -> RGB。
此外,我们对单个 PNG 图像帧进行操作。
# Use some default options.
ffmpeg="ffmpeg -nostdin -hide_banner -v error"
# Obtain a source image.
wget -nv -O original.png https://i.stack.imgur.com/8J1qY.png
size="256x256"
# Compare it with itself to verify that we get an infinite average PSNR.
$ffmpeg -v info -i original.png -i original.png -lavfi psnr -f null - |& grep PSNR
# average:inf
# Convert the image to YUV420, and convert back to RGB.
$ffmpeg -i original.png -pix_fmt yuv420p -f rawvideo -y temp1.yuv420
$ffmpeg -f rawvideo -s $size -pix_fmt yuv420p -i temp1.yuv420 -y result1.png
# Compare it with the original image to measure the PSNR (in dB).
$ffmpeg -v info -i result1.png -i original.png -lavfi psnr -f null - |& grep PSNR
# average:36.894551
现在,作为替代方案,我们手动执行 RGB YUV420 色度重采样:
yuv444_to_yuv420="extractplanes=y+u+v[y][u][v];\
[u]scale=w=iw/2:h=ih/2:flags=area[u];\
[v]scale=w=iw/2:h=ih/2:flags=area[v];\
[y][u][v]mergeplanes=0x001020:yuv420p"
yuv420_to_rgb="extractplanes=y+u+v[y][u][v];\
[u]scale=w=iw*2:h=ih*2:flags=neighbor[u];\
[v]scale=w=iw*2:h=ih*2:flags=neighbor[v];\
[y][u][v]mergeplanes=0x001020:yuv444p,format=rgb24"
$ffmpeg -i original.png -pix_fmt yuv444p -f rawvideo - | \
$ffmpeg -f rawvideo -pix_fmt yuv444p -s $size -i - \
-lavfi "$yuv444_to_yuv420" -f rawvideo -y temp2.yuv420
$ffmpeg -f rawvideo -pix_fmt yuv420p -s $size -i temp2.yuv420 \
-lavfi "$yuv420_to_rgb" -y result2.png
# Measure PSNR by comparing with the original image.
$ffmpeg -v info -i result2.png -i original.png -lavfi psnr -f null - |& grep PSNR
# average:37.536444
# This is an improvement of 0.64 dB!
这带来了两个问题:
- 为什么
ffmpeg默认不实现与yuv420p的更好转换? - 有没有更简单的方法来获得或表达这种改进的转换?
【问题讨论】:
-
RGB 8 位 -> YUV420 -> RGB 8 位根本不无损,RGB 8 位 -> YUV420 10 位 -> RGB 8 位。
标签: ffmpeg