H.264 Quantizer

一般的量化器,可用下面的公式来表示:

$Z=\pm \left \lfloor\frac{ \left | W \right | }{\bigtriangleup }\right \rfloor$

反量化可表示为:

$W' = \bigtriangleup \cdot Z$

量化步长$\bigtriangleup$决定了量化器的编码压缩率与图像精度。如果$\bigtriangleup$比较大,相应的编码长度较小,图像细节损失较多;如果$\bigtriangleup$比较小,相应的编码长度较大,图像损失细节较少。编码器需根据实际图像来改变$\bigtriangleup$值。

Quantization Offset

可以看到,这种量化器是求下整,也就是会把区间$[0,\bigtriangleup)$的值量化成0。这种量化器显然不是最优的,最优的量化器在某区间上的量化值应该为该区间的期望值。为此需要知道残差变换系数的统计分布,这个分布是经过统计实验得出来的,其中帧间比帧内分布得更为集中。

为了表明分布集中于区间的期望值,引入了参数——offset(量化偏移量)$f$。相应的量化公式变为:

$Z=\pm \left \lfloor\frac{ \left | W \right | + f }{\bigtriangleup }\right \rfloor$

反量化保持不变:

$W' =\pm (\bigtriangleup \cdot Z)$

H.264参考模型建议:当帧内预测时$f = \bigtriangleup/3$,帧间预测时$f = \bigtriangleup/6$。

另外参数$f$可以控制量化死区(量化后为0区域)大小。

当$f$变大时,量化死区减少;当$f$变小时,量化死区增加。死区大小可以直接影响到视频图像的主观质量。变换后,图像高频部分的数值比较小,也就是说离0值比较接近。如果死区比较大,0值附近的值会被量化为0,则图像会损失这些细节。这个特性在电影中特别有用:在电影胶片上会随机分布着一些斑点,这些斑点是胶片化学物质的结晶体,由于这些斑点与视频的内容在时间、空间上的不相关性,其值没法在预测模块中预测到。因此这些斑点表现为变换后的一些小的高频系数。为了消除这些斑点,可取较小的$f$值,这样量化死区就会较大。在字幕区域的细节比较多,可对字幕区域取比较大的$f$值。

从上方的例子可以看出,死区特征的应用是与应用直接相关的,最好能根据不同的应用相应加以调整。

我们注意到通过参数$f$可以控制量化区间的偏移,以及控制死区大小。两者耦合在一起了。JVT-K026有个直接的解耦方法:加入一个新的参数$\Theta$来控制量化死区的大小,并将量化公式修改为:

$ Z=\pm \left \lfloor\frac{ \left | W \right | + \Theta + f }{\bigtriangleup }\right \rfloor $

$ W' = \pm (\bigtriangleup \cdot Z - \Theta) $

但是这种方法并没有被标准采用。

Quantization Step

H.264标准共设计了52个不同的量化步长$Q_{step}$,如下表所示,其中QP是量化参数,也就是量化步长的序号。QP由小变大,意味着量化步长的增大,也就是由精细变粗糙。

QP

Qstep QP Qstep QP Qstep QP Qstep QP Qstep

0

0.625 12 2.5 24 10 36 40 48 160

1

0.6875 13 2.75 25 11 37 44 49 176

2

0.8125 14 3.25 26 13 38 52 50 208

3

0.875 15 3.5 27 14 39 56 51 224

4

1 16 4 28 16 40 64    

5

1.125 17 4.5 29 18 41 72    

6

1.25 18 5 30 20 42 80    

7

1.375 19 5.5 31 22 43 88    

8

1.625 20 6.5 32 26 44 104    

9

1.75 21 7 33 28 45 112    

10

2 22 8 34 32 46 128    

11

2.25 23 9 35 36 47 144    

$Q_{step}$变化有明显的规律:QP每增加1,量化步长就增加12.25%(即$\sqrt[6]{2}-1$);QP每增加6,量化步长就增加一倍,即$Q_{step}(QP+6) = 2Q_{step}(QP)$。这样做就可以显著减少量化表与反量化表的大小,仅用0~5这6个QP的$Q_{step}$,通过右移就可以得到剩下所有的$Q_{step}$,即$Q_{step}(QP) = Q_{step}(QP\%6) \cdot 2^{QP/6}$。

在讲述变换的时候说过,变换的$\bigotimes$运算矩阵$E_f$可以合并到量化表中。下面来看一下该运算矩阵

