以一个分辨率1920×1080,帧率30,RGB888像素24bit的视频为例:
1920×1080=2,073,600(Pixels 像素)
2073600×24=49,766,400 bit
49766400bit = 6220800Byte = 5.93MB
一帧图像5.93MB,30的帧率,一秒的视频就177.9MB,一分钟视频就大约1G,90分钟视频就90G。传输和存储都是问题,所以就需要对视频进行编码。
RGB信号不利于压缩。在YUV这种方式里面,加入了亮度这一概念。人眼对色度的敏感程度要低于对亮度的敏感程度。所以在视频存储中,没有必要存储全部颜色信号。可以把更多带宽留给黑—白信号(被称作“亮度”),将稍少的带宽留给彩色信号(被称作“色度”)。于是,就有了YUV。YUV里面的Y就是亮度(Luma),U和V则是色度(Chroma)。
YUV在模拟分量为YPbPr,在数字分量为YCbCr,编码都是对数字信号编码,下面的说YUV都是YCbCr。
常用的YUV有如下三种格式:
YUV 4:4:4采样,每一个Y对应一组UV分量,一个YUV占8+8+8 = 24bits 3个字节。
YUV 4:2:2采样,每两个Y共用一组UV分量,一个YUV占8+4+4 = 16bits 2个字节。
YUV 4:2:0采样,每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。
我们最常见的YUV420P和YUV420SP都是基于4:2:0采样的,存储格式又分为I420(YU12),YV12,NV12,NV21
YUV420P(YU12和YV12)格式
YUV420P又叫plane平面模式,Y , U , V分别在不同平面,也就是有三个平面,它是YUV标准格式4:2:0,主要分为:YU12和YV12,格式如下:
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
YUV420SP(NV12和NV21格式)
YUV420SP格式的图像阵列,首先是所有Y值,然后是UV或者VU交替存储,NV12和NV21属于YUV420SP格式,UV(CbCr)为交错存储,格式如下:
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP
帧率与画面流畅度成正比:帧率越大,画面越流畅;帧率越小,画面越有跳动感。人眼如果所看画面之帧率高于16的时候,就会认为是连贯的。如果码率为变量,则帧率也会影响体积,帧率越高,每秒钟经过的画面越多,需要的码率也越高,体积也越大。帧率就是在1秒钟时间里传输的图片的帧数。
视频码率就是数据传输时单位时间传送的数据位数,一般我们用的单位是kbps即千位每秒。通俗一点的理解就是取样率,单位时间内取样率越大,精度就越高,处理出来的文件就越接近原始文件。
但是文件体积与取样率是成正比的,所以几乎所有的编码格式重视的都是如何用最低的码率达到最少的失真,围绕这个核心衍生出来的cbr(固定码率)与vbr(可变码率)
CBR固定码率(constant bitrate):
以恒定比特率方式进行编码,有运动发生时,由于码率恒定,只能通过增大QP来减少码字大小,图像质量变差,当场景静止时,图像质量又变好,因此图像质量不稳定。这种算法优先考虑码率(带宽)。适合在流式播放中应用。CBR编码的缺点在于编码内容的质量不稳定
ABR平均码率(average bitrate):
平均比特率,是在CBR和VBR两者之间的一种权衡,即设定一段时间的平均码率,在此时间内,对简单,静态的图像分配低于平均码率的码率,对于复杂的,大量运动的图像分配高于平均码率的码流;适合网络传输;
VBR可变码率(variable bitrate):
以可变的比特方式进行编码,比特分配根据图像内容的复杂度进行。如果图像细节较丰富或者含有大量的运动,则给其分配大一点的码流,若图像比较平坦,就给其分配较少的码流,这样既保证了质量,又兼顾带宽限制。这种算法适合图像内容变化幅度较大的情况适合的应用场景是媒体存储,不适合网络传输;
现有的 码率控制 算法主要是通过调整离散余弦变换的 量化参数 大小输出目标码率。实际上,量化参数( QP )反映了空间细节压缩情况,如 QP 小,大部分的细节都会被保留; QP 增大,一些细节丢失,码率降低,但图像失真加强和质量下降。也就是说, QP 和比特率成反比的关系,而且随着视频源复杂度的提高,这种反比关系会更明显。
好的画质是分辨率、帧率和码率三者之间的平衡
如果一幅图,所有像素都是一个颜色,那么就可以只发一个像素并告诉对方有多大范围这样的像素即可,如果一段视频,有80%图像都是不动的,那么这块存储开销也可以节省下来,这些能节省内容就是视频中的冗余信息。
视频编码就是为了压缩。要实现压缩,就要设计各种算法,将视频数据中的冗余信息去除。
种类 | 内容 | 压缩方法 |
---|---|---|
空间冗余 | 像素间的相关性 | 变换编码,预测编码 |
时间冗余 | 时间方向上的相关性 | 帧间预测,运动补偿 |
图像构造冗余 | 图像本身的构造 | 轮廓编码,区域分割 |
知识冗余 | 收发两端对图像的共有认识 | 基于知识的编码 |
视觉冗余 | 人的视觉特性 | 非线性量化,位分配 |
其他 | 不确定行因素 | … |
视频编码技术优先消除的目标,就是空间冗余和时间冗余。
I帧:I帧采用帧内编码方式,是自带全部信息的独立帧,是最完整的画面(占用的空间最大),无需参考其它图像便可独立进行解码。视频序列中的第一个帧,始终都是I帧。
I帧的特点:
它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
解码时仅用I帧的数据就可重构完整图像;
I帧描述了图像背景和运动主体的详情;
I帧不需要参考其他画面而生成;
I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧;
I帧不需要考虑运动矢量;
I帧所占数据的信息量比较大。
P帧:“帧间预测编码帧”,需要参考前面的I帧和/或P帧的不同部分,才能进行编码。P帧对前面的P和I参考帧有依赖性。但是,P帧压缩率比较高,占用的空间较小。
P帧的特点
P帧是I帧后面相隔1~2帧的编码帧;
P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);
解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧;
P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧;
由于P帧是参考帧,它可能造成解码错误的扩散;
由于是差值传送,P帧的压缩比较高。
B帧:“双向预测编码帧”,以前帧后帧作为参考帧。不仅参考前面,还参考后面的帧,所以,它的压缩率最高。
B帧的特点
B帧是由前面的I或P帧和后面的P帧来进行预测的;
B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
B帧是双向预测编码帧;
B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确;
B帧不是参考帧,不会造成解码错误的扩散。
DTS(解码时间戳),PTS(显示时间戳),为什么要有这两个东西呢?前面说过B帧是双向预测帧,需要依赖前面的I帧或P帧以及后面的P帧才能生成B帧,如果B帧后边还不是P帧怎么办,只能等到后面的P帧生成,举个例子吧,假设视频帧如下:
1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|
I帧 | B帧 | B帧 | P帧 | B帧 | B帧 | P帧 |
B帧只能依靠后边的P帧才能生成,所以编码顺序是如下的:
1 | 4 | 2 | 3 | 7 | 5 | 6 |
---|---|---|---|---|---|---|
I帧 | P帧 | B帧 | B帧 | P帧 | B帧 | B帧 |
传输顺序与解码顺序DTS也相同的
1 | 4 | 2 | 3 | 7 | 5 | 6 |
---|---|---|---|---|---|---|
I帧 | P帧 | B帧 | B帧 | P帧 | B帧 | B帧 |
最后显示顺序一看不对,按PTS调整回来
1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|
I帧 | B帧 | B帧 | P帧 | B帧 | B帧 | P帧 |
这里也只是介绍H.264编码的格式,并没有H.264的原理和算法。
IDR帧:
IDR(Instantaneous Decoding Refresh)–即时解码刷新:
在H.264中引入IDR帧的概念,IDR帧一定是I帧,但I帧不一定是IDR帧。对于IDR帧来说,在IDR帧之后的所有帧都不能引用任何IDR帧之前的帧的内容。
SP帧/SI帧
SP和SI是H264中引入的新技术,主要是为了适应视频流的带宽自适应和抗误码性能的要求,主要应用于流媒体服务。
SP帧就是指能够参考不同的参考帧重构出相同的图像帧。(SP和SI不同在于SI是基于帧内预测,SP是基于帧间预测),在某些场景,SP帧可以替代I帧,主要用于多码流之间的切换、图像和视频的拼接,SP帧效率低于P帧,高于I帧,在复杂的多码流,弱网的情况下,提高了适应能力和抗干扰能力。
流媒体服务自身有一些特征,网络状况是一直变化的,有时候比较繁忙,有时候则比较空闲。针对不同的网络条件,服务器可能提供几种不同质量的数据服务,当网络比较差时,提供比较差但是码率低的服务,当网络好时候,提供比较好码率高的服务。由于视频的编码是参考帧预测的基础上,在不同的条件下切换时很可能会出现丢帧的现象,这种时候SP帧和SI帧就派上用场了。
H.264整体框架
H264可以分为2层:视频编码层『VCL』和网络提取层『NAL』。
VCL(Video Coding Layer)是管理H264视频数据层,VCL主要做了以下事情。
1、压缩:预测(帧内预测和帧间预测)-> DCT变化和量化 -> 比特流编码;
2、切分数据,切片(slice)、宏块(macroblock)都是VCL一层的。
3、包装成NAL。
NAL(Network Abstraction Layer)旨在提供网络友好性,以便为各种系统简单有效地定制VCL的使用。 NAL有助于将VCL数据映射到传输层,例如:RTP 实时传输。 用于广播服务等的MPEG-2系统。
VCL(Video Coding Layer),视频编码层,H264编码/压缩的核心,主要负责将视频数据编码/压缩,再切分。NAL(Network Abstraction Layer),网络抽象层,负责将VCL的数据组织打包。
H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位。如下所示:
NAL将VCL编码处理后的数据,
映射或封装进 NAL 单元(以下简称 NALU,Nal Unit) 中。每个 NALU 包括一个原始字节序列负荷(RBSP, Raw Byte Sequence Payload)、一组对应于视频编码的 NALU 头部信息。H264帧由多个NALU和起始码(start code)组成,格式如下:
NAL头(NAL header)用于标识NAL单元中的RBSP数据类型,|- F -|- NRI -|- Type -|长度一字节,F禁止位在编码中默认值为0出错可设置为1;NRI重要程度;Type类型中,nal_unit_type为1, 2, 3, 4, 5的NAL单元称为VCL的NAL单元,其他类型的NAL单元为非VCL的NAL单元,类型如下:。
A、B和C类数据分割组成Slice的Coded Data被存放在三种数据分割中,A、B和C类数据分割。每种分割包含Coded Slice的一个子集。每种分割被单独的存放在一个NAL单元中,因此可以被单独传输。
A类数据分割:包含Slice的头和每个宏块的头;
B类数据分割:包含Intra和SI Slice宏块的被编码的Residual数据;
C类数据分割:包含P、B和SP Slice宏块的被编码的Residual数据。
如果A类数据分割丢失,很难甚至不可能重构其所在的Slice。三类数据分割在对错误的容忍度方面相比,A最不能容忍错误的出现,而C的容错能力最强。在一个容易出错的环境,提高性能的策略包括:对这三种数据分割应用非均匀错误保护。例如,对A类数据分割使用向前纠错,通过不同的通道传输不同类型的数据分割,或者给A类数据分割选择一个最可靠的通道。
PPS是携带解码参数的NAL Units。发送这些参数采用独立于Coded Slices的方式能够提高效率,因为共用的参数仅仅需要传输一次。Parameter Sets(PPS)对于正确的解码是非常重要的。在一个有损耗的传输场景,在传输过程中比特流或包可能丢失或损坏。在这种网络环境中,Parameter Sets可以通过高质量的服务来发送,比如向前纠错机制或优先级机制。
SEI(Supplemental Enhancement Information),补充增强信息,这部分参数可以作为H.264的比特流数据而被传输,每一个SEI信息被封装成一个NAL单元。SEI对于解码器来说可能是有用的,但是对于基本的解码过程来说,并不是必须的。
SPS(Sequence Parameter Set)包含一些通用的参数,比如Profile和Level,比如视频帧的尺寸,参考帧的最大数量等,这些参数对整个Video Sequence或者Programme都是通用的。PPS(Picture Parameter Set)包含一些通用的参数,比如熵编码类型,有效的参考图像的数目和初始化参数等,这些参数可以应用到一个Video Sequence或者一部分编码帧。
典型的H.264视频序列如下:
RTP实时传输协议(Real-time Transport Protocol)。是IETF提出的一个标准,对应的RFC文档为RFC3550(RFC1889为其过期版本)。RFC3550不仅定义了RTP,而且定义了配套的相关协议RTCP(Real-time Transport Control Protocol,即实时传输控制协议)。RTP用来为IP网上的语音、图像、传真等多种需要实时传输的多媒体数据提供端到端的实时传输服务。RTP为Internet上端到端的实时传输提供时间信息和流同步,但并不保证服务质量,服务质量由RTCP来提供。
RTP载荷第一个字节格式跟NALU头一样:
|- F -|- NRI -|- Type -|
F和NRI也跟NALU头一样,只有Type有些不一样:
Type | 定义 | 描述 |
---|---|---|
1-23 | NAL单元 | 单个 NAL 单元包 |
24 | STAP-A | 单一时间的组合包 |
25 | STAP-B | 单一时间的组合包 |
26 | MTAP16 | 多个时间的组合包 |
27 | MTAP24 | 多个时间的组合包 |
28 | FU-A | 分片的单元 |
29 | FU-B | 分片的单元 |
30-31 | 没有定义 |
可以看到NALU类型23往后未定义的部分就留给了RTP额外的类型,载荷格式定义三个不同的基本荷载结构,接收者可以通过RTP荷载的第一个字节后5位(Type)识别荷载结构:
单一NALU载荷如下:
NAL单元的第一字节和RTP荷载头第一个字节重合。RTP打包时去除起始码 “00 00 01” 或 “00 00 00 01” , 把其他数据封装成 RTP 包即可。
分块结构和组合结构就不详细介绍了,感兴趣看看下面两篇博客https://blog.csdn.net/bytxl/article/details/50395427和https://blog.csdn.net/chen495810242/article/details/39207305。
参考:https://www.jianshu.com/p/0c296b05ef2ahttps://www.jianshu.com/p/0ecb499ebc65
https://blog.csdn.net/u010178611/article/details/82592393
https://blog.csdn.net/chen495810242/article/details/39207305