H264帧类型判断

我们经常在网络直播推流或者客户端拉流的时候,需要对获取到的H.264视频帧进行判断后处理,我们经常获取到各种不同的视频数据0x67 0x68 0x65 0x61,0x27 0x28 0x25 0x21,0x47 0x48 0x45 0x41,各种不同的编码芯片有时间出来的NAL Header规则不大一样,那么我们怎么来以统一的方式判断帧的类型呢:sps、pps、IDR、P

如下转自EasyDarwin开源贡献者Kim的博客:http://blog.csdn.net/jinlong0603/article/details/70170042

H264

H264在网络传输的是NALU,NALU的结构是:NAL头+RBSP,实际传输中的数据流如图所示: 
这里写图片描述

其中NAL头占一个字节,其低5个bit位表示NAL type,具体如下表:

NAL typeNAL类型
0未使用
1非IDR的片
2片数据A分区
3片数据B分区
4片数据C分区
5IDR图像的片
6补充增强信息单元(SEI)
7序列参数集(SPS)
8图像参数集(PPS)
9分界符
10序列结束
11码流结束
12填充
13..23保留
24..31不保留

RBSP 为原始字节序列载荷。

NAL type为5,则此帧为I帧即关键帧,type为1时为非关键帧(P帧…)。 
在实际的H264数据帧中,往往帧NAL type前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧,然后是P帧…

SPS部分 
1. NALU起始符为00 00 00 01。 
2. 紧跟着起始符的是是Start code,如 00 00 00 01 0x67(start coe)

