《FFmpeg从入门到精通》读书笔记(三)

2022-09-13 10:48:40 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

写在前面

2019.06.20

第四章 FFmpeg转码


FFmpeg转码

FFmpeg软编码H.264与H.265

FFmpeg本身不支持H.264的编码器,是由FFmpeg的第三方模块对其进行支持,当前常用的编码器为x264,所支持的像素格式主要包括以下几种(使用ffmpeg -h encoder=libx264进行查询)

Encoder libx264 [libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10]:     Threading capabilities: no     Supported pixel formats: yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p nv12 nv16 nv21

x264的编码参数 (表格在书 P117)
1.preset String 编码器预设参数
代码语言:javascript复制
ffmpeg -i input.mp4 -vcodec libx264 -preset medium -b:v 2000k output1.mp4

preset是x264中最重要的选项,它影响编码性能和编码速度,它由不是一个单一的参数,而是由一组参数构成。preset分为下面几种类型:

代码语言:javascript复制
static const char * const x264_preset_names[] = { 
"ultrafast", "superfast", "veryfast", 
"faster", "fast", "medium", "slow", 
"slower", "veryslow", "placebo", 0 
};

从左到右,编码速度越来越慢,编码质量越来越好,其中placebo不建议使用,没有太大意义,对视频的质量要求很严格时才使用veryslow,ultrafast产生的视频可能会非常大,使用前也需要仔细思考。不同preset对应设置的值请参考 x264的preset和tune

2.tune String 调优编码参数

tune是x264中重要性仅次于preset的选项,它是视觉优化的参数,tune可以理解为视频偏好(或者视频类型),tune不是一个单一的参数,而是由一组参数构成。tune分为下面几种类型:

代码语言:javascript复制
static const char * const x264_tune_names[] = { 
"film", "animation", "grain", 
"stillimage", "psnr", "ssim", 
"fastdecode", "zerolatency", 0 };

film:电影类型,对视频的质量非常严格时使用该选项 animation:动画片,压缩的视频是动画片时使用该选项 grain:颗粒物很重,该选项适用于颗粒感很重的视频 stillimage:静态图像,该选项主要用于静止画面比较多的视频 psnr:提高psnr,该选项编码出来的视频psnr比较高 ssim:提高ssim,该选项编码出来的视频ssim比较高 fastdecode:快速解码,该选项有利于快速解码 zerolatency:零延迟,该选项主要用于视频直播

不同tune对应设置的值请参考 x264的preset和tune

3.profile与level String 编码profile档级设置、编码level层级设置

H.264有四种画质级别,分别是baseline, extended, main, high:   1、Baseline Profile:基本画质。支持I/P 帧,只支持无交错(Progressive)和CAVLC;   2、Extended profile:进阶画质。支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC;(用的少)   3、Main profile:主流画质。提供I/P/B 帧,支持无交错(Progressive)和交错(Interlaced),     也支持CAVLC 和CABAC 的支持;   4、High profile:高级画质。在main Profile 的基础上增加了8×8内部预测、自定义量化、 无损视频编码和更多的YUV 格式; H.264 Baseline profile、Extended profile和Main profile都是针对8位样本数据、4:2:0格式(YUV)的视频序列。在相同配置情况下,High profile(HP)可以比Main profile(MP)降低10%的码率。 根据应用领域的不同,Baseline profile多应用于实时通信领域,Main profile多应用于流媒体领域,High profile则多应用于广电和存储领域。

每个level都规定了一组对标准中语法成员(syntax element)所采用的各种参数值的限制。 在给定的profile下,level通常与解码器的处理能力和内存容量相对应。每一个档次设置不同的参数(如取样速率、图像尺寸、编码比特率等),得到对应的编解码器性能的不同level。

4.sc_threshold int 场景切换阙值参数(控制场景切换关键帧插入参数)
代码语言:javascript复制
知识点1:GOP
在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离。一个I帧所占用的字节数大于一个P帧,一个P帧所占用的字节数大于一个B帧。

>在视频编码序列中,主要有三种编码帧:I帧、P帧、B帧
● I帧即Intra-coded picture(帧内编码图像帧),不参考其他图像帧,只利用本帧的信息进行编码
● P帧即Predictive-codedPicture(预测编码图像帧),利用之前的I帧或P帧,采用运动预测的方式进行帧间预测编码
● B帧即Bidirectionallypredicted picture(双向预测编码图像帧),提供最高的压缩比,它既需要之前的图
像帧(I帧或P帧),也需要后来的图像帧(P帧),采用运动预测的方式进行帧间双向预测编码