$ E_f[i][j] = \begin{bmatrix} a^2 & \frac{1}{2}ab & a^2 & \frac{1}{2}ab\\ \frac{1}{2}ab & \frac{1}{4}b^2 & \frac{1}{2}ab & \frac{1}{4}b^2\\ a^2 & \frac{1}{2}ab & a^2 & \frac{1}{2}ab\\ \frac{1}{2}ab & \frac{1}{4}b^2 & \frac{1}{2}ab & \frac{1}{4}b^2 \end{bmatrix}$

得到量化矩阵所进行的合并运算如下(归一化为$2^{15}$)

$\begin{align*}Q(QP,i,j) &= \frac{E_f[i][j]}{Q_{step}(QP)}\times 2^{15+QP/6} \\ &= \frac{E_f[i][j]}{Q_{step}(QP\%6)\times 2^{QP/6}} \times 2^{15+QP/6} \\ &= \frac{E_f[i][j]}{Q_{step}(QP\%6)} \cdot 2^{15}\end{align*}$

上式表明$Q(QP,i,j) = Q(QP\%6,i,j)$

以$Q(0,0,0) $为例,

$\begin{align*}Q(0,0,0) &= \frac{a^2}{Q_{step}(QP)} \times 2^{15} \\ &= \frac{0.25}{0.625}\times 2^{15} \\ &= 13107 \end{align*}$

把0~5这6个QP的$Q_{step}$分别与$\bigotimes$运算矩阵$E_f$合并后,可以得到以下6个矩阵,即$Q(QP\%6,i,j)$

$Q(0,i,j) = \begin{bmatrix}13107 & 8066&13107& 8066\\ 8066& 5243& 8066& 5243\\13107& 8066&13107& 8066\\ 8066& 5243& 8066& 5243 \end{bmatrix}$

$Q(1,i,j) =\begin{bmatrix}11916& 7490&11916& 7490\\ 7490& 4660& 7490& 4660\\11916& 7490&11916& 7490\\ 7490& 4660& 7490& 4660\end{bmatrix}$

$Q(2,i,j)= \begin{bmatrix}10082& 6554&10082& 6554\\ 6554& 4194& 6554& 4194\\10082& 6554&10082& 6554\\ 6554& 4194& 6554& 4194\end{bmatrix}$

$Q(3,i,j) =\begin{bmatrix} 9362& 5825& 9362& 5825\\ 5825& 3647& 5825& 3647\\ 9362& 5825& 9362& 5825\\ 5825& 3647& 5825& 3647\end{bmatrix} $

$Q(4,i,j) =\begin{bmatrix} 8192& 5243& 8192& 5243\\ 5243& 3355& 5243& 3355\\ 8192& 5243& 8192& 5243\\ 5243& 3355& 5243& 3355\end{bmatrix} $

$Q(5,i,j) =\begin{bmatrix} 7282& 4559& 7282& 4559\\ 4559& 2893& 4559& 2893\\ 7282& 4559& 7282& 4559\\ 4559& 2893& 4559& 2893\end{bmatrix}$

在$E_f$矩阵中,可以看到里面有3个数值$a^2, ab, b^2$,合并到量化矩阵后,就有$3 \times 52 = 156$个参数。采用了上面的QP每增加6,量化步长增加一倍的方法后,参数就只有$3 \times 6 = 18$个参数:

$QuantMatrix[6][3] = \begin{bmatrix}13107 & 5243 & 8066 \\11916 & 4660 & 7490 \\10082 & 4194 & 6554 \\9362 & 3647 & 5825 \\8192 & 3355 & 5243 \\7282 & 2893 & 4559\end{bmatrix}$

采用量化矩阵的方式后,4x4整数DCT变换的量化公式为

