基本概念
H264中常见的几种宏块有I、P、B宏块,宏块类型由宏块头中的mb_type确定。其中I slice中只允许存在I宏块,P slice允许存在P宏块和I宏块,B slice允许存在I宏块和B宏块。
为节省编码码流,mb_type包含了多个信息,比如该宏块的划分方式,子块预测方式,cbp等。
1.1 宏块划分方式
- I宏块支持16x16、4个8x8块、16个4x4块划分方式;
- P宏块支持16x16、2个16x8块、2个8x16块、4个8x8块(8x8块还需要再次划分)
- B宏块支持16x16、2个16x8块、2个8x16块、4个8x8块(8x8块还需要再次划分)
1.2 CodedBlockPatternLuma
CodedBlockPatternLuma是4bit数据,宏块中16x16亮度块分为4个8x8大小的块,每一个bit对应一个8x8亮度块,表示该8x8亮度块残差系数是否编码。
-
如果宏块预测模式为Intra_16x16,该宏块16x16亮度块划分为16个4x4块分别DCT变换后,16个块的DCT系数组成一个4x4亮度DC块,再进行hadamard变换,因此对于Intra_16x16宏块DC系数是单独编码,不受CodedBlockPatternLuma影响。
如果对应bit为0,表示该8x8块AC系数全为0;
如果不等于0,表示该8x8块至少有一个AC系数不为0,对码流进行熵解码得到对应系数; -
如果宏块预测模式不是Intra_16x16,
如果对应bit为0,表示该8x8块系数全为0;
如果不等于0,表示该8x8块至少有一个系数不为0,对码流进行熵解码得到对应系数;
1.3 CodedBlockPatternChroma
所有预测模式宏块中8x8色度块都会划分为4个4x4块,分别DCT变换后,将4个DC系数进行hadamard变换
CodedBlockPatternChroma表示该宏块色度块DCT系数是否编码。
2. I slice中mb_type对应的宏块类型
下表中transform_size_8x8_flag表示该宏块是否使用8x8大小的DCT变换,MbPartPredMode(mb_type, 0)表示宏块中第一个划分块的预测方式,Intra16x16PredMode表示帧内16x16块大小预测方式(一共4中预测方式)。
- mb_type为0,如果transform_size_8x8_flag=0,宏块划分为16个4x4块;如果transform_size_8x8_flag=1,宏块划分为4个8x8块;
- Mb_type为25,表示使用I_PCM编码方式
- mb_type在1-24之间,则表示宏块按照16x16大小编码,不再划分子块,并且可以根据mb_type的值确定16x16块预测方式Intra16x16PredMode(4种方式)和cbp;
3. P slice中mb_type对应的宏块类型
P slice中的宏块可以是P宏块也可以是I宏块,其中mb_type值为0-4表示P宏块,可参考下表,mb_type值为5-30表示I宏块,参考I宏块表,序号为mb_type的值减5.
- mb_type=0表示,该宏块不再划分子块,以16x16大小做前向预测;
- mb_type=1表示,该宏块划分为2个16x8块;
- mb_type=2表示,该宏块划分为2个8x16块;
- mb_type=3表示,该宏块划分为4个8x8块(其中每个8x8块还可以继续划分子块,由sub_mb_pred中的sub_mb_type语法确定);
- mb_type=4表示,该宏块划分方式与P_8x8一样,唯一的区别在于没有编码参考帧索引ref_idx0,需要根据相邻宏块预测得到;
- P_Skip宏块表示该宏块没有编码任何数据,残差全为0,并且参考帧索引ref_idx0和mv信息都可以从相邻宏块预测得到。可以根据slice data中的mb_skip_run/mb_skip_flag确定该宏块为skip宏块。
- mb_type=5-30表示该宏块为I宏块
需要注意的一点是:在JM代码中P slice中的I宏块值与标准文档有些出入,mbmode比mb_type值大1.
static void interpret_mb_mode_P(Macroblock *currMB)
{
static const short ICBPTAB[6] = {0,16,32,15,31,47};
short mbmode = currMB->mb_type;
if(mbmode < 4)
{
currMB->mb_type = mbmode;
memset(currMB->b8mode, mbmode, 4 * sizeof(char));
memset(currMB->b8pdir, 0, 4 * sizeof(char));
}
else if((mbmode == 4 || mbmode == 5))
{
currMB->mb_type = P8x8;
currMB->p_Slice->allrefzero = (mbmode == 5);
}
else if(mbmode == 6)
{
currMB->is_intra_block = TRUE;
currMB->mb_type = I4MB;
memset(currMB->b8mode, IBLOCK, 4 * sizeof(char));
memset(currMB->b8pdir, -1, 4 * sizeof(char));
}
else if(mbmode == 31)
{
currMB->is_intra_block = TRUE;
currMB->mb_type = IPCM;
currMB->cbp = -1;
currMB->i16mode = 0;
memset(currMB->b8mode, 0, 4 * sizeof(char));
memset(currMB->b8pdir,-1, 4 * sizeof(char));
}
else
{
currMB->is_intra_block = TRUE;
currMB->mb_type = I16MB;
currMB->cbp = ICBPTAB[((mbmode-7))>>2];
currMB->i16mode = ((mbmode-7)) & 0x03;
memset(currMB->b8mode, 0, 4 * sizeof(char));
memset(currMB->b8pdir,-1, 4 * sizeof(char));
}
}
3.1 P_8x8子宏块类型
对于每个P_8x8块还可以继续划分为sub-block,划分方式由sub_mb_type决定。如下表所示,
1)sub_mb_type=0,表示划分为1个8x8块
2)sub_mb_type=1,表示划分为2个8x4块
3)sub_mb_type=2,表示划分为2个4x8块
4)sub_mb_type=3,表示划分为4个4x4块
4. B slice中mb_type对应的宏块类型
B slice中可以存在I宏块和B宏块,其中mb_type值为0-22表示B 宏块,如下表所示;mb_type值为23-48表示I宏块
- mb_type为0表示该宏块使用direct预测模式,该宏块只编码残差信息,不编码参考帧索引和mv信息,这些可以通过direct预测方式得到;
- mb_type为1-3表示该宏块划分方式为16x16,帧间预测方式分别对应前向、后向、双向预测;
- mb_type为4-21表示该宏块划分方式和预测方式的各种组合,划分方式有16x8或8x16,两个MxN划分块预测方式可能为前向、后向、双向预测。
- mb_type为22表示该宏块划分为4个8x8块(8x8块还可继续往下划分);
- B_Skip表示该宏块没有编码任何数据,残差全为0,并且参考帧索引ref_idx0和mv信息都可以通过direct方式预测得到。可以根据slice data中的mb_skip_run/mb_skip_flag确定该宏块为skip宏块。
4.1 B_8x8子宏块划分方式
对于每个B_8x8块还可以继续划分为sub-block,划分方式由sub_mb_type决定。如下表所示,
1)sub_mb_type=0-3,表示划分为1个8x8块,分别使用direct、前向、后向、双向方式预测
2)sub_mb_type=4-9,表示划分方式为4x8或8x4,预测方式可以为前向、后向、双向
3)sub_mb_type=10-12,表示划分为4个4x4块,预测方式分别为前向、后向、双向