所以在码率不变的前提下,GOP值越大,P、B帧的数量会越多,平均每个I、P、B帧所占用的字节数就越多,也就更容易获取较好的图像质量;Reference越大,B帧的数量越多,同理也更容易获得较好的图像质量。

需要说明的是,通过提高GOP值来提高图像质量是有限度的,在遇到场景切换的情况时,H.264编码器会自动强制插入一个I帧,此时实际的GOP值被缩短了。另一方面,在一个GOP中,P、B帧是由I帧预测得到的,当I帧的图像质量比较差时,会影响到一个GOP中后续P、B帧的图像质量,直到下一个GOP开始才有可能得以恢复,所以GOP值也不宜设置过大。

同时,由于P、B帧的复杂度大于I帧,所以过多的P、B帧会影响编码效率,使编码效率降低。另外,过长的GOP还会影响Seek操作的响应速度,由于P、B帧是由前面的I或P帧预测得到的,所以Seek操作需要直接定位,解码某一个P或B帧时,需要先解码得到本GOP内的I帧及之前的N个预测帧才可以,GOP值越长,需要解码的预测帧就越多,seek响应的时间也越长。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190620234120890.png)
代码语言:javascript复制
知识点2:IDR帧
IDR(Instantaneous Decoding Refresh)--即时解码刷新。

I和IDR帧都是使用帧内预测的。它们都是同一个东西而已,在编码和解码中为了方便,要首个I帧和其他I帧区别开,所以才把第一个首个I帧叫IDR,这样就方便控制编码和解码流程。IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始,重新算一个新的序列开始编码。而I帧不具有随机访问的能力,这个功能是由IDR承担。IDR会导致DPB(DecodedPictureBuffer 参考帧列表——这是关键所在)清空,而I不会。IDR图像一定是I图像,但I图像不一定是IDR图像。一个序列中可以有很多的I图像,I图像之后的图像可以引用I图像之间的图像做运动参考。一个序列中可以有很多的I图像,I图像之后的图象可以引用I图像之间的图像做运动参考。 

对于IDR帧来说,在IDR帧之后的所有帧都不能引用任何IDR帧之前的帧的内容,与此相反,对于普通的I-帧来说,位于其之后的B-和P-帧可以引用位于普通I-帧之前的I-帧。从随机存取的视频流中,播放器永远可以从一个IDR帧播放,因为在它之后没有任何帧引用之前的帧。但是,不能在一个没有IDR帧的视频中从任意点开始播放,因为后面的帧总是会引用前面的帧。

x264有一指标,用于衡量每一帧与前一帧的差异程度。若该值小于scenecut,则检测到’场景切换’(‘scenecut’)条件,并放置一个I帧 (前提:该帧与上一个IDR帧的间隔小于min-keyint,否则就放置一个IDR帧)。提高scenecut值将增加检测到的’场景切换’数量。

ffmpeg中使用-sc_threshold设置此项。将scenecut设为0,相当于设定 no-scenecut

在FFmpeg中,通过命令行的-g参数设置以帧数间隔为GOP的长度,但是当遇到场景切换时,例如从一个画面跳到另一个画面,会强行插入一个关键帧,这时GOP的间隔将会重新开始,这样的场景在点播视频文件中会频频遇到,如果将点播文件进行M3U8切片,或者将点播文件进行串流虚拟直播时,GOP的间隔也会出现相同的情况,为了避免这种情况的产生,可以通过使用sc_threshold参数进行设定以决定是否在场景切换时插入关键帧

代码语言:javascript复制
ffmpeg -i input.mp4 -c:v libx264 -g 50 -sc_threshold 0 -t 60 output.mp4

这样可以控制关键帧,进行视频切片时会更加方便

5.x264opts String 设置x264专有参数

可以通过该参数设置x264的内部私有参数,如设置I帧、P帧、B帧的顺序及规律等

例如:设置视频无B帧

代码语言:javascript复制
ffmpeg -i input.mp4 -c:v libx264 -x264opts "bframes=0" -g 50 -sc_threshold 0 output.mp4

例如:设置每2个P帧之间存放3个B帧

代码语言:javascript复制
ffmpeg -i input.mp4 -c:v libx264 -x264opts "bframes=3:b-adapt=0" -g 50 -sc_threshold 0 output.mp4

B帧越多,同等码率时的清晰度越高,但编解码的复杂度也越高

6.nal-hrd int HRD信号信息设置:None、VBR、CBR设置

CBR恒定码率设置参数

代码语言:javascript复制
ffmpeg -i input.mp4 -c:v libx264 -x264opts "bframes=10:b-adapt=0" -b:v 1000k -maxrate 1000k -minrate 1000k -bufsize 50k -nal-hrd cbr -g 50 -sr_threshold 0 output.ts

