[音视频学习笔记]三、H.264视频码流解析

参考文献

H.264基础知识及视频码流解析

视音频数据处理入门:H.264视频码流解析

音视频面试必问-H264编码原理|为什么需要进行视频编码,I/P/B帧原理,预测-DCT-量化原理,FFmpeg编码实战

H.264基础知识及视频码流解析

一、H.264概述

1、编码是为了将数据进行压缩,这样在传输的过程中就不会使资源被浪费。

2、用一个简单的例子来说明编码的必要性:当你此刻显示器正在播放一个视频,分辨率是1280720,帧率是25,那么一秒所产生正常的数据大小为:1280720(位像素)*25(张) / 8(1字节8位)(结果:B) / 1024(结果:KB) / 1024 (结果:MB) = 2.75MB。显然一秒这么大的数据你是无法接受的,需要将数据进行压缩。

3、H264在视频采集到输出中属于编解码层次的数据,如下图所示,是在采集数据后做编码压缩时通过编码标准编码后所呈现的数据。

在这里插入图片描述
4、对于视频⽂件来说,视频由单张图⽚帧所组成,⽐如每秒25帧,但是图⽚帧的像素块之间存在相似性,因此视频帧图像可以进⾏图像压缩;H264采⽤了16*16的分块⼤⼩对,视频帧图像进⾏相似⽐较和压缩编码。如下图所示:

在这里插入图片描述

一、H264相关概念

1. 序列

  1. H264编码标准中所遵循的理论依据个人理解成:参照一段时间内相邻的图像中,像素、亮度与色温的差别很小。所以当面对一段时间内图像我们没必要去对每一幅图像进行完整一帧的编码,而是可以选取这段时间的第一帧图像作为完整编码,而下一幅图像可以记录与第一帧完整编码图像像素、亮度与色温等的差别即可,以此类推循环下去。

  2. 什么叫序列呢?上述的这段时间内图像变化不大的图像集我们就可以称之为一个序列。序列可以理解为有相同特点的一段数据。但是如果某个图像与之前的图像变换很大,很难参考之前的帧来生成新的帧,那么就结束删一个序列,开始下一段序列。重复上一序列的做法,生成新的一段序列。

2. 帧类型

  1. H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位。
  2. H26使⽤帧内压缩和帧间压缩的⽅式提⾼编码压缩率;
  3. H264采⽤了独特的I帧、P帧和B帧策略来实现,连续帧之间的压缩;
1. I帧

I帧:帧内编码帧 ,I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)

I帧特点:

  1. 它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
    解码时仅用I帧的数据就可重构完整图像;
  2. I帧描述了图像背景和运动主体的详情;
  3. I帧不需要参考其他画面而生成;
  4. I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
  5. I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧;
  6. I帧不需要考虑运动矢量;
  7. I帧所占数据的信息量比较大。
2. P帧

P帧:前向预测编码帧。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)

P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。

P帧特点:

  1. P帧是I帧后面相隔1~2帧的编码帧;
  2. P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);
  3. 解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
  4. P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧;
  5. P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧;
  6. 由于P帧是参考帧,它可能造成解码错误的扩散;
  7. 由于是差值传送,P帧的压缩比较高。
3. B帧

B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。

B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。

B帧特点

  1. B帧是由前面的I或P帧和后面的P帧来进行预测的;
  2. B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
  3. B帧是双向预测编码帧;
  4. B帧压缩比最高,因为它只反映两个参考帧间运动主体的变化情况,预测比较准确;
  5. B帧不是参考帧,不会造成解码错误的扩散。

3. GOP(画面组)

  1. GOP即Group of picture(图像组),指两个I帧之间的距离(下图所说的视频序列就是GOP),Reference(参考周期)指两个P帧之间的距离,可以理解为跟序列差不多意思,就是一段时间内变化不大的图像集,比较说GOP为120,如果是720 p60 的话,那就是2s一次I帧。一个I帧所占用的字节数大于一个P帧,一个P帧所占用的字节数大于一个B帧。所以在码率不变的前提下,GOP值越大,P、B帧的数量会越多,平均每个I、P、B帧所占用的字节数就越多,也就更容易获取较好的图像质量;Reference越大,B帧的数量越多,同理也更容易获得较好的图像质量。

  2. GOP结构一般有两个数字,如M=3,N=12。M指定I帧和P帧之间的距离,N指定两个I帧之间的距离。上面的M=3,N=12,GOP结构为:IBBPBBPBBPBBI。在一个GOP内I frame解码不依赖任何的其它帧,p frame解码则依赖前面的I frame或P frame,B frame解码依赖前最近的一个I frame或P frame 及其后最近的一个P frame。

4. IDR帧(关键帧)

  1. IDR(Instantaneous Decoding Refresh)即时解码刷新。 在编码解码中为了方便,将GOP中首个I帧要和其他I帧区别开,把第一个I帧叫IDR,这样方便控制编码和解码流程,所以IDR帧一定是I帧,但I帧不一定是IDR帧;IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始算新的序列开始编码。I帧有被跨帧参考的可能,IDR不会。

  2. I帧不用参考任何帧,但是之后的P帧和B帧是有可能参考这个I帧之前的帧的。IDR就不允许这样,例如:

