Commit b5bf7b13 authored by Yunqing Wang's avatar Yunqing Wang
Browse files

Add two-pass quantization

Optimized the quantization function by making it a two-pass
process. The first pass does a quick checking of the transform
coefficients against the base ZBIN, and only keep the good
enough set of coefficients for quantization. A skipping
check is added. If all coefficients are within the base ZBIN, no
quantization is needed. The second pass is the actual quantization
pass, which only processes the coefficient subset determined
in first pass. This reduces the computation. Furthermore, an
alternitive method is used for large transform size, which often
has sparse nonzero quantized coefficients.

Overall, the encoder speedup is about 4%. The quantization function
itself gets 20% faster.

Change-Id: I3a9dd0da6db030260b6d9c314a9fa48ecae89f22
parent 2319b7aa
......@@ -26,6 +26,153 @@ static INLINE int plane_idx(int plane) {
plane == 1 ? 16 : 20;
}
static void quantize(int16_t *zbin_boost_orig_ptr,
int16_t *coeff_ptr, int n_coeffs, int skip_block,
int16_t *zbin_ptr, int16_t *round_ptr, int16_t *quant_ptr,
uint8_t *quant_shift_ptr,
int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr,
int16_t *dequant_ptr, int zbin_oq_value,
uint16_t *eob_ptr,
const int *scan, int mul) {
int i, rc, eob;
int zbins[2], nzbins[2], zbin;
int x, y, z, sz;
int zero_run = 0;
int16_t *zbin_boost_ptr = zbin_boost_orig_ptr;
int zero_flag = n_coeffs;
vpx_memset(qcoeff_ptr, 0, n_coeffs*sizeof(int16_t));
vpx_memset(dqcoeff_ptr, 0, n_coeffs*sizeof(int16_t));
eob = -1;
// Base ZBIN
zbins[0] = zbin_ptr[0] + zbin_oq_value;
zbins[1] = zbin_ptr[1] + zbin_oq_value;
nzbins[0] = zbins[0] * -1;
nzbins[1] = zbins[1] * -1;
if (!skip_block) {
// Pre-scan pass
for (i = n_coeffs - 1; i >= 0; i--) {
rc = scan[i];
z = coeff_ptr[rc] * mul;
if (z < zbins[rc != 0] && z > nzbins[rc != 0]) {
zero_flag--;
} else {
break;
}
}
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
for (i = 0; i < zero_flag; i++) {
rc = scan[i];
z = coeff_ptr[rc] * mul;
zbin = (zbins[rc != 0] + zbin_boost_ptr[zero_run]);
zero_run += (zero_run < 15);
sz = (z >> 31); // sign of z
x = (z ^ sz) - sz;
if (x >= zbin) {
x += (round_ptr[rc != 0]);
y = ((int)(((int)(x * quant_ptr[rc != 0]) >> 16) + x))
>> quant_shift_ptr[rc != 0]; // quantize (x)
x = (y ^ sz) - sz; // get the sign back
qcoeff_ptr[rc] = x; // write to destination
dqcoeff_ptr[rc] = x * dequant_ptr[rc != 0] / mul; // dequantized value
if (y) {
eob = i; // last nonzero coeffs
zero_run = 0; // set zero_run
}
}
}
}
*eob_ptr = eob + 1;
}
// This function works well for large transform size.
static void quantize_sparse(int16_t *zbin_boost_orig_ptr,
int16_t *coeff_ptr, int n_coeffs, int skip_block,
int16_t *zbin_ptr, int16_t *round_ptr,
int16_t *quant_ptr, uint8_t *quant_shift_ptr,
int16_t *qcoeff_ptr, int16_t *dqcoeff_ptr,
int16_t *dequant_ptr, int zbin_oq_value,
uint16_t *eob_ptr, const int *scan, int mul,
int *idx_arr) {
int i, rc, eob;
int zbins[2], pzbins[2], nzbins[2], zbin;
int x, y, z, sz;
int zero_run = 0;
int16_t *zbin_boost_ptr = zbin_boost_orig_ptr;
int idx = 0;
int pre_idx = 0;
vpx_memset(qcoeff_ptr, 0, n_coeffs*sizeof(int16_t));
vpx_memset(dqcoeff_ptr, 0, n_coeffs*sizeof(int16_t));
eob = -1;
// Base ZBIN
zbins[0] = zbin_ptr[0] + zbin_oq_value;
zbins[1] = zbin_ptr[1] + zbin_oq_value;
// Positive and negative ZBIN
pzbins[0] = zbins[0]/mul;
pzbins[1] = zbins[1]/mul;
nzbins[0] = pzbins[0] * -1;
nzbins[1] = pzbins[1] * -1;
if (!skip_block) {
// Pre-scan pass
for (i = 0; i < n_coeffs; i++) {
rc = scan[i];
z = coeff_ptr[rc];
// If the coefficient is out of the base ZBIN range, keep it for
// quantization.
if (z >= pzbins[rc != 0] || z <= nzbins[rc != 0])
idx_arr[idx++] = i;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
for (i = 0; i < idx; i++) {
rc = scan[idx_arr[i]];
// Calculate ZBIN
zero_run += idx_arr[i] - pre_idx;
if(zero_run > 15) zero_run = 15;
zbin = (zbins[rc != 0] + zbin_boost_ptr[zero_run]);
pre_idx = idx_arr[i];
z = coeff_ptr[rc] * mul;
sz = (z >> 31); // sign of z
x = (z ^ sz) - sz; // x = abs(z)
if (x >= zbin) {
x += (round_ptr[rc != 0]);
y = ((int)(((int)(x * quant_ptr[rc != 0]) >> 16) + x))
>> quant_shift_ptr[rc != 0]; // quantize (x)
x = (y ^ sz) - sz; // get the sign back
qcoeff_ptr[rc] = x; // write to destination
dqcoeff_ptr[rc] = x * dequant_ptr[rc != 0] / mul; // dequantized value
if (y) {
eob = idx_arr[i]; // last nonzero coeffs
zero_run = -1; // set zero_run
}
}
}
}
*eob_ptr = eob + 1;
}
#if 0
// Original quantize function
static void quantize(int16_t *zbin_boost_orig_ptr,
int16_t *coeff_ptr, int n_coeffs, int skip_block,
int16_t *zbin_ptr, int16_t *round_ptr, int16_t *quant_ptr,
......@@ -74,6 +221,7 @@ static void quantize(int16_t *zbin_boost_orig_ptr,
*eob_ptr = eob + 1;
}
#endif
void vp9_quantize(MACROBLOCK *mb, int plane, int block, int n_coeffs,
TX_TYPE tx_type) {
......@@ -97,19 +245,40 @@ void vp9_quantize(MACROBLOCK *mb, int plane, int block, int n_coeffs,
break;
}
quantize(mb->plane[plane].zrun_zbin_boost,
BLOCK_OFFSET(mb->plane[plane].coeff, block, 16),
n_coeffs, mb->skip_block,
mb->plane[plane].zbin,
mb->plane[plane].round,
mb->plane[plane].quant,
mb->plane[plane].quant_shift,
BLOCK_OFFSET(xd->plane[plane].qcoeff, block, 16),
BLOCK_OFFSET(xd->plane[plane].dqcoeff, block, 16),
xd->plane[plane].dequant,
mb->plane[plane].zbin_extra,
&xd->plane[plane].eobs[block],
scan, mul);
// Call different quantization for different transform size.
if (n_coeffs >= 1024) {
// Save index of picked coefficient in pre-scan pass.
int idx_arr[1024];
quantize_sparse(mb->plane[plane].zrun_zbin_boost,
BLOCK_OFFSET(mb->plane[plane].coeff, block, 16),
n_coeffs, mb->skip_block,
mb->plane[plane].zbin,
mb->plane[plane].round,
mb->plane[plane].quant,
mb->plane[plane].quant_shift,
BLOCK_OFFSET(xd->plane[plane].qcoeff, block, 16),
BLOCK_OFFSET(xd->plane[plane].dqcoeff, block, 16),
xd->plane[plane].dequant,
mb->plane[plane].zbin_extra,
&xd->plane[plane].eobs[block],
scan, mul, idx_arr);
}
else {
quantize(mb->plane[plane].zrun_zbin_boost,
BLOCK_OFFSET(mb->plane[plane].coeff, block, 16),
n_coeffs, mb->skip_block,
mb->plane[plane].zbin,
mb->plane[plane].round,
mb->plane[plane].quant,
mb->plane[plane].quant_shift,
BLOCK_OFFSET(xd->plane[plane].qcoeff, block, 16),
BLOCK_OFFSET(xd->plane[plane].dqcoeff, block, 16),
xd->plane[plane].dequant,
mb->plane[plane].zbin_extra,
&xd->plane[plane].eobs[block],
scan, mul);
}
}
void vp9_regular_quantize_b_4x4(MACROBLOCK *mb, int b_idx, TX_TYPE tx_type,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment