H264语法分析
一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)
映射指数熵编码
7
se(v)
有符号指数熵编码
8
te(v)
截断指数熵编码
9
u(n)/u(v)
读进连续的若干Bit,并把它们解释为无符号整数
10
ue(v)
无符号指数熵编码
表1
1.3句法的表示方法
句法元素的名称由小写字母和一系列下划线组成,变量名称是大小写字母组成,中间没有下划线。
二句法表
定义了H.264的句法,指明在码流中依次出现的句法元素及它们出现的条件、提取描述子等。句法表是分层嵌套的。
句法表中的C字段表示该句法元素的分类,这是为片区服务,分类的具体含义如下表描述。
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语法
编码器将每个NAL各自独立、完整地放入一个分组,因为分组都有头部,解码器可以方便地检测出NAL的分界,并依次取出NAL进行解码。
每个NAL前有一个起始码,解码器检测每个起始码,作为一个NAL的起始标识,当检测到下一个起始码时,当前NAL结束。同时H.264规定,当检测到时,也可以表征当前NAL的结束。对于NAL中数据出现或时,H.264引入了防止竞争机制,如果编码器检测到NAL数据存在或时,编码器会在最后个字节前插入一个新的字节0x03,这样:
->
->
->
->
解码器检测到时,把03抛弃,恢复原始数据。
解码器在解码时,首先逐个字节读取NAL的数据,统计NAL的长度,然后再开始解码。
句法
C
Desc
(){/* 为统计出来的数据长度*/
/*等于0 */
All
f(1)
/*当前NAL的优先级,取值范围0-3 */
All
u(2)
/* NAL类型,见表2描述*/
All
u(5)
=0
for(i=1;i
if(i+2
/* 伪起始码,需要删除0x03这个字节*/
[++]
All
b(8)
[++]
All
b(8)
i+=2/*取出前两个0x00后,跳过0x03 */
/* equal to 0x03 */
All
f(8)
}else{
[++]/*继续读取后面的字节*/
All
b(8)
}
}
表3
2.2序列参数集(SPS)
句法
C
Desc
sp(){
/*指明所用的 */
0
u(8)
0
u(1)
0
u(1)
0
u(1)
/* equal to 0 */
0
u(5)
/*指明所用的Level */
0
u(8)
/*指明本序列参数集的id号,0-31,被图像集引用,编码需要产生新的序列集时,使用新的id,而不是改变原来参数集的内容*/
0
ue(v)
inus4/*为读取元素服务,标识图像的解码顺序,的解码函数是ue(v),其中v=inus4+4,该元素同时指明的最大值=2( inus4+4)*/
0
ue(v)
/*指明poc的编码方法,poc标识图像的播放顺序,poc可以由计算,也可以显示传送。poc共三种计算方式*/
0
ue(v)
if(==0)
/*指明变量的值,=2(+4) */
0
ue(v)
else if(==1){
/*等于1时,元素[0]和[1]不在片头中出现,并且它们的默认值是0,等于0时,上述两元素出现的片头中*/
0
u(1)
ic/*用来计算非参考帧或场的poc,[-231,231-1] */
0
se(v)
/*计算帧的底场的poc */
0
se(v)
/*用来解码poc,[0.255] */
0
ue(v)
for(i=0;i
[i]/*用来解码poc,对于循环中的每个元素指定一个偏移*/
0
se(v)
}
/*参考帧队列可达到的最大长度,[0,16] */
0
ue(v)
/*为1,允许slice 中的不连续*/
0
u(1)
s1/*本元素加1,指明以宏块为单位的图像宽度=us1+1 */
0
ue(v)
/*本元素加1,指明以宏块为单位的图像高宽度bs=+1 */
0
ue(v)
/*等于0表示本序列中所有图像均为帧编码;等于1,表示可能是帧,也可能场或帧场自适应,具体编码方式由其它元素决定。结合前一元素:=(2-)* */
0
ue(v)
if()
/*指明本序列是否是帧场自适应模式:
=1,全部是帧
=0,=0,帧场共存
=0,=1,帧场自适应和场共存*/
0
u(1)
_flag/*用于指明B片的直接和skip模式下的运动矢量的计算方式*/
0
u(1)
/*解码器是否要将图像裁剪后输出,如果是,后面为裁剪的左右上下的宽度*/
0
u(1)
if(){
et
0
ue(1)
set
0
ue(1)
t
0
ue(1)
fset
0
ue(1)
}
/*指明vui子结构是否出现在码流中,vui子结构在附录中指明,用于表征视频格式的信息*/
0
u(1)
if()
()
0
()
0
}
表4
2.4片层句法
1片层句法(不分区)
句法
C
Desc
(){
()
2
()/* all of () */
2|3|4
bits()
2
}
表6
2片层A分区句法
句法
C
Desc
(){
()
2
2
ue(v)
()/* only 2 parts of () */
2
bits()
2
}
表7
3片层B分区句法
句法
C
Desc
(){
3
ue(v)
if()
3
()/* only 3 parts of () */
3
ue(v)
bits()
3
}
表8
4片层C分区句法
句法
C
Desc
(){
4
ue(v)
if()
4
()/* only 4 parts of () */
4
ue(v)
bits()
4
}
表9
5拖尾( bits)句法
句法
C
Desc
(){
/* equal to 1 */
All
f(1)
while(!())
bit/* equal to 0 */
All
f(1)
}
表10
6片头(Slice )句法
句法
C
Desc
(){
/*片中的第一个宏块地址,片通过这个句法元素来标定它自己的地址。在帧场自适应模式下,宏块都是成对出现,这时本句法元素表示的是第几个宏块对,对应的第一个宏块的真实地址应该是:2* */
2
ue(v)
/*片的类型,见表12 */
2
ue(v)
/*引用的图像集索引*/
2
ue(v)
/*每个参考帧都有一个连续的作为它们的标识,它指明了各图像的解码顺序。非参考帧也有,但没有意义。*/
2
u(v)
if(!){
/*片层中标识图像编码模式的唯一一个元素,详细描述,见图3 */
2
u(1)
if()
/* 1:底场,0:顶场*/
2
u(1)
}
if(==5)
/* IDR图像标识,不同的IDR图像有不同的IDR值。场模式下,IDR帧的两个场有相同的值,[0..65535] */
2
ue(v)
if(==0){
/*在poc的第一种算法中,显示传递poc的值,u(v)中,v=+4 */
2
u(v)
if(ag && !)
/*如果是在场模式下,场对中的两个场都各自被构造为一个图像,它们有各自的poc的计算方法来分别计算两场的poc,也就是一个场对拥有一对poc值;而在帧模式或帧场自适应模式下,一个图像只能根据片头中的元素计算出一个poc。在不为1时,每个帧或场自适应的图像在解码时,帧或帧场自适应中包含的两个场也必须有各自的poc值,通过本元素,可以在已经解码的帧或帧场自适应图像的poc基础上新映射一个poc,并把它赋给底场。*/
2
se(v)
}
if(==1 && !){
[0]/* poc的第二和第三种算法是从中映射得来,本元素用于帧编码下的底场和场编码方式的场*/
2
se(v)
if(ag && !)
[1]/*用于帧编码下的顶场*/
2
se(v)
}
if()
/*冗余片的id号*/
2
ue(v)
if(==B)
/* B图像在直接预测模式下,1:空间预测,0:时间预测*/
2
u(1)
if(==P||==SP||==B){
/*重载PPS中的参考帧队列中实际可用的参考帧的数目。*/
2
u(1)
if(){
/*重载值*/
2
ue(v)
if(==B)
/*重载值*/
2
ue(v)
}
}
ing()/*见第7节描述*/
2
if(( && (==P || ==SP)) || (==1 && ==B))
()/*见第8节描述*/
2
if(!=0)
()/*见第9节描述*/
2
if(flag && !=1 && != SI)
/*给出cabac初始化时表格的选择,[0..2] */
2
ue(v)
/*指出用于当前片的所有宏块的量化参数的初始值。=26++,[0..51] */
2
se(v)
if(==SP || ==SI){
if(==SP)
/*指出SP帧中的p宏块的解码方式是否是模式*/
2
u(1)
/*与的语义相似,用于SP和SI,QSY=26++,[0..51] */
2
se(v)
}
if(){
/* H.264指定了一套算法可以在解码器端独立地计算图像中各边界的滤波强度进行滤波。除了解码器独立计算之外,编码器也可以传递句法元素来干涉滤波强度,该元素指定了在块的是否使用滤波,同时批明那个块的边界不用滤波*/
2
ue(v)
if( != 1){
/*增强alpha时的偏移值,= =3 && -> */
if(!=I && !=SI){
/*指明List0是否进行重排序*/
2
u(1)
if()
do{
s_idc/*执行哪种重排序操作,见表14描述*/
2
ue(v)
if(s_idc==0 || s_idc==1)
us1/*对短期参考帧重排序时指明重排序图像与当前的差,见表14 */
2
ue(v)
(s_idc==2)
/*对长期参考帧得排序时指明重排序图像*/
2
ue(v)
}while(!=3)
}
if(==B){
/*指明List1是否进行重排序*/
2
u(1)
if()
do{
s_idc/*执行哪种重排序操作,见表14描述*/
2
ue(v)
if(s_idc==0 || s_idc==1)
us1/*对短期参考帧重排序时指明重排序图像与当前的差,见表14 */
2
ue(v)
(s_idc==2)
/*对长期参考帧得排序时指明重排序图像*/
2
ue(v)
}while(!=3)
}
}
表13
操作
0
短期参考帧重排序,us1会出现在码流中,从当前图像的减去(us1+1)后指明需要重排序的图像
1
短期参考帧重排序,us1会出现在码流中,从当前图像的加上(us1+1)后指明需要重排序的图像
2
长期参考帧重排序,会出现在码流中,指明需要重排序的图像。
3
结束循环,退出重排序操作。
表14
8加权预测的语义
句法
C
Desc
(){
om/*给出参考帧列表中参考图像所有亮度的加权系数,[0..7] */
2
ue(v)
enom/*给出参考帧列表中参考图像所有色度的加权系数,[0..7] */
2
ue(v)
for(i=0;i