手机相册里拍摄的视频越来越多,占用了大量储存空间。为了释放空间,我将拍摄的所有视频压缩为AV1编码,同时尽可能避免视频中的信息损失。在此简要记录过程。
我选择使用libsvtav1
软件编码器进行AV1编码,因为:
libaom
和librav1e
AV1编码器速度太慢;libsvtav1
软件编码器的速度已经可以接受:在我的笔记本(CPU:AMD R7 6800H)上,使用中等预设编码1080P视频,平均速度可达18.7fps;libsvtav1
的码率明显小于libx264
和libx265
。音频使用libopus
编码器,这是普遍认为音质最佳的有损编码器,并且受大部分设备和软件支持。
我没有启用硬件加速编解码,因为我感觉AMD的集显很不可靠(在我的电脑上,有时硬解播放2K H.264的视频,画面都可能出现马赛克/花屏;软解正常)。
我使用的转码脚本(Windows 命令提示符):
for %%i in (*.mp4) do ffmpeg -hide_banner -benchmark -i "%%i" -c:v libsvtav1 -crf 31 -preset 4 -pix_fmt yuv420p10le -svtav1-params tune=0:keyint=10s:film-grain=8 -c:a libopus -b:a 128k -movflags use_metadata_tags+faststart -map_metadata 0 "%%~ni.mkv"
使用方法:在配置好FFmpeg
环境变量的情况下,将上方的代码保存为cmd格式,放入所有视频文件所在的文件夹并执行。
使用此脚本压缩我拍摄的所有视频,最后统计得出:文件体积累计减小了63.5%。
下面是参数的详细解析:
遍历当前文件夹内的所有mp4格式视频。
默认值:35;取值区间:[1, 63];值越大,码率越低。
为了减少压缩带来的信息损失,我选择的值是31。
默认值:10;取值区间:[-1, 13];值越大,编码速度越快,但画质越低,码率越高。
对于视频压缩,可取的值是4和6。低于4的值太慢,高于6的值损失较大。为了更好的画质和更小的体积,我选择的是4。
6相比4禁用了这五个特性:Filter intra
、Global motion compensation
、Wedge prediction
、Difference-weighted prediction
和Distance-weighted prediction
;但收益是:6的编码速度大约是4的2.5倍。
如果不填此项,则像素格式会尽可能保持与原视频一致。yuv420p10le
意味着强制将输出视频的像素格式设为10bit的yuv420p,这样做是因为根据文档和实测,即使原视频像素格式是8bit,输出为10bit相比输出为8bit能得到更好的色彩品质和更高的VMAF指标,同时文件体积只会增大约5%。
可选择的值有:[0 = 优化视觉质量, 1 = 优化PSNR指标, 2 = 优化SSIM指标],默认值为1。我选择的值是0。
指定关键帧距离。如果不填,默认值为“大约5秒”。更长的关键帧距离可以提高压缩率,所以我选择10秒。
根据文档:
众所周知,与胶片颗粒(或 CCD 噪声)相关的随机图案很难压缩。当原始源中存在颗粒时,通过删除胶片颗粒并将其替换为不占用文件中大量空间的合成颗粒,可以显着提高效率。启用
film-grain
后,SVT-AV1 对图像进行降噪,将生成的图像与原始图像进行比较,并分析颗粒的性质。然后它会插入具有类似特性的合成颗粒。这可以极大地提高效率,同时保留视觉质量和特征。去除颗粒的过程有时会删除原始图像中非常精细的细节,因此不应过度使用。传递给
film-grain
参数的级别控制该过程的使用程度。一般来说,film-grain
对于具有正常颗粒量的实景视频来说,8 左右的级别就足够了。噪声较大的视频受益于 10-15 范围内的较高级别。 2-D 动画通常具有较少的颗粒,因此 4 左右的级别适用于标准(手绘)动画。颗粒动画可以受益于高达 10 左右的更高级别。
由于我压缩的视频都是通过手机拍摄的,通常存在噪点,所以启用此功能。实测此功能能明显降低码率,同时保持良好的画质,但会减慢编码速度。
对于立体声音频,编码为opus格式、码率128kbps足以达到感知上无损。
保留原视频中的元数据(比如拍摄时间、机型、地理位置);以及优化视频文件,使视频可以被快速加载。
参考资料:
https://gitlab.com/AOMediaCodec/SVT-AV1
https://trac.ffmpeg.org/wiki/Encode/AV1
https://ottverse.com/analysis-of-svt-av1-presets-and-crf-values/
https://gist.github.com/mrintrepide/b3009f5d0f08d437ebbb4c17cbf36e18
@tasy5kg,看了看文档,libsvtav1 确实只支持 8/10 bit。。
但 avifenc 支持 12 bit。我搜索论坛里的 mp4 文件,选了其中三个,试了试转成动图,确实 12 bit 能比 8 bit 再小 20% 左右。
转码脚本(Windows 下可用 600KB 的 busybox-w32 来运行,要求 PATH
处能找到 ffmpeg
、avifenc
):
speed=5
quality=50
for file in *.mp4; do
for depth in 8 10 12; do
ffmpeg -v quiet -i "$file" -strict -1 -pix_fmt "yuv420p$( [[ $depth == 8 ]] && echo '' || echo "${depth}le" )" -f yuv4mpegpipe - |
avifenc -q "$quality" -s "$speed" --min 0 --max 63 --stdin "${depth}bit_${speed}s_${quality}q_${file%.*}.avif"
done
done
文件所在帖子:
在我的电脑上,有时硬解播放2K H.264的视频,画面都可能出现马赛克/花屏
如果是播放网络视频出现这问题,是Chrome和EDGE的Bug,用英伟达显卡有时也会这样。
可能和微软正在修改的MediaFoundation功能有关。
使用 -c:v copy 时,无法精确地控制剪辑时间点
在不重编码的情况下,只能在关键帧(I帧)处进行切分。非关键帧(P帧、B帧)需要使用帧间预测,需要I帧的存在才能解码,所以无法在这些帧上切分。
@tasy5kg,以前我转 AVIF 照片时,意外发现,像素格式是 12bit 的话,体积会比 8bit、10bit 下降很多。。
但是 Windows 只支持 8bit 的。。