ffmpeg 转码心得
格式 / 编码 / 码率 / 硬解 / 分布式
阅读时间 2 分钟
前言
请注意,本文创建于 2019 年,其中涉及的 h264 和 h265 的兼容性的问题可能已经不再符合如今的实际情况。
本菜鸡用 ffmpeg 也有一段时间了,平时都是用来压制冻鳗、演唱会或者视频录像,试来试去也踩了不少坑…于是决定水一篇
这篇文章的目的,是想介绍一些常用、好用、能背下来的参数,以及一些基本的编码知识。
常用选项
-c:a copy
这是我常用参数之一,-c:a copy
表示不会对音频进行重新编码
为啥?
首先音频轨道的体积相对于整个文件来说是比较小的,一般来说,对音频重新压缩体积小不了多少,但是音质会有明显的降低,是得不偿失的
其次,就算音频轨道是 FLAC 96000kHz 24bit,也不会占用过多空间。并且本人认为无损音频是珍贵值得保留的。
-c:a aac -ab 64k -ac 1
使用 aac 编码器(mp4 格式最常见的编码器)。音频码率限制在 32k。音频通道数量为 1(也就是所谓的单声道)
与影视作品不同,一般的录音录像更有可能是电话级别的音质。主要内容是人声,并且带有严重失真和底噪。这种音频多给 1kb 都是浪费。
如果你确定录音设备是不是单声道,那么可以忽略 -ac 1 参数。但 64k 的码率对于人声来说仍然是足够的。
码率不是按声道平均分配。64k 双声道不代表每个声道只有 32k 的码率。编码器的算法可能会提取双声道中相同的部分(中置声道)并将调整码率分配的方式。
-c:v h264
H264 大概是我最常用的视频编码方式了
平常所说的 .avi .mp4 .mkv 都是视频格式,是一种容器,容器里包含了一个或多个视频/音频轨道,每一个视频轨道的编码方式称之为视频编码,常见的视频编码格式有 h264 h265 vp9 mpeg4 等等…
为什么用 h264?
就目前情况来看,h264 是压缩率比较高,支持设备比较多的一种格式
支持设备多意味着能够被硬解码,硬解意味着能够调用 GPU 而不是 CPU 更加流畅、省电地播放视频
h265 可以说是 h264 的进化版本,相同视频质量下,体积可以减少 40%左右,一般用于高清视频的压制
市面上大多数新出的设备都能硬解 h265,但还有更多的老设备在播放 h265 仍然只能软解,cpu 占用 100%,风扇呼呼响,却只能看个 ppt
ffmpeg 的 h264 编码默认采用 vbr 码率控制方式,VBR 会根据视频内容动态调整码率,视频变化多的时候分配高码率,视频画面静止的时候分配低码率,优点是能保证视频质量,缺点是无法预测视频大小,如果用于直播,可能会出现卡顿。
除此之外,还可以用 crf 值来指定 VBR 的码率,crf 的取值范围介于 0-51,一般来说,18-28 是一个合理的范围,默认值为 23,18 被认为是视觉无损,因此如果觉得 vbr 码率偏高或偏低,可以适当调整 crf。
若 Crf 值加 6,输出码率大概减少一半;若 Crf 值减 6,输出码率翻倍(在 8bit 的前提下)。
-preset medium
使用预设,预设是一系列参数的集合,不同的预设对应不同的编码速度和压缩率,编码速度越慢,压缩率越高。
假如你很有耐心,通常的建议是使用较慢的预设,目前所有的预设按照编码速度降序排列
- ultrafast
- superfast
- veryfast
- faster
- fast
- medium
- slow
- slower
- veryslow
- placebo
默认值是 medium,请不要使用 placebo,因为它以极高的编码时间为代价,仅仅提升了 1% 左右的压缩率,这是一种收益递减准则,veryslow 与 slower 相比提升了 3%;slower 与 slow 相比提升了 5%;slow 与 medium 相比提升了 5%~10%。你可以使用 --preset
来查看预设列表,也可以通过 x264 --fullhelp
来查看预设所采用的参数配置
在测试中,用不同的预设重现编码动画测试片段
ffmpeg -i test.mp4 -c:a copy -c:v libx264 -preset [preset] test_[preset].mp4
文件大小结果如下(test.mp4 是源文件)
如果说 medium 的编码速度为 4x,大致来说每个等级之间相差 1x,到 veryslow 时甚至慢到 0.5x
而 superfast 速度飙到 15x,utralfast 更是快到了 20x
-tune animation
-tune
的参数主要配合视频类型和视觉优化的参数,或特别的情况。如果视频的内容符合其中一个可用的调整值又或者有其中需要,则可以使用此选项,否则建议不使用(如 tune grain 是为高比特率的编码而设计的)。
tune 的值有:
- film 电影、真人类型
- animation 动画
- grain 需要保留大量的纹理时用
- stillimage 静态图像编码时使用
- psnr 为提高 psnr(峰值信噪比)做了优化的参数
- ssim 为提高 ssim 做了优化的参数
- fastdecode 可以快速解码的参数
- zerolatency 零延迟,用在需要非常低的延迟的情况下,比如电视电话会议的编码
再来测一波-tune(test.mp4 是源文件,normal 是不加 -tune
参数的结果)(再说一遍,用的测试文件动画片段)
ffmpeg -i test.mp4 -c:a copy -c:v libx264 -tune [tune] test_[tune].mp4
不出所料,animation 对动画的编码效果是最好的
关于显卡加速
压制发布视频一般不推荐使用,几乎所有情况下显卡编码质量都没有 CPU 编码好。编码质量是指在相同码率的情况下的视频质量。这是因为硬件编码芯片将算法写成电路并行运算加速,而 CPU 能使用最新的算法进行更复杂的编码。
但是,它快啊,快到离谱
市面上大部分新的 intel CPU 都有 QSV 芯片模块,用于加速视频的编码解码
查看 ffmpeg 支持的 qsv 编码器,在 windows 下是 findstr,在 linux 下是 grep
ffmpeg -decoders | findstr qsv
然后瞎用就是了
ffmpeg -i test.mp4 -c:v h264_qsv -c:a copy output.mp4
详情参考 ffmpeg 使用 QSV 硬件加速视频转码 或自行问 Google
又快又好 - 分布式转码
原理很简单,主机用 ffmpeg 将原视频无损切片(切片速度很快,跟复制差不多),将切好的视频片段分发到多个 Worker 中,多个 Worker 同时开始转码视频片段,转码完成后发送回主机,主机再将所有视频片段拼接
有人用 hadoop 实现了,我觉着就是切香蕉用杀猪刀了
python 写百来行我觉着就够用(不考虑 Worker 宕机,假设网络稳定)(挖坑预定)
切片
ffmpeg -i input.mp4 -acodec copy -vcodec copy \
-f segment -segment_time 20 -reset_timestamps 1 -map 0:0 -map 0:1 %d.mp4
转码
ffmpeg -i input.mp4 -vcodec libx264 -s 1280x720 output.mp4
合并
ffmpeg -f concat -i filelist.txt -c copy output.mp4
参考 分布式转码(三)实现