$\begin{align*}Z_{ij} &= \frac{Y_{ij}\bigotimes E_f[i][j] + f'}{Q_{step}(QP)} \\ &= \frac{Y_{ij}\bigotimes E_f[i][j] + f}{Q_{step}(QP\%6)} \div 2^{QP/6} \\ &= Y_{ij}\bigotimes Q(QP\%6,i,j) \div 2^{15+QP/6}\end{align*}$

同样道理,逆量化矩阵为(归一化为$2^{10}$):

$\begin{align*}R(QP,i,j) &= E^R_f[i][j] \times Q_{step}(QP) \times 2^{10-QP/6} \\ &= E^R_f[i][j] \times Q_{step}(QP\%6) \times 2^{QP/6} \times 2^{10-QP/6} \\ &= E^R_f[i][j] \times Q_{step}(QP\%6) \times 2^{10}\end{align*}$

上式表明$R(QP,i,j) = R(QP\%6,i,j)$

逆量化公式为:

$\begin{align*}Y'_{ij} &= Z_{ij}\bigotimes E^R_f[i][j] \times Q_{step} \\&= Z_{ij} \bigotimes R(QP\%6,i,j) \div {2^{10-QP/6}}\end{align*}$

逆量化矩阵为

$dequantMat[6][3]= \begin{bmatrix} 160 & 256 & 208\\ 176 & 288 & 224\\ 208 & 320 & 256\\224 & 368 & 288\\ 256 & 400 & 320\\ 288 & 464 & 368\end{bmatrix}$

Nonuniformity Quantization

非一致性量化就是4x4或8x8矩阵上各个位置的量化权重不同,通过这种方法可以在进行量化之前调整量化步长,得到更适合人类视觉系统,更真实的图像。

加入权重矩阵$W_{ij}$后,量化矩阵与逆量化矩阵分别为:

$Q(QP,i,j) = \frac{1}{W_{ij}}\cdot \frac{E_f[i][j]}{Q_{step}(QP\%6)}\times 2^{15+QP/6}$

$ R(QP,i,j) = W_{ij} \cdot E^R_f[i][j] \times Q_{step}(QP\%6) \times 2^{10-QP/6}$

其中$W_{ij}$会被归一为16,即$2<<4$

JM18.6参考代码如下

量化矩阵:

/*!
************************************************************************
* \brief
* For calculating the quantisation values at frame level
*
* \par Input:
* none
*
* \par Output:
* none
************************************************************************
*/
void CalculateQuant4x4Param(VideoParameters *p_Vid)
{
QuantParameters *p_Quant = p_Vid->p_Quant;
ScaleParameters *p_QScale = p_Vid->p_QScale; pic_parameter_set_rbsp_t *active_pps = p_Vid->active_pps;
seq_parameter_set_rbsp_t *active_sps = p_Vid->active_sps; int i, j, k, temp;
int k_mod;
int present[];
int no_q_matrix=FALSE;//FALSE means donot use default quant ,use weight qp on config files (quantMat << 4 / weight) int max_bitdepth = imax(p_Vid->bitdepth_luma, p_Vid->bitdepth_chroma);
int max_qp = ( + *(max_bitdepth)); if(!active_sps->seq_scaling_matrix_present_flag && !active_pps->pic_scaling_matrix_present_flag) //set to no q-matrix
no_q_matrix=TRUE;
else
{
memset(present, , * sizeof(int)); if(active_sps->seq_scaling_matrix_present_flag)
for(i=; i<; i++)
present[i] = active_sps->seq_scaling_list_present_flag[i]; if(active_pps->pic_scaling_matrix_present_flag)
for(i=; i<; i++)
{
if((i==) || (i==))
present[i] |= active_pps->pic_scaling_list_present_flag[i];
else
present[i] = active_pps->pic_scaling_list_present_flag[i];
}
} if(no_q_matrix==TRUE)//normal quant
{
for(k_mod = ; k_mod <= max_qp; k_mod++)
{
k = k_mod % ;
set_default_quant4x4(p_Quant->q_params_4x4[][][k_mod], quant_coef[k], dequant_coef[k]);
set_default_quant4x4(p_Quant->q_params_4x4[][][k_mod], quant_coef[k], dequant_coef[k]);
set_default_quant4x4(p_Quant->q_params_4x4[][][k_mod], quant_coef[k], dequant_coef[k]);
set_default_quant4x4(p_Quant->q_params_4x4[][][k_mod], quant_coef[k], dequant_coef[k]);
set_default_quant4x4(p_Quant->q_params_4x4[][][k_mod], quant_coef[k], dequant_coef[k]);
set_default_quant4x4(p_Quant->q_params_4x4[][][k_mod], quant_coef[k], dequant_coef[k]);
}
}
else //weight quant
{
for(k_mod = ; k_mod <= max_qp; k_mod++)
{
k = k_mod % ;
for(j=; j<; j++)
{
for(i=; i<; i++)
{
temp = (j<<)+i;
//present means we use the weight quant on the file q_matrix.cfg
if((!present[]) || p_QScale->UseDefaultScalingMatrix4x4Flag[])
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/Quant_intra_default[temp];
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*Quant_intra_default[temp];
}
else
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/p_QScale->ScalingList4x4[][temp];
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*p_QScale->ScalingList4x4[][temp];
} if(!present[])
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp;
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp;
}
else
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[][temp]);
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[][temp]);
} if(!present[])
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp;
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp;
}
else
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[][temp]);
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_intra_default[temp]:p_QScale->ScalingList4x4[][temp]);
} if((!present[]) || p_QScale->UseDefaultScalingMatrix4x4Flag[])
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/Quant_inter_default[temp];
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*Quant_inter_default[temp];
}
else
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/p_QScale->ScalingList4x4[][temp];
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*p_QScale->ScalingList4x4[][temp];
} if(!present[])
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp;
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp;
}
else
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[][temp]);
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[][temp]);
} if(!present[])
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp;
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp;
}
else
{
p_Quant->q_params_4x4[][][k_mod][j][i].ScaleComp = (quant_coef[k][j][i]<<)/(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[][temp]);
p_Quant->q_params_4x4[][][k_mod][j][i].InvScaleComp = dequant_coef[k][j][i]*(p_QScale->UseDefaultScalingMatrix4x4Flag[] ? Quant_inter_default[temp]:p_QScale->ScalingList4x4[][temp]);
}
}
}
}
}
}

