h264 NALU的获取与分析

转自:
h264 NALU的获取与分析 - CSDN博客
https://blog.csdn.net/xiaoluer/article/details/53462894

一、如何从H264数据流中获取NALU
0x00000001或0x000001是一个nalu的起始标志,遇到下一个此标志时为该nalu的结尾。起始标志的后面第一个字节(type)里包含有nalu的类型,type & 0x1F即为该nalu的类型(nal_unit_type),具体类型分析详见下节。
二、H264帧分类
1、PPS与SPS
nal_unit_type=7时,nalu为SPS;nal_unit_type=8时,nalu为PPS。
SPS(Sequence Parameter Set)序列参数集,PPS(Picture Parameter Set)图像参数集。SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。如果对获取的nalu去掉开始码之后进行base64编码,得到的信息就可以用于sdp(SPS和PPS需要用逗号分隔开来)。下图为一个完整的sdp,sprop-parameter-sets为SPS和PPS的base64码,逗号前的为SPS,逗号后的为PPS:

2、I帧
nal_unit_type=5是,nalu为I帧。
I帧全名叫“IDR图像的编码条带”,俗称关键帧,也叫帧内编码帧 ,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)。
I帧特点:
1)它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
2)解码时仅用I帧的数据就可重构完整图像;
3)I帧描述了图像背景和运动主体的详情;
4)I帧不需要参考其他画面而生成;
5)I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
6)I帧是帧组GOP (Group of Pictures)的基础帧(第一帧),在一组中只有一个I帧;
7)I帧不需要考虑运动矢量;
8)I帧所占数据的信息量比较大。
3、nal_unit_type=1时,nalu为“非IDR图像的编码条带”,为P或B帧。
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帧的压缩比较高。
B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况,但我这样说简单些),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。
B帧的预测与重构
B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。
B帧特点
1)B帧是由前面的I或P帧和后面的P帧来进行预测的;
2)B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
3)B帧是双向预测编码帧;
4)B帧压缩比最高,因为它只反映了参考帧间运动主体的变化情况,预测比较准确;
5)B帧不是参考帧,不会造成解码错误的扩散。
注:I、B、P各帧是根据压缩算法的需要,是人为定义的,它们都是实实在在的物理帧。一般来说,I帧的压缩率是7(跟JPG差不多),P帧是20,B帧可以达到50。可见使用B帧能节省大量空间,节省出来的空间可以用来保存多一些I帧,这样在相同码率下,可以提供更好的画质。
三、h264 NALU分析示例
下图为用UE打开的一个h264文件:


该段数据中共有4个nalu,红色标注部分为4个nalu的起始位置,开头均为0x00000001四个字节,根据起始的第五个字节分析,段1:0x06 & 0x1f = 6,nalu为辅助增强信息 (SEI);段2:0x67 & 0x1f = 7,nalu为SPS;段3:0x68 & 0x1f = 8,nalu为PPS;段4:0x65 & 0x1f = 5,nalu为I帧。

四、附录
nal_unit_type类型列表:
nal_unit_type NAL 单元和 RBSP 语法结构的内容 备注
0 未指定  
1 一个非IDR图像的编码条带
slice_layer_without_partitioning_rbsp( )
 
2 编码条带数据分割块A
slice_data_partition_a_layer_rbsp( )
 
3 编码条带数据分割块B
slice_data_partition_b_layer_rbsp( )
 
4 编码条带数据分割块C
slice_data_partition_c_layer_rbsp( )
 
5 IDR图像的编码条带
slice_layer_without_partitioning_rbsp( )
I帧
6 辅助增强信息 (SEI)
sei_rbsp( )
 
7 序列参数集
seq_parameter_set_rbsp( )
SPS
8 图像参数集
pic_parameter_set_rbsp( )
PPS
9 访问单元分隔符
access_unit_delimiter_rbsp( )
 
10 序列结尾
end_of_seq_rbsp( )
 
11 流结尾
end_of_stream_rbsp( )
 
12 填充数据
filler_data_rbsp( )
 
13 序列参数集扩展
seq_parameter_set_extension_rbsp( )
 
14…18 保留  
19 未分割的辅助编码图像的编码条带
slice_layer_without_partitioning_rbsp( )
 
20…23 保留  
24…31 未指定  
下面是h264标准中定义的nalu类型宏:
#define NALU_TYPE_SLICE 1
#define NALU_TYPE_DPA 2
#define NALU_TYPE_DPB 3
#define NALU_TYPE_DPC 4
#define NALU_TYPE_IDR 5
#define NALU_TYPE_SEI 6
#define NALU_TYPE_SPS 7
#define NALU_TYPE_PPS 8
#define NALU_TYPE_AUD 9
#define NALU_TYPE_EOSEQ 10
#define NALU_TYPE_EOSTREAM 11
#define NALU_TYPE_FILL 12


