通常一个H264码流中包含了多个GOP(图像组),每一个GOP里面包含多个视频编码帧,如下图所示。GOP(Group of Pictures)图像组的意思。H264码流对GOP的划分是两个邻近关键帧(IDR帧)之间的图像为一个GOP,包含前面的IDR帧,不包含后面的IDR帧,包含第一个IDR帧后面的所有P帧和B帧;如下图GOP图像包含了5个图像编码帧,一个IDR帧和两个P帧,两个B帧。
GOP又分为开放(open)GOP和闭合(close)GOP;open GOP是指当前GOP中的P帧和B帧能将前一个GOP的图像作为参考帧,并且open gop中不存在IDR帧,会有I帧(下面会介绍),假设下图是open GOP的情况,序号为6的P帧能参考序号为0的IDR帧(此时应该叫I帧)或者序号为6的P帧参考序号为1和4的P帧。close GOP是指当前GOP中的P帧和B帧不能将前一个GOP的图像作为参考帧,若下图是close GOP的情况序号为6的P帧不能参考序号为0的IDR帧,也不能参考序号为1和4的P帧,他只能参考序号为5的IDR帧。
一个GOP包含了一个IDR帧和多个P帧或B帧。这里在介绍下H264的编码帧类型:
- IDR帧:Instantaneous Decoding Refresh,即时解码刷新帧;也叫关键帧 。同时IDR帧也是I帧(帧内编码帧);IDR帧编码上采用帧内编码技术,即IDR帧的编码和解码不需要参考其他视频帧,只对图像做空间上冗余的压缩编码;解码过程遇到IDR帧会重新解析计算解码参数,并清空之前的解码信息,可以防止前面GOP内的错误延续到当前GOP。
- I帧:帧内(Intraframe)压缩编码帧;帧内压缩过程,主要是通过空间上邻近像素相似的特点来解决空间冗余(当前编码块/像素和周围块/像素存在相似或者相同就是空间冗余)的一个编码方法,比如常见的jpeg图像就是通过帧内编码压缩的图像。I帧不一定是IDR帧(关键帧),IDR帧一定是I帧/关键帧;I帧解码不会像P帧B帧那样需要依赖前面或者后面视频帧图像,所以I帧可以单独一帧来解码;I帧和IDR帧最大的区别在于解码过程是否会清空之前的解码信息(IDR帧会清空之前的解码信息,I帧则不会)。
- P帧:前向参考编码帧,通常采用帧间和帧内混合的编码方式。通常当前视频图像和前一帧视频图像有着相似和差异的内容,去除相似的内容,保留差异的值进行编码,就可以消除图像时间上的冗余;解码需要依赖参考帧,等参考帧解码完成后才能解码P帧。
- B帧:双向参考编码帧,就是需要参考前面一帧图像也需要参考后面的一帧的图像;和P帧类似,B帧通常也采用帧间和帧内混合的编码方式;不同的地方是P帧是和前一帧的差异做编码,B帧不仅仅和前一帧差异做编码,也和后面一帧的差异进行编码;B帧解码需要依赖前后的参考帧,等前后参考帧解码全部完成后才能解码B帧。
P帧和B帧在编码的过程也可以采用帧内编码的模式,B帧和P帧主要靠帧间编码来提示压缩率的。下图2-1是一个I帧/IDR帧的信息,下面中画面中需要的橙色方块就是I帧/IDR帧采用帧内编码的数据块。下图2-2是P帧的信息,图2-2中方块的颜色大多是蓝色,这表示这些数据采用帧间编码;另外有小部分是橙色方块这些块采用帧内编码。
二、H264帧结构:
我们知道H264视频码流是由若干个GOP组成,而GOP由一个I帧和多个P帧/B帧组成。那么I帧和P帧/B帧的构成是什么样子的呢?H264在功能上分为两层:NAL 层,和VLC层。
- NAL层:NetworkAbstraction Layer,网络提取层;再将VLC层数据进行存储或者传输前需要将这些VLC数据映射或者封装到NAL单元中。
- VLC层:VideoCoding Layer,视频编码层;视频图像编码后输出的数据,他表示被压缩后的视频序列。
在一帧编码图像中存在一个或多个NAL Unit(Nal 单元);NAL单元包含NAL Unit Header(Nal 单元头)和NAL Unit Body(Nal 单元主体数据);NAL Unit Header由起始码和Nal Type组成。NAL Unit Body通常是RBSP(Raw Byte Sequence Payload 原始字节序列载荷)数据 ,即编码后的比特流数据。
Nal Unit 起始码通常是十六进制数0x000001或者0x00000001;在解析Nal Unit的时候首先要找到起始码,根据起始码的位置来判断一个NalUnit的开始或者结束。NalUnit根据类型可以分为 SPS、PPS、I Slice、P slice、B slice等:
- SPS:Sequence Paramater Set 序列参数集;主要记录了编码视频的的 Profile、level、图像宽高等。
- PPS:Picture Paramater Set 图像参数集 ;主要记录编码数据所依赖的参数,如参考帧,图像序列计算方法等。
- Islice/Pslice/Bslice:编码帧片数据;在编码I帧、P帧或者B帧的时候会将待编码的图像分成一个或多个Slice(片),对每个Slice单独编码生成Slice编码数据;在多线程的时候多个Slice可以并行编码提高编码速度。
SPS和PPS记录的数据是GOP里面图像的信息或者单个图像的信息,这些信息都是公共的部分,比如一个GOP的图像分辨率都是一样的;所以通常SPS和PPS Nal Unit数据放在GOP的IDR帧前面或者I帧前面,通常说PPS和SPS在IDR/I帧里面。
如何区分Nal Unit里面数据类型呢?通过Nal Type来判断当前Nal Unit的类型;Nal Unit 定义如下;根据nal_unit_type字段来解析Nal Unit的类型。下图可以看出nal_unit_type在码流前8个bit中,具体在前8个比特的高5bit的位置,nal_unit_type的取值计算为(data[0] &0x1f)。
nal_unit_type字段定义如下;如下图可以知道 nal_unit_type为7时候 Nal Unit是SPS;nal_unit_type为8时候 Nal Unit是PPS;nal_unit_type为5时候 Nal Unit是IDR Slice;nal_unit_type为1时候 Nal Unit是非IDR Slice;nal_unit_type为9时候 Nal Unit是SEI(视频增强信息):
对于非IDR 的Slice我们可以进一步解析slice_header()中的slice_type;slice_header()定义如下图。
下图是slice_type的定义:
下图是码流分析工具StreamAnalyzer展现出的SPS Nal Unit的bit构成,如下蓝色区域数字,起始码为00000001 ,起始码后面的67为十六进制数,取高5bit得到nal_unit_type值是7:
下图是码流分析工具StreamAnalyzer展现出的PPS Nal Unit的bit构成,如下蓝色区域数字,起始码为00000001 ,起始码后面的68为十六进制数,取高5bit得到nal_unit_type值是8:
下图是码流分析工具StreamAnalyzer展现出的I slice Nal Unit的bit构成,如下蓝色区域数字,起始码为00000001 ,起始码后面的65为十六进制数,取高5bit得到nal_unit_type值是5:
下图是码流分析工具StreamAnalyzer展现出的P slice Nal Unit的bit构成,如下蓝色区域数字,起始码为00000001 ,起始码后面的61为十六进制数,取高5bit得到nal_unit_type值是1:
文章来源:https://blog.csdn.net/u010140427/article/details/127629547
版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。