一 H.264句法
1.1元素分层结构
H.264编码器输出的Bit流中,每个Bit都隶属于某个句法元素。句法元素被组织成有层次的结构,分别描述各个层次的信息。
图1
H.264分层结构由五层组成,分别是序列参数集、图像参数集、片(Slice)、和宏块和子块。参数集是一个独立的数据单位,不依赖于参数集外的其它句法元素。图2描述了参数集与参数集外的句法元素之间的关系。
图2
一个参数集不对应某一个特定的图像或序列,同一序列参数集可以被多个图像参数集引用,同理,同一个图像参数集也可以被多个图像引用。只在编码器认为需要更新参数集的内容时,才会发出新的参数集。
在H.264中,图像以序列为单位进行组织。一个序列的第一个图像叫做IDR图像,IDR图像都是I帧,H.264引入IDR图像为了解码的同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。
IDR是I帧,但I帧不一定是IDR。I帧之后的图像有可能会使用I帧之前的图像做运动参考。
1.2描述子
描述子描述从Bit流中取出句法元素的方法。
编号
| 语法
| 说明
|
1
| ae(e)
| CABAC
|
2
| b(8)
| 读进连续的8个Bit
|
3
| ce(v)
| CAVLC
|
4
| f(n)
| 读进连续的n个Bit
|
5
| i(n)/i(v)
| 读进连续的若干Bit,并把它们解释为有符号整数
|
6
| me(v)
| 映射指数Golomb熵编码
|
7
| se(v)
| 有符号指数Golomb熵编码
|
8
| te(v)
| 截断指数Golomb熵编码
|
9
| u(n)/u(v)
| 读进连续的若干Bit,并把它们解释为无符号整数
|
10
| ue(v)
| 无符号指数Golomb熵编码
|
表1
1.3句法的表示方法
句法元素的名称由小写字母和一系列下划线组成,变量名称是大小写字母组成,中间没有下划线。
二 句法表
定义了H.264的句法,指明在码流中依次出现的句法元素及它们出现的条件、提取描述子等。句法表是分层嵌套的。
句法表中的C字段表示该句法元素的分类,这是为片区服务,分类的具体含义如下表描述。
nal_unit_type
| NAL类型
| C
|
0
| 未使用
|
|
1
| 不分区、非IDR的片
| 2,3,4
|
2
| 片分区A
| 2
|
3
| 片分区B
| 3
|
4
| 版分区C
| 4
|
5
| IDR图像中的片
| 2,3
|
6
| 补充增强信息单元(SEI)
| 5
|
7
| 序列参数集
| 0
|
8
| 图像参数集
| 1
|
9
| 分界符
| 6
|
10
| 序列结束
| 7
|
11
| 码流结束
| 8
|
12
| 填充
| 9
|
13..23
| 保留
|
|
24..31
| 不保留
|
|
表2
2.1 NAL语法
句法
| C
| Desc
|
nal_nuit(NumBytesInNALunit){/* NumBytesInNALunit为统计出来的数据长度 */
|
|
|
forbidden_zero_bit /* 等于0 */
| All
| f(1)
|
nal_ref_idc/* 当前NAL的优先级,取值范围0-3 */
| All
| u(2)
|
nal_unit_type /* NAL类型,见表2描述 */
| All
| u(5)
|
NumBytesInRBSP=0
|
|
|
for(i=1;i<NumBytesInNALunit;i++){
|
|
|
if(i+2<NumBytesInNALunit && next_bits(24)==0x000003{
|
|
|
/* 0x000003伪起始码,需要删除0x03这个字节 */
|
|
|
rbsp_byte[NumBytesInRBSP++]
| All
| b(8)
|
rbsp_byte[NumBytesInRBSP++]
| All
| b(8)
|
i+=2/* 取出前两个0x00后,跳过0x03 */
|
|
|
emulation_prevention_three_byte/* equal to 0x03 */
| All
| f(8)
|
}else{
|
|
|
rbsp_byte[NumBytesInRBSP++] /* 继续读取后面的字节 */
| All
| b(8)
|
}
|
|
|
}
|
|
|
表3
2.2序列参数集(SPS)
句法
| C
| Desc
|
seq_parameter_set_rbsp(){
|
|
|
profile_idc/* 指明所用的Profile */
| 0
| u(8)
|
constraint_set0_flag
| 0
| u(1)
|
constraint_set1_flag
| 0
| u(1)
|
constraint_set1_flag
| 0
| u(1)
|
reserved_zero_5bits /* equal to 0 */
| 0
| u(5)
|
level_idc /* 指明所用的Level */
| 0
| u(8)
|
seq_parameter_set_id /* 指明本序列参数集的id号,0-31,被图像集引用,编码需要产生新的序列集时,使用新的id,而不是改变原来参数集的内容 */
| 0
| ue(v)
|
log2_max_frame_num_minus4/* 为读取元素frame_num服务,frame_num标识图像的解码顺序,frame_num的解码函数是ue(v),其中v=log2_max_frame_num_minus4+4,该元素同时指明frame_num的最大值MaxFrameNum=2( log2_max_frame_num_minus4+4)*/
| 0
| ue(v)
|
pic_order_cnt_type /* 指明poc的编码方法,poc标识图像的播放顺序,poc可以由frame_num计算,也可以显示传送。poc共三种计算方式 */
| 0
| ue(v)
|
if(pic_order_cnt_type==0)
|
|
|
log2_max_pic_order_cnt_lsb_minus4 /* 指明变量MaxPicOrderCntLsb的值, MaxPicOrderCntLsb=2(log2_max_pic_order_cnt_lsb_minus4+4) */
| 0
| ue(v)
|
else if(pic_order_cnt_type==1){
|
|
|
delta_pic_order_always_zero_flag /* 等于1时,元素delta_pic_order_cnt[0]和delta_pic_order_cnt[1]不在片头中出现,并且它们的默认值是0,等于0时,上述两元素出现的片头中 */
| 0
| u(1)
|
offset_for_non_ref_pic /* 用来计算非参考帧或场的poc,[-231,231-1] */
| 0
| se(v)
|
offset_for_top_to_bottom_field/* 计算帧的底场的poc */
| 0
| se(v)
|
num_ref_frames_inpic_order_cnt_cycle /* 用来解码poc,[0.255] */
| 0
| ue(v)
|
for(i=0;i<num_ref_frames_inpic_order_cnt_cycle;i++)
|
|
|
offset_for_ref_frame[i]/* 用来解码poc,对于循环中的每个元素指定一个偏移 */
| 0
| se(v)
|
}
|
|
|
num_ref_frames /* 参考帧队列可达到的最大长度,[0,16] */
| 0
| ue(v)
|
gaps_in_frame_num_value_allowed_flag /* 为1,允许slice header中的frame_num不连续 */
| 0
| u(1)
|
pic_width_inmbs_minus1 /* 本元素加1,指明以宏块为单位的图像宽度 PicWidthInMbs=pic_width_in_mbs_minus1+1 */
| 0
| ue(v)
|
pic_height_in_map_units_minus1 /* 本元素加1,指明以宏块为单位的图像高宽度 PicHeightInMapUnitsMbs=pic_height_in_map_units_minus1+1 */
| 0
| ue(v)
|
frame_mbs_only_flag /* 等于0表示本序列中所有图像均为帧编码;等于1,表示可能是帧,也可能场或帧场自适应,具体编码方式由其它元素决定。结合前一元素:FrameHeightInMbs=(2-frame_mbs_only_flag)*PicHeightInMapUnits */
| 0
| ue(v)
|
if(frame_mbs_only_flag)
|
|
|
mb_adaptiv_frame_field_flag /* 指明本序列是否是帧场自适应模式:
frame_mbs_only_flag=1,全部是帧
frame_mbs_only_flag=0, mb_adaptiv_frame_field_flag=0,帧场共存
frame_mbs_only_flag=0, mb_adaptiv_frame_field_flag=1,帧场自适应和场共存*/
| 0
| u(1)
|
direct_8x8_inference_flag /* 用于指明B片的直接和skip模式下的运动矢量的计算方式 */
| 0
| u(1)
|
frame_cropping_flag /* 解码器是否要将图像裁剪后输出,如果是,后面为裁剪的左右上下的宽度 */
| 0
| u(1)
|
if(frame_cropping_flag){
|
|
|
frame_crop_left_offset
| 0
| ue(1)
|
frame_crop_right_offset
| 0
| ue(1)
|
frame_crop_top_offset
| 0
| ue(1)
|
frame_crop_bottom_offset
| 0
| ue(1)
|
}
|
|
|
vui_parameters_present_flag /* 指明vui子结构是否出现在码流中,vui子结构在附录中指明,用于表征视频格式的信息 */
| 0
| u(1)
|
if(vui_parameters_present_flag)
|
|
|
vui_parameters()
| 0
|
|
rbsp_trailing_bits()
| 0
|
|
}
|
|
|
表4
//////////////////////////////////////////////////////////////////////////代码//////////////////////////////////////////////////////////////////////////////////
以下是解析宽高的代码:
view sourceprint?001 | bool UDPReceiver::getResolution( int channel, int &Width, int & Height) |
003 | BYTE *buf = new BYTE [1024]; |
006 | BOOL bSpsComplete = FALSE; |
010 | int ret = av_read_frame(m_pFormatContext[channel], &packet); |
011 | if (packet.flags & AV_PKT_FLAG_KEY) |
013 | BYTE * p = packet.data; |
014 | BYTE last_nal_type = 0; |
016 | for ( int i=0; i<packet.size-5; i++) |
019 | if (p[0]==0x00&&p[1]==0x00&&p[2]==0x00&&p[3]==0x01) |
021 | if (last_nal_type == 0x67) |
023 | nLen = i-last_nal_pos; |
024 | memcpy (buf, packet.data+last_nal_pos, nLen); |
027 | last_nal_type = p[4]; |
035 | if (last_nal_type == 0x67 && bSpsComplete == FALSE) |
037 | nLen = packet.size - last_nal_pos; |
038 | memcpy (buf, packet.data+last_nal_pos, nLen); |
043 | // Analyze SPS to find width and height |
046 | int forbidden_zero_bit=u(1,buf,StartBit); |
047 | int nal_ref_idc=u(2,buf,StartBit); |
048 | int nal_unit_type=u(5,buf,StartBit); |
051 | int profile_idc=u(8,buf,StartBit); |
052 | int constraint_set0_flag=u(1,buf,StartBit); //(buf[1] & 0x80)>>7; |
053 | int constraint_set1_flag=u(1,buf,StartBit); //(buf[1] & 0x40)>>6; |
054 | int constraint_set2_flag=u(1,buf,StartBit); //(buf[1] & 0x20)>>5; |
055 | int constraint_set3_flag=u(1,buf,StartBit); //(buf[1] & 0x10)>>4; |
056 | int reserved_zero_4bits=u(4,buf,StartBit); |
057 | int level_idc=u(8,buf,StartBit); |
059 | int seq_parameter_set_id=Ue(buf,nLen,StartBit); |
061 | if ( profile_idc == 100 || profile_idc == 110 || |
062 | profile_idc == 122 || profile_idc == 144 ) |
064 | int chroma_format_idc=Ue(buf,nLen,StartBit); |
065 | if ( chroma_format_idc == 3 ) |
066 | int residual_colour_transform_flag=u(1,buf,StartBit); |
067 | int bit_depth_luma_minus8=Ue(buf,nLen,StartBit); |
068 | int bit_depth_chroma_minus8=Ue(buf,nLen,StartBit); |
069 | int qpprime_y_zero_transform_bypass_flag=u(1,buf,StartBit); |
070 | int seq_scaling_matrix_present_flag=u(1,buf,StartBit); |
072 | int seq_scaling_list_present_flag[8]; |
073 | if ( seq_scaling_matrix_present_flag ) |
075 | for ( int
i = 0; i < 8; i++ ) { |
076 | seq_scaling_list_present_flag[i]=u(1,buf,StartBit); |
080 | int log2_max_frame_num_minus4=Ue(buf,nLen,StartBit); |
081 | int pic_order_cnt_type=Ue(buf,nLen,StartBit); |
082 | if ( pic_order_cnt_type == 0 ) |
083 | int log2_max_pic_order_cnt_lsb_minus4=Ue(buf,nLen,StartBit); |
084 | else if ( pic_order_cnt_type == 1 ) |
086 | int delta_pic_order_always_zero_flag=u(1,buf,StartBit); |
087 | int offset_for_non_ref_pic=Se(buf,nLen,StartBit); |
088 | int offset_for_top_to_bottom_field=Se(buf,nLen,StartBit); |
089 | int num_ref_frames_in_pic_order_cnt_cycle=Ue(buf,nLen,StartBit); |
091 | int *offset_for_ref_frame= new int [num_ref_frames_in_pic_order_cnt_cycle]; |
092 | for ( int
i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ ) |
093 | offset_for_ref_frame[i]=Se(buf,nLen,StartBit); |
094 | delete [] offset_for_ref_frame; |
096 | int num_ref_frames=Ue(buf,nLen,StartBit); |
097 | int gaps_in_frame_num_value_allowed_flag=u(1,buf,StartBit); |
098 | int pic_width_in_mbs_minus1=Ue(buf,nLen,StartBit); |
099 | int pic_height_in_map_units_minus1=Ue(buf,nLen,StartBit); |
101 | Width=(pic_width_in_mbs_minus1+1)*16; |
102 | Height=(pic_height_in_map_units_minus1+1)*16; |
112 | // Ue find the num of zeros and get (num+1) bits from the first 1, and |
113 | // change it to decimal |
114 | // e.g. 00110 -> return 6(110)
|
115 | UINT UDPReceiver::Ue( BYTE *pBuff, UINT nLen, UINT &nStartBit) |
119 | while (nStartBit < nLen * 8) |
121 | if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) //&:按位与,%取余 |
133 | for ( UINT
i=0; i<nZeroNum; i++) |
136 | if (pBuff[nStartBit / 8] & (0x80 >> (nStartBit % 8))) |
142 | return (1 << nZeroNum) - 1 + dwRet; |
145 | int UDPReceiver::Se( BYTE *pBuff, UINT nLen, UINT &nStartBit) |
147 | int UeVal=Ue(pBuff,nLen,nStartBit); |
149 | int nValue=std:: ceil (k/2); //ceil函数:ceil函数的作用是求不小于给定实数的最小整数。ceil(2)=ceil(1.2)=cei(1.5)=2.00 |
155 | // u Just returns the BitCount bits of buf and change it to decimal. |
156 | // e.g. BitCount = 4, buf = 01011100, then return 5(0101) |
157 | DWORD UDPReceiver::u( UINT BitCount, BYTE * buf, UINT &nStartBit) |
160 | for ( UINT
i=0; i<BitCount; i++) |
163 | if (buf[nStartBit / 8] & (0x80 >> (nStartBit % 8))) |