1、如何从H264数据流中获取NALU
0x00000001或0x000001是一个nalu的起始标志,遇到下一个此标志时为该nalu的结尾。起始标志的后面第一个字节(type)里包含有nalu的类型,type & 0x1F即为该nalu的类型(nal_unit_type),具体类型分析详见下节。
2、H264帧分类
一、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帧所占数据的信息量比较大。
三、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帧,这样在相同码率下,能够提供更好的画质。
3、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帧。
4、附录
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