1.4.3 AV1中的量化

AV1的量化参数的范围是0~255,比H264、H265中的最大范围52大了很多。量化步长和量化参数的关系图如图146所示。

图146 AV1量化步长和量化参数的关系图

对比图1-44,可以看出,图1-46的曲线与图1-44的曲线走向非常相似,只是范围变大了。另外,DC系数的量化步长小于AC系数,因为DC系数更重要,要保存更高的精度。

AV1参考代码的编码器输入参数中有一项名为cq_level,它的取值范围是0~63,cq_level与量化参数的关系用下面代码表示:

static const int quantizer_to_qindex[] = {

  0,   4,   8,   12,  16,  20,  24,  28,  32,  36,  40,  44,  48,

  52,  56,  60,  64,  68,  72,  76,  80,  84,  88,  92,  96,  100,

  104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, 148, 152,

  156, 160, 164, 168, 172, 176, 180, 184, 188, 192, 196, 200, 204,

  208, 212, 216, 220, 224, 228, 232, 236, 240, 244, 249, 255,

};

量化参数与量化步长的映射关系用下面代码表示:

static const int16_t dc_qlookup_QTX[QINDEX_RANGE] = {

  4,    8,    8,    9,    10,  11,  12,  12,  13,  14,  15,   16,   17,   18,

  19,   19,   20,   21,   22,  23,  24,  25,  26,  26,  27,   28,   29,   30,

  31,   32,   32,   33,   34,  35,  36,  37,  38,  38,  39,   40,   41,   42,

  43,   43,   44,   45,   46,  47,  48,  48,  49,  50,  51,   52,   53,   53,

  54,   55,   56,   57,   57,  58,  59,  60,  61,  62,  62,   63,   64,   65,

  66,   66,   67,   68,   69,  70,  70,  71,  72,  73,  74,   74,   75,   76,

  77,   78,   78,   79,   80,  81,  81,  82,  83,  84,  85,   85,   87,   88,

  90,   92,   93,   95,   96,  98,  99,  101, 102, 104, 105,  107,  108,  110,

  111,  113,  114,  116,  117, 118, 120, 121, 123, 125, 127,  129,  131,  134,

  136,  138,  140,  142,  144, 146, 148, 150, 152, 154, 156,  158,  161,  164,

  166,  169,  172,  174,  177, 180, 182, 185, 187, 190, 192,  195,  199,  202,

  205,  208,  211,  214,  217, 220, 223, 226, 230, 233, 237,  240,  243,  247,

  250,  253,  257,  261,  265, 269, 272, 276, 280, 284, 288,  292,  296,  300,

  304,  309,  313,  317,  322, 326, 330, 335, 340, 344, 349,  354,  359,  364,

  369,  374,  379,  384,  389, 395, 400, 406, 411, 417, 423,  429,  435,  441,

  447,  454,  461,  467,  475, 482, 489, 497, 505, 513, 522,  530,  539,  549,

  559,  569,  579,  590,  602, 614, 626, 640, 654, 668, 684,  700,  717,  736,

  755,  775,  796,  819,  843, 869, 896, 925, 955, 988, 1022, 1058, 1098, 1139,

  1184, 1232, 1282, 1336,

};

量化运算的除法运算,在实际计算中都要改成乘法加右移运算。在AV1中,通过以下代码来完成转换:

//  Qstep是量化步长

for (l = 0; Qstep> 1; l++) Qstep>>= 1;

// 根据量化步长的范围,把65536放大一定倍数后除量化步长,也就是计算量化步长的倒数。如果用65536直接除量化步长,把结果保存下来用在量化过程,那就等于对不同的量化步长,保存了不同的精度。量化步长越大,量化步长的倒数保存的精度越低。为了避免这种情况发生,AV1中根据量化步长的值的范围,在用65536除量化步长之前,先把65536根据量化步长的范围放大一定的倍数,这样就保持了较高的精度

  m = 1 + (1 <<(16 + l)) / Qstep ;

  // 把量化步长倒数与65536的差保存下来

  *quant_ptr= (int16_t)(m - (1 << 16));

  // 把l也保留下来

  *quant_shift_ptr = 1 << (16 - l);

AV1为了保持更高的量化精度,做了精心的设计,包括:量化步长倒数需要保存的精度、右移的位数、量化中需要完成前面DCT遗留的移位运算。这让整个的量化过程看上去很复杂。

AV1编码中的量化与反量化过程是在函数aom_quantize_b_helper_c()中完成的,部分代码如下:

for (i = 0; i < non_zero_count; i++) {

// 按照扫描顺序得到索引

const int rc = scan[i];

// 用索引得到DCT后的系数

const int coeff = coeff_ptr[rc];

// 得到当前系数的符号

const int coeff_sign = AOMSIGN(coeff);

// 得到当前系数的绝对值

const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;

int tmp32;

// 如果使用量化矩阵,就取出量化矩阵中对应位置的值,否则,使用32 

const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS);

// 判断一下当前DCT值是否大于量化步长,如果大于,再做量化。

if (abs_coeff * wt >= (zbins[rc != 0] << AOM_QM_BITS){

// 对DCT值做rounding,clip操作

int64_t tmp =

          clamp(abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], log_scale), INT16_MIN, INT16_MAX);

// 以下这两行,是在做量化,量化运算虽然是一个除法运算,但是实际运算时都是把除数放大2的N次方,做乘法,然后再右移N位。((tmp * quant_ptr[rc != 0])>> 16) + tmp操作的来源就是上面的 *quant_ptr= (int16_t)(m - (1 << 16));。这个量化过程看上去与众不同,多了一个+tmp的操作,因为在计算保存quant_ptr的时候,做了一个- (1 << 16)操作。这里面的log_scale,是跟变换块大小相关的,小于32×32的为0,32×32的为1,大于32×32的为2。它是变换操作遗留的移位运算。

tmp *= wt;

      tmp32 = (int)(((((tmp * quant_ptr[rc != 0])>> 16) + tmp) *

                     quant_shift_ptr[rc != 0])>>(16 - log_scale + AOM_QM_BITS)); 

// 把量化后的值加上符号,保存起来

      qcoeff_ptr[rc] = (tmp32 ^ coeff_sign) - coeff_sign;

// 下面是反量化的过程,首先得到反量化矩阵中的对应值,如果没有,就是32

      const int iwt = iqm_ptr != NULL ? iqm_ptr[rc] : (1 << AOM_QM_BITS);

// 得到反量化系数

      const int dequant =

(dequant_ptr[rc != 0] * iwt + (1 <<(AOM_QM_BITS - 1))) >>AOM_QM_BITS;

// 做反量化,这个简单,就是一个乘法操作

      const tran_low_t abs_dqcoeff = (tmp32 * dequant) >> log_scale;

// 添加符号位,保存起来

      dqcoeff_ptr[rc] = (tran_low_t)((abs_dqcoeff ^ coeff_sign) - coeff_sign);

// 记录最后一个非0值的索引

      if (tmp32) eob = i;

    }

  }

从以上代码可以看出,AV1的量化过程还是比较复杂的。但是,从它的反量化代码来看,量化过程就是一个除法运算。反量化代码为:

abs_dqcoeff = (tmp32 * dequant) >> log_scale;

AV1中也提供了15组量化矩阵,针对不同的变化块大小、亮度和色度分量使用不同的量化矩阵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值