在这里插入图片描述

  1. 其核⼼作⽤是,是为了解码的重同步,当解码器解码到 IDR 图像时,⽴即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。这样,如果前⼀个序列出现重⼤错误,在这⾥可以获得重新同步的机会。IDR图像之后的图像永远不会使⽤IDR之前的图像的数据来解码。
    在这里插入图片描述

三、H264压缩方式

H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。

帧内(Intraframe)压缩也称为空间压缩(Spatialcompression)。当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一般采用有损压缩算法,由于帧内压缩是编码一个完整的图像,所以可以独立的解码、显示。帧内压缩一般达不到很高的压缩,跟编码jpeg差不多。

帧间(Interframe)压缩的原理是:相邻几帧的数据有很大的相关性,或者说前后两帧信息变化很小的特点。也即连续的视频其相邻帧之间具有冗余信息,根据这一特性,压缩相邻帧之间的冗余量就可以进一步提高压缩量,减小压缩比。帧间压缩也称为时间压缩(Temporalcompression),它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的。帧差值(Framedifferencing)算法是一种典型的时间压缩法,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。

四. H264分层结构

1、 H264的主要目标是为了有高的视频压缩比和良好的网络亲和性,为了达成这两个目标,H264的解决方案是将系统框架分为两个层面,分别是视频编码层面(VCL:Video Coding Layer)和网络抽象层面(NAL:Network Coding Layer),H.264原始码流(裸流)是由⼀个接⼀个NALU组成,如下图:
在这里插入图片描述
2、 VLC层是对核心算法引擎、块、宏块及片的语法级别的定义,负责有效表示视频数据的内容,最终输出编码完的数据SODB;
3、 NAL层定义了片级以上的语法级别(如序列参数集和图像参数集,针对网络传输,后面会描述到),负责以网络所要求的恰当方式去格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL层将SODB打包成RBSP然后加上NAL头组成一个NALU单元,具体NAL单元的组成也会在后面详细描述。
4、 在VCL进⾏数据传输或存储之前,这些编码的VCL数据,被映射或封装进NAL单元。(NALU)
5、⼀个NALU = ⼀组对应于视频编码的NALU头部信息 + ⼀个原始字节序列负荷(RBSP,Raw Byte Sequence Payload).
6、NALU结构单元的主体结构如下所示;⼀个原始的H.264 NALU单元通常由[StartCode] [NALU Header] [NALU Payload]三部分组成,其中 Start Code ⽤于标示这是⼀个NALU 单元的开始,必须是"00 00 00 01" 或"00 00 01",除此之外基本相当于⼀个NAL header + RBSP;
7、SODB与RBSP的关联,具体结构如下图所示:

  1. SODB(String Of Data Bits): 数据比特串,是编码后的原始数据;
  2. RBSP(Raw Byte Sequence Payload): 原始字节序列载荷,即在SODB的后面添加了trailing bits,即一个bit 1和若干个bit 0,以便字节对齐;

8、RBSP的形成过程
如果SODB的内容是空的,那么RBSP的内容也是空的。否则,RBSP的第一个字节取自SODB的第1到第8个比特,RBSP字节内部按照从左到右从高到低的顺序排列。以此类推,RBSP中的每个字节都直接取自SODP的相应比特。RBSP的最后一个字节包含SODB的最后几个比特,以及trailing bits。其中,trailing bits的第一个比特为1,其余的比特为0,保证字节对齐。所以RBSP就等于,SODB在它的最后一个字节的最后一个比特后,紧跟值为1的1个比特,然后增加若干比特的0,以补齐这个字节。

五. H264码流结构

具体讲述NAL单元前,十分有必要先了解一下H264的码流结构。在经过编码后的H264的码流如下图所示,从图中我们需要得到一个概念,H264码流是由一个个的NAL单元组成,其中SPS、PPS、IDR和SLICE是NAL单元某一类型的数据。

六. H264的NAL单元

1. H264的NAL结构

1、在实际的网络数据传输过程中H264的数据结构是以NALU(NAL单元)进行传输的,传输数据结构组成为[NALU Header]+[RBSP],如下图所示:


2、从之前的分析我们可以知道,VCL层编码后的视频帧数据,帧有可能是I/B/P帧,这些帧也可能是属于不同的序列之中;同一序列也还有相应的序列参数集与图片参数集;综上所述,想要完成准确无误视频的解码,除了需要VCL层编码出来的视频帧数据,同时还需要传输序列参数集和图像参数集等等,所以RBSP不单纯只保存I/B/P帧的数据编码信息,还有其他信息也可能出现在里面。

3、上面知道NAL单元是作为实际视频数据传输的基本单元,NALU头是用来标识后面RBSP是什么类型的数据,同时记录RBSP数据是否会被其他帧参考以及网络传输是否有错误,所以针对NAL头和RBSP的作用以及结构与所承载的数据需要做个简单的了解。

2. NAL头
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值