量化偏移矩阵

/*!
************************************************************************
* \brief
* Init quantization offset parameters
*
* \par Input:
* none
*
* \par Output:
* none
************************************************************************
*/ void InitOffsetParam (QuantParameters *p_Quant, InputParameters *p_Inp)
{
int i, k;
int max_qp_luma = ( + *(p_Inp->output.bit_depth[]));
int max_qp_cr = ( + *(p_Inp->output.bit_depth[])); for (i = ; i < (p_Inp->AdaptRoundingFixed ? : imax(max_qp_luma, max_qp_cr)); i++)
{
if (p_Inp->OffsetMatrixPresentFlag)
{
memcpy(&(p_Quant->OffsetList4x4[i][][]),&(p_Quant->OffsetList4x4input[][]), * sizeof(short)); // 25 * 16
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(p_Quant->OffsetList8x8input[][]), * sizeof(short)); // 15 * 64
}
else
{
if (p_Inp->OffsetMatrixFlat == )
{
// 0 (INTRA4X4_LUMA_INTRA)
memcpy(&(p_Quant->OffsetList4x4[i][][]),&(Offset_intra_flat_intra[]), * sizeof(short));
for (k = ; k < ; k++) // 1,2 (INTRA4X4_CHROMA_INTRA)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_flat_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 3,4,5,6,7,8 (INTRA4X4_LUMA/CHROMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 9,10,11,12,13,14 (INTER4X4)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_inter_flat[]), * sizeof(short)); // 0 (INTRA8X8_LUMA_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_flat_intra[]), * sizeof(short));
for (k = ; k < ; k++) // 1,2 (INTRA8X8_LUMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 3,4 (INTER8X8_LUMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_flat[]), * sizeof(short)); // 5 (INTRA8X8_CHROMAU_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_flat_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_flat[]), * sizeof(short)); // 10 (INTRA8X8_CHROMAV_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_flat_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_flat[]), * sizeof(short));
}
else if (p_Inp->OffsetMatrixFlat == )
{
// 0 (INTRA4X4_LUMA_INTRA)
memcpy(&(p_Quant->OffsetList4x4[i][][]),&(Offset_intra_default_intra[]), * sizeof(short));
for (k = ; k < ; k++) // 1,2 (INTRA4X4_CHROMA_INTRA)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_flat_chroma[]), * sizeof(short));
memcpy(&(p_Quant->OffsetList4x4[i][][]),&(Offset_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 4,5 (INTRA4X4_CHROMA_INTERP)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_flat_inter[]), * sizeof(short));
memcpy(&(p_Quant->OffsetList4x4[i][][]),&(Offset_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 7,8 (INTRA4X4_CHROMA_INTERB)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 9,10,11,12,13,14 (INTER4X4)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_inter_default[]), * sizeof(short)); // 0 (INTRA8X8_LUMA_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_default_intra[]), * sizeof(short));
for (k = ; k < ; k++) // 1,2 (INTRA8X8_LUMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 3,4 (INTER8X8_LUMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_default[]), * sizeof(short)); // 5 (INTRA8X8_CHROMAU_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_flat_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_default[]), * sizeof(short)); // 10 (INTRA8X8_CHROMAV_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_flat_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_flat_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_default[]), * sizeof(short));
}
else
{
// 0 (INTRA4X4_LUMA_INTRA)
memcpy(&(p_Quant->OffsetList4x4[i][][]),&(Offset_intra_default_intra[]), * sizeof(short));
for (k = ; k < ; k++) // 1,2 (INTRA4X4_CHROMA_INTRA)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_default_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 3,4,5,6,7,8 (INTRA4X4_LUMA/CHROMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 9,10,11,12,13,14 (INTER4X4)
memcpy(&(p_Quant->OffsetList4x4[i][k][]),&(Offset_inter_default[]), * sizeof(short)); // 0 (INTRA8X8_LUMA_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_default_intra[]), * sizeof(short));
for (k = ; k < ; k++) // 1,2 (INTRA8X8_LUMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 3,4 (INTER8X8_LUMA_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_default[]), * sizeof(short)); // 5 (INTRA8X8_CHROMAU_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_default_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 6,7 (INTRA8X8_CHROMAU_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 8,9 (INTER8X8_CHROMAU_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_default[]), * sizeof(short)); // 10 (INTRA8X8_CHROMAV_INTRA)
memcpy(&(p_Quant->OffsetList8x8[i][][]),&(Offset8_intra_default_chroma[]), * sizeof(short));
for (k = ; k < ; k++) // 11,12 (INTRA8X8_CHROMAV_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_intra_default_inter[]), * sizeof(short));
for (k = ; k < ; k++) // 8,9 (INTER8X8_CHROMAV_INTERP/INTERB)
memcpy(&(p_Quant->OffsetList8x8[i][k][]),&(Offset8_inter_default[]), * sizeof(short));
}
}
}
} /*!
************************************************************************
* \brief
* Calculation of the quantization offset parameters at the frame level
*
* \par Input:
* none
*
* \par Output:
* none
************************************************************************
*/
void CalculateOffset4x4Param (VideoParameters *p_Vid)
{
QuantParameters *p_Quant = p_Vid->p_Quant;
int k;
int qp_per, qp;
int img_type = ((p_Vid->type == SI_SLICE) ? I_SLICE : (p_Vid->type == SP_SLICE ? P_SLICE : p_Vid->type)); int max_qp_scale = imax(p_Vid->bitdepth_luma_qp_scale, p_Vid->bitdepth_chroma_qp_scale);
int max_qp = + max_qp_scale;
InputParameters *p_Inp = p_Vid->p_Inp; p_Vid->AdaptRndWeight = p_Inp->AdaptRndWFactor [p_Vid->nal_reference_idc != ][img_type];
p_Vid->AdaptRndCrWeight = p_Inp->AdaptRndCrWFactor[p_Vid->nal_reference_idc != ][img_type]; if (img_type == I_SLICE )
{
for (qp = ; qp < max_qp + ; qp++)
{
k = p_Quant->qp_per_matrix [qp];
qp_per = Q_BITS + k - OffsetBits;
k = p_Inp->AdaptRoundingFixed ? : qp; // Intra4x4 luma
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Intra4x4 chroma u
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Intra4x4 chroma v
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
}
}
else if (img_type == B_SLICE)
{
for (qp = ; qp < max_qp + ; qp++)
{
k = p_Quant->qp_per_matrix [qp];
qp_per = Q_BITS + k - OffsetBits;
k = p_Inp->AdaptRoundingFixed ? : qp; // Inter4x4 luma
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][], qp_per);
// Intra4x4 luma
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Inter4x4 chroma u
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][], qp_per);
// Intra4x4 chroma u
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Inter4x4 chroma v
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][], qp_per);
// Intra4x4 chroma v
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
}
}
else
{
for (qp = ; qp < max_qp + ; qp++)
{
k = p_Quant->qp_per_matrix [qp];
qp_per = Q_BITS + k - OffsetBits;
k = p_Inp->AdaptRoundingFixed ? : qp; // Inter4x4 luma
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Intra4x4 luma
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Inter4x4 chroma u
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][], qp_per);
// Intra4x4 chroma u
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
// Inter4x4 chroma v
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][], qp_per);
// Intra4x4 chroma v
update_q_offset4x4(p_Quant->q_params_4x4[][][qp], p_Quant->OffsetList4x4[k][ ], qp_per);
}
}
}

