一、FFmpeg软编码H.264和H.265
H.264编码简介
当前网络中常见的视频编码格式要数H.264最为火热,支持H.264的封装格式有很多,如FLV、MP4、HLS(M3U8)、MKV、TS等格式;FFmpeg本身并不支持H.264的编码器,而是由FFmpeg的第三方模块对其进行支持,例如x264和OpenH264。
在FFmpeg中进行H.265编码时,可以采用x265进行编码,H.265编码参数与x264的编码参数相差不多,基本可以通用。
H.264分析两大利器:264VISA和Elecard StreamEye。
1 | $ ffmpeg -h encoder=libx264 |
参数如下:
编码器预设参数设置preset
有几种预设模板,转码速度从快到慢,画质响应也会提升(慢工出细活),分别是:
- ultrafast
- superfast
- veryfast
- faster
- fast
- medium(基准,默认参数)
- slow
- slower
- veryslow
- placebo
1 | $ ffmpeg -i input.mp4 -vcodec libx264 -b:v 2000k -preset ultrafast output.mp4 |
H.264编码优化参数tune
可以包含如下几个场景:
- film
- animation
- grain
- stillimage
- psnr
- ssim
- fastdecode
- zerolatency(用于直播,提升效率,降低因编码导致的延迟)
H.264的profile与level设置
这里的profile(档次)与level(等级)的设置与H.264标准文档ISO-14496-Part10中描述的profile、level的信息基本相同,x264编码器支持7种profile参数设置,根据profile的不同,编码出来的视频的很多参数也有所不同。
level 参数如下:
1 | # Baseline,不支持B帧分片 |
控制场景切换关键帧插入参数sc_threshold
在FFmpeg中,通过命令行的-g参数设置以帧数间隔为GOP的长度。
1 | $ ffmpeg -i input.mp4 -c:v libx264 -g 50 -t 60 output_g50.mp4 |
使用StreamEye打开可看到,60s的视频,fps为25,一共1500帧中,有85帧I帧,超过了GOP为50应有的30帧。
但是当遇到场景切换时,会强行插入一个关键帧,这时GOP的间隔将会重新开始,可以通过使用sc_threshold参数进行设定以决定是否在场景切换时插入关键帧。
1 | $ ffmpeg -i input.mp4 -c:v libx264 -g 50 -t 60 -sc_threshold 0 output_g50_threshold.mp4 |
再使用StreamEye打开可以看到I帧有30帧,可见场景转换时没有插入额外的I帧。
设置x264内部参数x264opts
由于FFmpeg设置x264参数时增加的参数比较多,可以通过x264opts这个参数设置x264内部私有参数,如设置I帧、P帧、B帧的顺序及规律等。
1 | # 设置的GOP参数,如果视频GOP设置为50帧,那么如果在这50帧中没有B帧 |
CBR恒定码率设置参数nal-hrd
编码能够设置VBR、CBR的编码模式,VBR为可变码率,CBR为恒定码率。FFmpeg是通过参数-b:v来指定视频的编码码率的,但是设定的码率是平均码率,并不能够很好地控制最大码率及最小码率的波动,如果需要控制最大码率和最小码率以控制码率的波动,则需要使用FFmpeg的三个参数-b:v、maxrate、minrate。同时为了更好地控制编码时的波动,还可以设置编码时buffer的大小,buffer的大小使用参数-bufsize设置即可,buffer的设置不是越小越好,而是要设置得恰到好处。
1 | # 设置B帧的个数,并且是每两个P帧之间包含10个B帧 |
二、FFmpeg硬编解码
使用软编解码,CPU的消耗过大,编码效率较低,成本相对较高。
考虑到效率和成本原因,可以使用基于GPU的硬编解码。常见的硬编码包含NVIDIA GPU与Intel QSV两种。此外还有树莓派
NVIDIA GPU硬编码
1 | # 查看对于NVIDIA的GPU“编码”参数支持 |
编码的参数与开源的x264有些类似,例如preset参数、profile参数、level参数、场景切换参数等。
1 | # 使用cuvid硬解码与nvenc硬编码 |
Intel QSV硬编码
1 | # 查看FFmpeg是否编译开启QSV,grep为linux命令 |
h264_qsv只支持nv12与qsv的像素格式,所以在使用yuv420p时需要将其转换成nv12才可以。
1 | # 软编码,不使用qsv,2.5倍速,且cpu一直打满 |
QSV同样支持H.265编码,load_plugin参数包括hevc_hw的265硬编码和hevc_sw的265软编。
1 | # 针对高清编码,使用AVC(H.264)编码后码率较高。同样清晰度下,使用HEVC(H.265)能更好的降低码率。 |
OS X硬编解码
苹果电脑的OS X系统下,通常硬编码采用h264_videotoolbox、硬解码采用h264_vda为最快捷、最节省CPU资源的方式,但是h264_videotoolbox的码率控制情况并不完美,因为h264_videotoolbox做硬编码时目前仅支持VBR(Variable Bitrate)/ABR(Average Bitrate)模式,而不支持CBR(Constant Bitrate)模式。
1 | #查看h264_videotoolbox编码支持的参数和像素的色彩格式 |
videotoolbox编码参数如下:
1 | # 使用h264_vda进行视频硬解码,使用h264_videotoolbox进行硬编码,码率为2M |
三、FFmpeg输出MP3
FFmpeg使用第三方库libmp3lame即可编码MP3格式。MP3编码还是低延迟的编码,可以支持的采样率比较多,包含44100、48000、32000、22050、24000、16000、11025、12000、8000多种采样率,采样格式包含s32p(signed 32 bits,planar)、fltp(float, planar)、s16p(signed 16 bits, planar)多种格式,声道布局方式支持包含mono(单声道模式)、stereo(环绕立体声模式)。
转码参数如下:
q参数来控制不同质量和不同码率,如下:
1 | # 编码时需要设置编码器libmp3lame |
以上码率设置方式为VBR码率,常见的MP3编码设置为CBR,通过FFmpeg参数-b即可设置。
1 | # 设置音频码率为64k的CBR |
ABR是VBR与CBR的混合产物,表示平均码率编码,使用ABR参数之后,编码速度将会比VBR高,但是质量会比VBR的编码稍逊一些,比CBR编码好一些,在FFmpeg中可使用参数-abr来控制MP3编码为ABR编码方式。
1 | # 设置音频码率为64k的ABR |
四、FFmpeg输出AAC
在音视频流中,无论直播与点播,AAC都是目前最常用的一种音频编码格式,例如RTMP直播、HLS直播、RTSP直播、FLV直播、FLV点播、MP4点播等文件中都是常见的AAC音视频。
与MP3相比,AAC是一种编码效率更高、编码音质更好的音频编码格式,常见的使用AAC编码后的文件存储格式为m4a,如在iPhone或者iPad中即为m4a。
FFmpeg可以支持AAC(AAC-LC)的三种编码器:
- aac:FFmpeg本身的AAC编码实现(GPL协议),质量次于libfdk_aac
- libfdk_aac:第三方的AAC编码器(非GPL协议),质量最优
- libfaac:第三方的AAC编码器(非GPL协议),质量最差,新版本FFmeg已删除
aac编码器
1 | # 编码为AAC音频,码率为160k |
libfdk_aac编码器
1、恒定码率(CBR)模式
1 | # 使用libfdk_aac转为恒定码率为128k、编码为AAC的,封装为m4a的音频文件 |
2、动态码率(VBR)模式
使用VBR可以有更好的音频质量,使用libfdk_aac进行VBR模式的AAC编码时,可以设置5个级别。如下:
编码信息有3种:
- LC:Low Complexity AAC,体积比较大,质量稍差
- HE(HE-AAC):High-Efficiency AAC,体积稍小,质量较好
- HEv2(HEv2-AAC):High-Efficiency AAC version 2,体积小,质量优
LC、HE、HEv2的推荐参数如下:
1 | # 使用libfdk_aac,选择vbr为3 |
五、系统资源使用情况
音视频转码与音视频转封装的不同之处在于音视频转码会占用大量的计算资源,而转封装则主要是将音频数据或者视频数据取出,然后转而封装(Mux)成另外一种封装格式,转封装主要占用IO资源,而转码主要占用CPU资源,同时转码也会使用更多的内存资源。
如果转码质量要求极高,那么必然需要大量的计算资源,可以考虑采用GPU进行编码,以节省CPU资源来进行其他工作。