0x67的二进制是0110 0111, 以0x67为例分析如下(u: 0110 0111): 
1. forbidden_zero_bit 是禁止位,应该是第一位即u(1) = 0,1为语法有错误 
2. nal_ref_idc是参考级别,代表被其它帧参考情况,u(2) = 11 = 3(Nal_ref_idc表示NAL的优先级,0-3, 取值越大,表示当前NAL越重要,如果当前NAL是属于参考帧的片,或是序列参数集,或是图像参数集这些重要单位时,取值必须>0) 
3. nal_unit_type是该帧的类型,为剩下的5位,u(5) = 0 0111 = 7 
目前类型有: 
H264定义的类型 values for nal_unit_type 
typedef enum { 
NALU_TYPE_SLICE = 1, 
NALU_TYPE_DPA = 2, 
NALU_TYPE_DPB = 3, 
NALU_TYPE_DPC = 4, 
NALU_TYPE_IDR = 5, 
NALU_TYPE_SEI = 6, 
NALU_TYPE_SPS = 7, 
NALU_TYPE_PPS = 8, 
NALU_TYPE_AUD = 9, 
NALU_TYPE_EOSEQ = 10, 
NALU_TYPE_EOSTREAM = 11, 
NALU_TYPE_FILL = 12, 
(#)if (MVC_EXTENSION_ENABLE) 
NALU_TYPE_PREFIX = 14, 
NALU_TYPE_SUB_SPS = 15, 
NALU_TYPE_SLC_EXT = 20, 
NALU_TYPE_VDRD = 24 // View and Dependency Representation Delimiter NAL Unit 
(#)endif 
} NaluType; 
可以看出7是NALU_TYPE_SPS 即sequence parameter sets

3.start code后面紧跟着的是profile_idc, 如00 00 00 01 0x67 
0x64(profile_idc)

0x64转化为十进制则是100, 
H264定义如下: 
66 Baseline 
77 Main 
88 Extended 
100 High (FRExt) 
110 High 10 (FRExt) 
122 High 4:2:2 (FRExt) 
144 High 4:4:4 (FRExt) 
所以0x64是100 表示high_profile, High (FRExt)

参考: 
00 00 00 01 67 42 00 28 E9 00 
A0 0B 77 FE 00 02 00 03 C4 80 
00 00 03 00 80 00 00 1A 4D 88 
10 94 00 00 00 01 
00 00 00 01为NALu头,‍其余码流由十六进制转为二进制 
67 0110 0111 
42 0100 0010 
00 0000 0000 
28 0010 1000 
E9 1110 1001 
00 0000 0000 
A0 1010 0000 
0B 0000 1011 
77 0111 01/11 
…… 
94 1001 01//00 
说明: 
“/”后的码流要对照标准中AnnexE的句法表,是VUI(VideoUsabilityInformation?)的内容, 
不懂,不写了,只写SPS部分先。 
“//”后面两个0是补齐用的。 
NAL层句法:码,值 
forbidden_zero_bit(f(1)):0,0 
nal_ref_idc(u(2)):11, 3 
nal_unit_type(u(5)): 0 0111, 7, SPS 
SPS序列参数集的句法:码,值 
profile_idc(u(8)) = 0100 0010,66 , baseline profile基础档次 
constraint_set0_flag(u(1)):0,0 
constraint_set1_flag(u(1)):0,0 
constraint_set2_flag(u(1)):0,0 
constraint_set3_flag(u(1)):0,0 
reserved_zero_4bits(u(4)):0000,0 
level_idc(u(8)) :00101000,40 ,级别 
seq_parameter_set_id(ue(v)): 1, 0 
log2_max_frame_num_minus4(ue(v): 1, 0 
MaxFrameNum = 2^(0+4) = 16 
pic_order_cnt_type(ue(v)):1, 0 
log2_max_pic_order_cnt_lsb_minus4(ue(v)):010 ,1 
MaxPicOrderCntLsb = 2^(1+4) = 32 
num_ref_frames(ue(v)):010, 1 
gaps_in_frame_num_value_allowed_flag(u(1)):0,0 
pic_width_in_mbs_minus1(ue(v)): 0000001010000, 2^6-1+16 = 79 
PicWidthInMbs = pic_width_in_mbs_minus1 + 1 = 80 
pic_height_in_map_units_minus1(ue(v)): 00000101101 ,2^5-1+13 = 44 
PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1 =45 
frame_mbs_only_flag(u(1)):1,1 
direct_8x8_inference_flag(u(1)): 1,1 
frame_cropping_flag(u(1)):0,0 
vui_parameters_present_flag(u(1)):1 ,1 
这个参数为1,说明下面的句法存在 
vui_parameters( ) 
aspect_ratio_info_present_flag(u(1)):1

其中: 
pic_width_in_mbs_minus1 : 79 
pic_height_in_map_units_minus1 : 44 
(79+1)x16=1280 
(44+1)x16=720

NAL全称Network Abstract Layer, 即网络抽象层。
         在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。因此我们平时的每帧数据就是一个NAL单元(SPS与PPS除外)。在实际的H264数据帧中,往往帧前面带有00 00 00 01 或 00 00 01分隔符,一般来说编码器编出的首帧数据为PPS与SPS,接着为I帧……

如下图:


如何判断帧类型(是图像参考帧还是I、P帧等)?

     NALU类型是我们判断帧类型的利器,从官方文档中得出如下图:


我们还是接着看最上面图的码流对应的数据来层层分析,以00 00 00 01分割之后的下一个字节就是NALU类型,将其转为二进制数据后,解读顺序为从左往右算,如下:
(1)第1位禁止位,值为1表示语法出错
(2)第2~3位为参考级别
(3)第4~8为是nal单元类型

例如上面00000001后有67,68以及65

其中0x67的二进制码为:
0110 0111
4-8为00111,转为十进制7,参考第二幅图:7对应序列参数集SPS

其中0x68的二进制码为:
0110 1000
4-8为01000,转为十进制8,参考第二幅图:8对应图像参数集PPS

其中0x65的二进制码为:
0110 0101
4-8为00101,转为十进制5,参考第二幅图:5对应IDR图像中的片(I帧)

 

所以判断是否为I帧的算法为: (NALU类型  & 0001  1111) = 5   即   NALU类型  & 31 = 5

比如0x65 & 31 = 5

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值