一、如何从H264数据流中获取NALU
0x00000001或0x000001是一个nalu的起始标志,遇到下一个此标志时为该nalu的结尾。起始标志的后面第一个字节(type)里包含有nalu的类型,type & 0x1F即为该nalu的类型(nal_unit_type),具体类型分析详见下节。
二、H264帧分类
1、PPS与SPS
nal_unit_type=7时,nalu为SPS;nal_unit_type=8时,nalu为PPS。
SPS(Sequence Parameter Set)序列参数集,PPS(Picture Parameter Set)图像参数集。SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等。如果对获取的nalu去掉开始码之后进行base64编码,得到的信息就可以用于sdp(SPS和PPS需要用逗号分隔开来)。下图为一个完整的sdp,sprop-parameter-sets为SPS和PPS的base64码,逗号前的为SPS,逗号后的为PPS:

2、I帧
nal_unit_type=5是,nalu为I帧。
I帧全名叫“IDR图像的编码条带”,俗称关键帧,也叫帧内编码帧 ,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)。
I帧特点:
1)它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
2)解码时仅用I帧的数据就可重构完整图像;
3)I帧描述了图像背景和运动主体的详情;
4)I帧不需要参考其他画面而生成;
5)I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量);
6)I帧是帧组GOP (Group of Pictures)的基础帧(第一帧),在一组中只有一个I帧;
7)I帧不需要考虑运动矢量;
8)I帧所占数据的信息量比较大。
3、nal_unit_type=1时,nalu为“非IDR图像的编码条带”,为P或B帧。
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帧的压缩比较高。
B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况,但我这样说简单些),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。
B帧的预测与重构
B帧以前面的I或P帧和后面的P帧为参考帧,“找出”B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。接收端根据运动矢量在两个参考帧中“找出(算出)”预测值并与差值求和,得到B帧“某点”样值,从而可得到完整的B帧。
B帧特点
1)B帧是由前面的I或P帧和后面的P帧来进行预测的;
2)B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量;
3)B帧是双向预测编码帧;
4)B帧压缩比最高,因为它只反映了参考帧间运动主体的变化情况,预测比较准确;
5)B帧不是参考帧,不会造成解码错误的扩散。
注:I、B、P各帧是根据压缩算法的需要,是人为定义的,它们都是实实在在的物理帧。一般来说,I帧的压缩率是7(跟JPG差不多),P帧是20,B帧可以达到50。可见使用B帧能节省大量空间,节省出来的空间可以用来保存多一些I帧,这样在相同码率下,可以提供更好的画质。
三、h264 NALU分析示例
下图为用UE打开的一个h264文件:


该段数据中共有4个nalu,红色标注部分为4个nalu的起始位置,开头均为0x00000001四个字节,根据起始的第五个字节分析,段1:0x06 & 0x1f = 6,nalu为辅助增强信息 (SEI);段2:0x67 & 0x1f = 7,nalu为SPS;段3:0x68 & 0x1f = 8,nalu为PPS;段4:0x65 & 0x1f = 5,nalu为I帧。

四、附录
nal_unit_type类型列表:
nal_unit_type NAL 单元和 RBSP 语法结构的内容 备注
0 未指定  
1 一个非IDR图像的编码条带
slice_layer_without_partitioning_rbsp( )
 
2 编码条带数据分割块A
slice_data_partition_a_layer_rbsp( )
 
3 编码条带数据分割块B
slice_data_partition_b_layer_rbsp( )
 
4 编码条带数据分割块C
slice_data_partition_c_layer_rbsp( )
 
5 IDR图像的编码条带
slice_layer_without_partitioning_rbsp( )
I帧
6 辅助增强信息 (SEI)
sei_rbsp( )
 
7 序列参数集
seq_parameter_set_rbsp( )
SPS
8 图像参数集
pic_parameter_set_rbsp( )
PPS
9 访问单元分隔符
access_unit_delimiter_rbsp( )
 
10 序列结尾
end_of_seq_rbsp( )
 
11 流结尾
end_of_stream_rbsp( )
 
12 填充数据
filler_data_rbsp( )
 
13 序列参数集扩展
seq_parameter_set_extension_rbsp( )
 
14…18 保留  
19 未分割的辅助编码图像的编码条带
slice_layer_without_partitioning_rbsp( )
 
20…23 保留  
24…31 未指定  
下面是h264标准中定义的nalu类型宏:
#define NALU_TYPE_SLICE 1
#define NALU_TYPE_DPA 2
#define NALU_TYPE_DPB 3
#define NALU_TYPE_DPC 4
#define NALU_TYPE_IDR 5
#define NALU_TYPE_SEI 6
#define NALU_TYPE_SPS 7
#define NALU_TYPE_PPS 8
#define NALU_TYPE_AUD 9
#define NALU_TYPE_EOSEQ 10
#define NALU_TYPE_EOSTREAM 11
#define NALU_TYPE_FILL 12


猜你喜欢

转载自blog.csdn.net/qq_17368865/article/details/80222753