H264学习1 手解NAL单元
作为一名向进军流媒体行业的工程师,学习H264太过于枯燥一时间理解不了H264的算法概念什么的就先从解析H264的源数据开始吧。
1.文件结构
H264的源文件是由NAL单元组成,一个完整的NAL数据由起始码前缀,NAL头和RBSP三部分组成。
起始码前缀为:0X00 0X00 0X00 0X01四个连续的字符组成。
NAL头由一个字节组成:
bit[7]固定为0即必须为0 表示:forbidden_zero_bit
bit[6:5]:表示:nal_ref_idc
bit[4:0]:表示NAL单元的类型,nal_unit_type
剩余的部分就是整个文件的主题部分RBSP
2.准备工作
在这里需要重要的提一下分析H264文件数据的时候一般是以bit 流的形式去分析数据除了常见的整形数据类型还有哥伦比亚指数编码。还有就是需要将NAL单元的除起始码前缀和NAL头部分的数据转换为RBSP形式。
2.1哥伦比亚指数编码解析
2.1.1哥伦比亚指数编码无符号数的解码
(1)首先读取当前位置的bit位,记录连续0的个数N
(2)对于连续0的个数为0值为0,对于连续0的个数不为0 跳过第一个非0的bit位
(3)再读取N个数据,此数据以无符号形式解析num
(4)num=num-1+2的N次方
2.1.2哥伦比亚指数编码有符号数的解码
(1)按照2.1.1的讲述先获取此段数据的哥伦比亚指数编码的无符号形式
(2)如果数据为奇数num=(num+1)/2;如果是偶数num=-(num/2)
2.2将NAL数据转换为RBSP数据
其实这个部分需要做的就是将NAL单元除头部的数据剔除连续两个0x00数据后面的0x03数据。
3.手动解析
当前获取的源数据为:
00 00 00 01 67 64 00 0C
AC D9 41 41 FB 01 10 00
00 03 00 10 00 00 03 01
E0 F1 42 99 60
NAL头部的数据为0x67(0110 0111)所以forbidden_zero_bit(0)的值为0,nal_ref_idc(11)的值为(3),nal_unit_type(00111)的值为7表示后面的RBSP数据为参数序列集
将后面的数据转换为RBSP格式的数据为:
64 00 0C
AC D9 41 41 FB 01 10 00
00 00 10 00 00 01
E0 F1 42 99 60
解析参数序列集的过程如下图所示
描述符一列表示此处数据的类型f和u表示的是无符号的数据类型,ue表示的是哥伦比亚指数编码的无符号数据,se表示的是哥伦比亚指数编码的有符号数据。
0x67
procfile:占用8个bit,当前使用到的字符为0x67数据类型为无符号类型所以值为100。
0x00
constraint_set0_flag0:占用1个bit,当前使用到的字符为0x0,二进制状态为0000 0000,数据类型为无符号类型所以值为0;
constraint_set0_flag1:占用1个bit,当前使用到的字符为0x0,二进制状态为000 0000,数据类型为无符号类型所以值为0;
constraint_set0_flag2:占用1个bit,当前使用到的字符为0x0,二进制状态为00 0000,数据类型为无符号类型所以值为0;
constraint_set0_flag3:占用1个bit,当前使用到的字符为0x0,二进制状态为0 0000,数据类型为无符号类型所以值为0;
constraint_set0_flag4:占用4个bit,当前使用到的字符为0x0,二进制状态为0000,数据类型为无符号类型所以值为0;
0x0C
level_idc:占用8个bit,当前使用到的字符为0x0c数据类型为无符号类型所以值为12。
0xAC
seq_parameter_set_id:使用哥伦比亚指数编码的无符号数,二进制状态1010 1100,连续0的个数为0,占用数据1bit,所以值为0.
由于procfile的值为100
chroma_format_idc:使用哥伦比亚指数编码的无符号数,二进制状态010 1100,连续0的个数为1,占用数据3bit,所以值为1(0+2-1).
bit_depth_luma_minus8:使用哥伦比亚指数编码的无符号数,二进制状态1100,连续0的个数为0,占用数据1bit,所以值为0.
bit_depth_chroma_minus8:使用哥伦比亚指数编码的无符号数,二进制状态100,连续0的个数为0,占用数据1bit,所以值为0.
qpprime_y_zero_transform_bypass_flag:占用1个bit,当前使用到的字符为0xAC,二进制状态为00,数据类型为无符号类型所以值为0;
seq_scaling_matrix_present_flag:占用1个bit,当前使用到的字符为0xAC,二进制状态为0,数据类型为无符号类型所以值为0;
0xD9
log2_max_frame_num_minus4:使用哥伦比亚指数编码的无符号数,二进制状态1101 1001,连续0的个数为0,占用数据1bit,所以值为0.
pic_order_cnt_type:使用哥伦比亚指数编码的无符号数,二进制状态101 1001,连续0的个数为0,占用数据1bit,所以值为0.
log2_max_pic_order_cnt_lsb_minus4:使用哥伦比亚指数编码的无符号数,二进制状态01 1001,连续0的个数为1,占用数据3bit,所以值为2.
0X41
num_ref_frames:使用哥伦比亚指数编码的无符号数,二进制状态001 0100 0001,连续0的个数为2,占用数据5bit,所以值为4.
gaps_in_frame_num_value_allowed_flag 0:占用1个bit,当前使用到的字符为0x41,二进制状态为00 0001,数据类型为无符号类型所以值为0;
0X41
pic_width_in_mbs_minus1:使用哥伦比亚指数编码的无符号数,二进制状态0 0001 0100 0001,连续0的个数为4,占用数据9bit,所以值为19.
0XFB
pic_height_in_map_units_minus1:使用哥伦比亚指数编码的无符号数,二进制状态0001 1111 1011,连续0的个数为3,占用数据7bit,所以值为14.
frame_mbs_only_flag:占用1个bit,当前使用到的字符为0xFB,二进制状态为1 1011,数据类型为无符号类型所以值为1;
direct_8x8_inference_flag:占用1个bit,当前使用到的字符为0xFB,二进制状态为1011,数据类型为无符号类型所以值为1;
frame_cropping_flag:占用1个bit,当前使用到的字符为0xFB,二进制状态为011,数据类型为无符号类型所以值为0;
vui_parameters_present_flag:占用1个bit,当前使用到的字符为0xFB,二进制状态为11,数据类型为无符号类型所以值为1;
aspect_ratio_info_present_flag:占用1个bit,当前使用到的字符为0xFB,二进制状态为1,数据类型为无符号类型所以值为1;
0X01
aspect_ratio_idc:占用8个bit,当前使用到的字符为0x01,二进制状态为0000 0001数据类型为无符号类型所以值为1;
0x10
overscan_info_present_flag:占用1个bit,当前使用到的字符为0x01,二进制状态为0001 0000数据类型为无符号类型所以值为0;
video_signal_type_present_flag:占用1个bit,当前使用到的字符为0x01,二进制状态为001 0000数据类型为无符号类型所以值为0;
chroma_loc_info_present_flag:占用1个bit,当前使用到的字符为0x01,二进制状态为01 0000数据类型为无符号类型所以值为0;
timing_info_present_flag:占用1个bit,当前使用到的字符为0x01,二进制状态为1 0000数据类型为无符号类型所以值为1;
0X00 0X00 0X00 0X10
num_units_in_tick:占用32个bit,当前使用到的字符为0x0 0X00 0X00 0X00 0X10,二进制状态为0000 0000 0000 0000 0000 0000 0000 0001数据类型为无符号类型所以值为1;
0X00 0X00 0X01 0XE0
time_scale:占用32个bit,当前使用到的字符为0x0 0X00 0X00 0X01 0XE0,二进制状态为0000 0000 0000 0000 0000 0001 1110 0000数据类型为无符号类型所以值为30;
0XE0
fixed_frame_rate_flag:占用1个bit,当前使用到的字符为0xe0,二进制状态为0000数据类型为无符号类型所以值为0;
nal_hrd_parameters_present_flag :占用1个bit,当前使用到的字符为0xe0,二进制状态为000数据类型为无符号类型所以值为0;
vcl_hrd_parameters_present_flag:占用1个bit,当前使用到的字符为0xe0,二进制状态为00数据类型为无符号类型所以值为0;
pic_struct_present_flag:占用1个bit,当前使用到的字符为0xe0,二进制状态为0数据类型为无符号类型所以值为0;
0XF1
bitstream_restriction_flag:占用1个bit,当前使用到的字符为0xF1,二进制状态为1111 0001数据类型为无符号类型所以值为1;
motion_vectors_over_pic_boundaries_flag:占用1个bit,当前使用到的字符为0xF1,二进制状态为111 0001数据类型为无符号类型所以值为1;
max_bytes_per_pic_denom:使用哥伦比亚指数编码的无符号数,二进制状态11 0001,连续0的个数为1,占用数据1bit,所以值为0.
max_bits_per_mb_denom:使用哥伦比亚指数编码的无符号数,二进制状态1 0001,连续0的个数为1,占用数据1bit,所以值为0.
0X42
log2_max_mv_length_horizontal:使用哥伦比亚指数编码的无符号数,二进制状态0001 0100 0010,连续0的个数为3,占用数据7bit,所以值为9.
0X99
log2_max_mv_length_vertical:使用哥伦比亚指数编码的无符号数,二进制状态0 0010 1001 1001,连续0的个数为3,占用数据7bit,所以值为9.
num_reorder_frames:使用哥伦比亚指数编码的无符号数,二进制状态01 1001,连续0的个数为1,占用数据3bit,所以值为2.
0x60
max_dec_frame_buffering:使用哥伦比亚指数编码的无符号数,二进制状态001 0110 0000,连续0的个数为2,占用数据5bit,所以值为4.
rbsp_stop_one_bit: 占用1个bit,当前使用到的字符为0x60,二进制状态为10 0000数据类型为无符号类型所以值为1;
满足一个完整的RBSP结构。
对比使用elecard stream analyze工具得到的结果对比,一致。