音视频学习基础2-H264编码

2022-06-09  本文已影响0人  samonking

首先要弄明白编码的目的,有目的的学习效率会更好。编码是为了将数据进行压缩,这样在传输的过程中就不会使资源被浪费,用一个简单的例子来说明编码的必要性:当你此刻显示器正在播放一个视频,分辨率是1280*720,帧率是25,那么一秒所产生正常的数据大小为:1280*720(位像素)*25(张) / 8(1字节8位)(结果:B) / 1024(结果:KB) / 1024 (结果:MB) = 2.75MB显然一秒这么大的数据你是无法接受的,所以如果不将数据进行压缩,那么只能一首凉凉表达此刻的感受了

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

H264相关概念

1.序列

H264编码标准中所遵循的理论依据个人理解成:参照一段时间内相邻的图像中,像素、亮度与色温的差别很小。所以当面对一段时间内图像我们没必要去对每一幅图像进行完整一帧的编码,而是可以选取这段时间的第一帧图像作为完整编码,而下一幅图像可以记录与第一帧完整编码图像像素、亮度与色温等的差别即可,以此类推循环下去。什么叫序列呢?上述的这段时间内图像变化不大的图像集我们就可以称之为一个序列。序列可以理解为有相同特点的一段数据。但是如果某个图像与之前的图像变换很大,很难参考之前的帧来生成新的帧,那么久结束删一个序列,开始下一段序列。重复上一序列的做法,生成新的一段序列。

2.帧类型

H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位。在H264协议内定义了三种帧,分别是I帧、B帧与P帧。I帧就是之前所说的一个完整的图像帧,而B、帧与P帧所对应的就是之前说的不编码全部图像的帧。P帧与B帧的差别就是P帧是参考之前的I帧而生成的,而B帧是参考前后图像帧编码生成的。

I帧

(1).I帧不需要参考其它画面生成,解码时仅靠自己就可以重构完整的图像

(2).I帧图像进行帧内编码

3.GOP(画面组)

GOP我个人也理解为跟序列差不多意思,就是一段时间内变化不大的图像集。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帧(关键帧)

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

IDR就不允许这样,

例如:IDR1 P4 B2 B3P7B5 B6I10B8B9 P13 B11 B12 P16 B14 B15 

这里的B8可以跨过I10去参考P7IDR1 P4 B2 B3 P7 B5 B6IDR8P11B9B10 P14 B11 B12

 这里的B9就只能参照IDR8和P11,不可以参考IDR8前面的帧

作用:H.264引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码 

H264压缩方式

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

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

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

1.压缩方式说明

Step1:分组,也就是将一系列变换不大的图像归为一个组,也就是一个序列,也可以叫GOP(画面组);

Step2:定义帧,将每组的图像帧归分为I帧、P帧和B帧三种类型;

Step3:预测帧, 以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧;Step4:数据传输, 最后将I帧数据与预测的差值信息进行存储和传输。 

H264分层结构

H264的主要目标是为了有高的视频压缩比和良好的网络亲和性,为了达成这两个目标,H264的解决方案是将系统框架分为两个层面,分别是视频编码层面(VCL)和网络抽象层面(NAL)

VLC层是对核心算法引擎、块、宏块及片的语法级别的定义,负责有效表示视频数据的内容,最终输出编码完的数据SODB

NAL层定义了片级以上的语法级别(如序列参数集参数集和图像参数集,针对网络传输,后面会描述到),负责以网络所要求的恰当方式去格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL层将SODB打包成RBSP然后加上NAL头组成一个NALU单元,具体NAL单元的组成也会在后面详细描述。

这里说一下SODB与RBSP的关联,具体结构

SODB: 数据比特串,是编码后的原始数据

RBSP: 原始字节序列载荷,是在原始编码数据后面添加了结尾比特,一个bit“1”和若干个比特“0”,用于字节对齐。 

H264码流结构

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

H264的NAL单元

1.H264的NAL结构 

NAL 层的主要作用就是用于纠错

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

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

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

2.NAL头

NAL头的组成

NAL单元的头部是由forbidden_bit(1bit),nal_reference_bit(2bits)(优先级),nal_unit_type(5bits)(类型)三个部分组成的

所示:

1.F(forbiden):禁止位,占用NAL头的第一个位,当禁止位值为1时表示语法错误;

2.NRI:参考级别,占用NAL头的第二到第三个位;值越大,该NAL越重要。

3.Type:Nal单元数据类型,也就是标识该NAL单元的数据类型是哪种,占用NAL头的第四到第8个位

NAL单元数据类型

NAL类型主要就是下面图7中这些类型每个类型都有特殊的作用

在具体介绍NAL数据类型前,有必要知道 NAL分为VCL和非VCL的NAL单元。在图8中有介绍(图表中DIR应该为IDR),其中SPS、SEI、PPS等非VCL的NAL参数对解码和显示视频都是很有用的。

而另外一个需要了解的概念就是 参数集(Parameter sets),参数集是携带解码参数的NAL单元,参数集对于正确解码是非常重要的,在一个有损耗的传输场景中,传输过程中比特列或包可能丢失或损坏,在这种网络环境下,参数集可以通过高质量的服务来发送,比如向前纠错机制或优先级机制。Parameter sets与其之外的句法元素之间的关系

H264压缩比是  1/100

码流参考值 : https://docs.agora.io/cn

H264整个编码过程参考:H.264_MPEG-4-Part-10-White-Pager

https//en.wikipedia.org/wiki/Advanced_Video_Coding

上一篇下一篇

猜你喜欢

热点阅读