H.264 Quantization的更多相关文章

  1. h.264语法结构分析

    NAL Unit Stream Network Abstraction Layer,简称NAL. h.264把原始的yuv文件编码成码流文件,生成的码流文件就是NAL单元流(NAL unit Stre ...

  2. x264 - 高品质 H.264 编码器

    转自:http://www.5i01.cn/topicdetail.php?f=510&t=3735840&r=18&last=48592660 H.264 / MPEG-4 ...

  3. H.264 / MPEG-4 Part 10 White Paper-翻译

    1. Introduction Broadcast(广播) television and home entertainment(娱乐) have been revolutionised(彻底改变) b ...

  4. World’s Smallest h.264 Encoder

    转载 http://www.cardinalpeak.com/blog/worlds-smallest-h-264-encoder/ View from the Peak World’s Smalle ...

  5. h.264 Mode Decision

    Mode Decision(模式选择)决定一个宏块以何种类型进行分割.宏块的分割类型有以下几种: //P_Skip and B_Skip means that nothing need to be e ...

  6. H.264, MPEG4之间的关系

    百度百科搜索 H.264 H.264是国际标准化组织(ISO)和国际电信联盟(ITU)共同提出的继MPEG4之后的新一代数字视频压缩格式.H.264是ITU-T以H.26x系列为名称命名的视频编解码技 ...

  7. H.264 Profile

    提到High Profile H.264解码许多人并不了解,那么到底什么是High Profile H.264解码?其应用效果又是如何呢?  作为行业标准,H.264编码体系定义了4种不同的Profi ...

  8. (转载)H.264码流的RTP封包说明

    H.264的NALU,RTP封包说明(转自牛人) 2010-06-30 16:28 H.264 RTP payload 格式 H.264 视频 RTP 负载格式 1. 网络抽象层单元类型 (NALU) ...

  9. H.264的优势和主要特点

    H.264,同时也是MPEG-4第十部分,是由ITU-T视频编码专家组(VCEG)和ISO/IEC动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压 ...

随机推荐

  1. Linux用户root忘记密码的解决(unbuntu16.04)

    参考: http://www.linuxidc.com/Linux/2012-04/59069.htm http://www.68idc.cn/help/server/linux/2015060735 ...

  2. IOS web网页图片上传问题

    用html5编写图片裁切上传,在iphone手机上可能会遇到图片方向错误问题,在此把解决方法和大家分享一下,用到了html5的 FileReader和Canvas,如果还没有接触的同学,先了解一下其方 ...

  3. 点击Enter键,文本框焦点改变 分类: WinForm 2014-04-15 10:30 223人阅读 评论(0) 收藏

    一个例子: 一个简单的 登陆界面,有用户名.密码文本框.登陆按钮.  想要实现的效果是,用户输入用户名之后,点击Enter键进入到下一个文本框,同理,输入完密码之后,登陆按钮获得焦点,再次点击Ente ...

  4. Shiro Quartz之Junit測试Session管理

    Shiro的quartz主要API上提供了org.apache.shiro.session.mgt.quartz下session管理的两个类:QuartzSessionValidationJob和Qu ...

  5. ld: 18 duplicate symbols for architecture i386 .linker command failed with exit code 1 (use -v to see invocation)_

    昨天被linker这个错误卡了一个小时!!!各种办法都试了 是导入第三方的问题 .. 网上说 要把所有的.m文件导入  但是我下载的微博SDK根本不关事..后来 大概知道是导入了多个相同的文件... ...

  6. Weibo SSO认证 和初次请求数据

    在进行SSO请求之前 我们要先去新浪微博的开放平台http://open.weibo.com/进行创建应用.以便得到appKey 和AppSecret. 点击创建应用 .进行资料填写  在这里 App ...

  7. ACM vim配置

    ACM现场赛时用的,比较简短,但是主要的功能都有了. 直接打开终端输入gedit ~/.vimrc 把下面的东西复制到里面就行了. filetype plugin indent on colo eve ...

  8. POJ 2891 扩展欧几里德

    这个题乍一看跟剩余定理似的,但是它不满足两两互素的条件,所以不能用剩余定理,也是给了一组同余方程,找出一个X满足这些方程,如果找不到的话就输出-1 因为它不满足互素的条件,所以两个两个的合并,最后合成 ...

  9. Android 自定义Activity的标题栏(Titlebar)

    缺省的情况下,通常见到Activity的标题栏(Titlebar)是这样的(红色框内): HandleContacts是Activity的标题.有时候,我们希望能改变一下这样单调的状况.比如,要在标题 ...

  10. ASP.NET-FineUI开发实践-14

    以前写过一个表格自动补全,改下,就出现了部分级联修改.测试版本4.1.1 共享下JS,ext-part2.js       后台再来个得到数据的方法就可以了.   1.方法还是删除+插入,主要在  i ...