分析上面的命令:

1 设置B帧个数,每2个P帧包含10个B帧 2 设置视频码率为1000kbit/s 3 设置最大码率为1000kbit/s 4 设置最小码率为1000kbit/s 5 设置编码的buffer为50KB 6 设置H.264的编码HRD信号形式为CBR 7 设置每50帧一个GOP 8 设置场景切换不强行插入关键帧

7.crf 用于控制视频画质,取值为[0-51],数值越低画质越好

0:无损 51:最次 默认值23, 通常取值范围:[18-28] crf每 6,比特率减半 ,crf每-6,比特率翻倍


FFmpeg硬编解码

FFmpeg硬编解码(对应书 P130-P141)

书上讲解了FFmpeg中使用不同硬件设备时硬编解码的用法、不同参数以及举例说明,这里不赘述了,感兴趣的同学可以去看一看书上对应的章节。这里需要提一点,就是FFmpeg是如何使用硬件编解码的。

基于FFmpeg的H.264视频硬件编解码在S3C6410处理器上的实现这篇文章里有详细的描述,并使用三星举例说明。FFmpeg编解码时的输入输出都是以帧为单位,将该环节的处理设备替换为具有多媒体硬件加速功能的硬件设备。虽然FFmpeg提供了简单的应用程序编程接口(API),可以很方便地实现多种格式的视频软件编解码,但是软件编解码在处理复杂视频编解码(如H.264)时无法运用到处理速度不快、内存空间不多的嵌入式环境中、,即在资源有限的嵌入式环境下使用FFmpeg实现复杂视频编解码。


FFmpeg输出MP3

FFmpeg使用第三方库libmp3lame即可编码MP3格式

代码语言:javascript复制
ffmpeg -i INPUT -acodec libmp3lame OUTPUT.mp3

控制质量需要通过-qscale:a,也可以使用q参数,质量不同码率也不同,如下表:

如果遇到将低码率转换为高码率的情况,不一定会符合上述参数

平均码率编码参数 abr

ABR是VBR与CBR的混合产物,表示平均码率编码,使用ABR参数之后,编码速度将会比VBR高,但是质量会比VBR的编码差; 比CBR编码好一些。

对于普通用户通常有两种码率控制模式:crf(Constant Rate Factor)和Two pass ABR。码率控制是一种决定为每一个视频帧分配多少比特数的方法,它将决定文件的大小和质量的分配。ffmpeg与x264编码指南 这篇文章详细的讲解两者的特性和使用方法。

FFmpeg输出AAC

与MP3相比,AAC编码效率更高、编码音质更好,使用AAC编码后的文件存储格式为m4a FFmpeg支持AAC的三种编码器:aac、libfaac、libfdk_aac

代码语言:javascript复制
ffmpeg -i input.mp4 -c:a aac -b:a 160k output.m4a
高质量AAC设置

AAC音频分为三种:LC、HE-AAC、HEv2-AAC

代码语言:javascript复制
知识点:HE是什么?
HE意思是 "high efficiency"(高效性)。HE-AAC混合了AAC与SBR技术。SBR代表的是Spectral Band Replication(频段复制)。SBR的关键是在低码流下提供全带宽的编码而不会产生产生多余的信号。传统认为音频编码在低码流下意味着减少带宽和降低采样率(见MP3 FAQ #7)或产生令人不快的噪音信号。SBR解决问题的方法是让核心编码去编码低频信号,而SBR解码器通过分析低频信号产生高频信号和一些保留在比特流中的指导信号(通常码流极低,~2 kbps)。 这就是采用无SBR解码器的原因,这样你的带宽(frequency response)(频率响应)会被严重浪费。这也是为什么被叫做Spectral Band Replication的原因,它只是增加音频的带宽,而非重建。
代码语言:javascript复制
知识点:AAC与MP3相比
将一个无损的因为文件(.ape)转为AAC和MP3,AAC文件与APE文件的频谱非常接近,在高频20K没有丢失,而MP3的在高频端上就严重丢失。比较了一下体积,AAC文件甚至还小些。
HE-AAC音频编码设置

ffmpeg -i input.wav -c:a libfdk_aac -profile:a aac_he -b:a 64k output.m4a

HEv2-AAC音频编码设置

ffmpeg -i input.wav -c:a libfdk_aac -profile:a aac_he_v2 -b:a 64k output.m4a


转码与转封装

音视频转码会占用大量的计算资源,主要占用CPU资源;音视频转封装主要是将音频或视频数据取出,然后转而封装成另一种格式,主要占用IO资源;相比较,转码也会占用更多的内存资源。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153360.html原文链接:https://javaforall.cn

0 人点赞