H.264 and MPEG-4 Video
Compression
Video Coding for Next-generation Multimedia
Iain E. G. Richardson这本书是很经典的,如果要学习H.264以及视频编解码一定要看了。
在之前的视频编码说明中,变换与量化是分开做的,而H.264将二者放在一起做,达到了一定的目的(下面的分析中可以看出)。首先,我们了解到,变换,无论是离散余弦变换还是小波变换,都是将进行过预测和补偿的参差进行分离,使得能量更集中于左上。而之后的量化是将位于很大范围的一组数在可以接受的精确性下进行压缩。从公式上来说(我们以H.264选择的DCT说明),如果X为输入,Y为输出,如果是真正的DCT:Y=AXA'(表转置)。其中A的系数是如书上所示。之后,标准又变换了这个式子:Y=(CXC')@E,其中@表示书中的那种矩阵乘。可以知道,上面两个式子是完全等价的,令C中的系数d为c/b,即可(可以将E分解为A和A',然后使用该种矩阵乘)。为了简化运算,标准又令a=1/2,b=sqrt(2/5),d=1/2(这个完全是一个近似,可以接受的)。之后把d的1/2系数转移到E中,得到另外关于Ej的公式,而这样的变化使得C中系数不是1,就是2,做一个铺垫。这样计算出来的称为Y’。它与Y是有误差的。标准也进行了比较。
那么接下来如何将量化与上述变换放在一起呢?又能达到什么样的目的呢?
第一个问题,可以很简单的回答。总之量化是将输入的一组数据,每个除以一个参数(该参数是一个折衷的值,太大,可以使得得到的范围很小,但是重建的时候精确度不高;反之,可以得到很好匹配(match),但是压缩率达不到很好的效果)。那么我们在上述的变换中,先把Ej的元素量化,之后再乘以CXC'不就也是量化了吗?这就是将二者放在一起的一个方法。具体的就是在计算一个4x4块的T-Q时,先计算其CXC',然后再乘以Ej。从标准的说法来看,Ej是计算好的。到时候只要根据一定的方式找到合适的位置,就可以计算了。这个过程说起来很简单,要想真正理解还要进行说明。
DECLARE_ALIGNED2_MATRIX_H(quant, 6, 4 * 4, int16_t, CACHE_SIZE) =
{
13107, 8066, 13107, 8066, 8066, 5243, 8066, 5243,
13107, 8066, 13107, 8066, 8066, 5243, 8066, 5243,
11916, 7490, 11916, 7490, 7490, 4660, 7490, 4660,
11916, 7490, 11916, 7490, 7490, 4660, 7490, 4660,
10082, 6554, 10082, 6554, 6554, 4194, 6554, 4194,
10082, 6554, 10082, 6554, 6554, 4194, 6554, 4194,
9362, 5825, 9362, 5825, 5825, 3647, 5825, 3647,
9362, 5825, 9362, 5825, 5825, 3647, 5825, 3647,
8192, 5243, 8192, 5243, 5243, 3355, 5243, 3355,
8192, 5243, 8192, 5243, 5243, 3355, 5243, 3355,
7282, 4559, 7282, 4559, 4559, 2893, 4559, 2893,
7282, 4559, 7282, 4559, 4559, 2893, 4559, 2893
};这是T264中关于quant数组的说明,从我的理解quant[6][16]。那么,上面的每两行就是quant的一个16个系数。刚才说明的计算好的Ej,就是这个了。这个数组的标准中的对应可以看书上的表6.6。Qp表示了量化的尺度,一共六个选择,而每个选择要对一个4*4块的每个位置进行说明,很明显,就要如上的数组了。
我们再看一段代码:
void
quant4x4_c(int16_t* data, const int32_t Qp, int32_t is_intra)
{
const int32_t qbits = 15 + Qp / 6;
const int32_t mf_index = Qp % 6;
int32_t i;
const int32_t f = (1 << qbits) / (is_intra ? 3 : 6); /*标准中有说明,对于帧内和帧间的不同对待*/
for(i = 0 ; i < 16 ; i ++)
{
if (data[i] > 0)
data[i] = (data[i] * quant[mf_index][i] + f) >> qbits; /*f是round的实现*/
else
data[i] = -((-(data[i] * quant[mf_index][i]) + f) >> qbits); /*data出错的处理*/
}
} 从函数的定义我们就可以知道,是4*4的量化。而从上面的了解可以知道,其实就是对选择Ej来相乘。Qp是传进来的参数,它决定了6个4*4块的16参数选择哪个(六选一)。同时也决定了在乘之后左移的位数。
这样就基本了解了选择的方法。其实在代码中已经可以有灵感了,这样的变化使得计算中只有加减和移位,正是DSP的特长。
问题:Qp的大小与选择的块系数,还有移位qbits有什么相制约的关系?