vpx/vp9/encoder/vp9_quantize.c
Guillaume Martres acf0d56f0b Get rid of "this_mi", use "mi_8x8[0]" everywhere instead
The only case where they were intentionally pointing to different
structures was in mbgraph, and this didn't have the expected behavior
because both of these pointers are used interchangeably through the code

Change-Id: I979251782f90885fe962305bcc845bc05907f80c
2013-10-16 16:24:03 -07:00

366 lines
12 KiB
C

/*
* Copyright (c) 2010 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <math.h>
#include "vpx_mem/vpx_mem.h"
#include "vp9/encoder/vp9_onyx_int.h"
#include "vp9/encoder/vp9_rdopt.h"
#include "vp9/encoder/vp9_quantize.h"
#include "vp9/common/vp9_quant_common.h"
#include "vp9/common/vp9_seg_common.h"
#ifdef ENC_DEBUG
extern int enc_debug;
#endif
void vp9_quantize_b_c(int16_t *coeff_ptr, intptr_t n_coeffs, int skip_block,
int16_t *zbin_ptr, int16_t *round_ptr, int16_t *quant_ptr,
int16_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 int16_t *scan,
const int16_t *iscan) {
int i, rc, eob;
int zbins[2], nzbins[2], zbin;
int x, y, z, sz;
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];
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];
zbin = (zbins[rc != 0]);
sz = (z >> 31); // sign of z
x = (z ^ sz) - sz;
if (x >= zbin) {
x += (round_ptr[rc != 0]);
x = clamp(x, INT16_MIN, INT16_MAX);
y = (((int)(((int)(x * quant_ptr[rc != 0]) >> 16) + x)) *
quant_shift_ptr[rc != 0]) >> 16; // 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]; // dequantized value
if (y) {
eob = i; // last nonzero coeffs
}
}
}
}
*eob_ptr = eob + 1;
}
void vp9_quantize_b_32x32_c(int16_t *coeff_ptr, intptr_t n_coeffs,
int skip_block,
int16_t *zbin_ptr, int16_t *round_ptr,
int16_t *quant_ptr, int16_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 int16_t *scan,
const int16_t *iscan) {
int i, rc, eob;
int zbins[2], nzbins[2];
int x, y, z, sz;
int idx = 0;
int idx_arr[1024];
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] = ROUND_POWER_OF_TWO(zbin_ptr[0] + zbin_oq_value, 1);
zbins[1] = ROUND_POWER_OF_TWO(zbin_ptr[1] + zbin_oq_value, 1);
nzbins[0] = zbins[0] * -1;
nzbins[1] = zbins[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 >= zbins[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]];
z = coeff_ptr[rc];
sz = (z >> 31); // sign of z
x = (z ^ sz) - sz; // x = abs(z)
x += ROUND_POWER_OF_TWO(round_ptr[rc != 0], 1);
x = clamp(x, INT16_MIN, INT16_MAX);
y = ((((x * quant_ptr[rc != 0]) >> 16) + x) *
quant_shift_ptr[rc != 0]) >> 15; // 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] / 2; // dequantized value
if (y)
eob = idx_arr[i]; // last nonzero coeffs
}
}
*eob_ptr = eob + 1;
}
struct plane_block_idx {
int plane;
int block;
};
// TODO(jkoleszar): returning a struct so it can be used in a const context,
// expect to refactor this further later.
static INLINE struct plane_block_idx plane_block_idx(int y_blocks,
int b_idx) {
const int v_offset = y_blocks * 5 / 4;
struct plane_block_idx res;
if (b_idx < y_blocks) {
res.plane = 0;
res.block = b_idx;
} else if (b_idx < v_offset) {
res.plane = 1;
res.block = b_idx - y_blocks;
} else {
assert(b_idx < y_blocks * 3 / 2);
res.plane = 2;
res.block = b_idx - v_offset;
}
return res;
}
void vp9_regular_quantize_b_4x4(MACROBLOCK *mb, int b_idx, TX_TYPE tx_type,
int y_blocks) {
MACROBLOCKD *const xd = &mb->e_mbd;
const struct plane_block_idx pb_idx = plane_block_idx(y_blocks, b_idx);
const int16_t *scan = get_scan_4x4(tx_type);
const int16_t *iscan = get_iscan_4x4(tx_type);
vp9_quantize_b(BLOCK_OFFSET(mb->plane[pb_idx.plane].coeff, pb_idx.block),
16, mb->skip_block,
mb->plane[pb_idx.plane].zbin,
mb->plane[pb_idx.plane].round,
mb->plane[pb_idx.plane].quant,
mb->plane[pb_idx.plane].quant_shift,
BLOCK_OFFSET(xd->plane[pb_idx.plane].qcoeff, pb_idx.block),
BLOCK_OFFSET(xd->plane[pb_idx.plane].dqcoeff, pb_idx.block),
xd->plane[pb_idx.plane].dequant,
mb->plane[pb_idx.plane].zbin_extra,
&xd->plane[pb_idx.plane].eobs[pb_idx.block],
scan, iscan);
}
static void invert_quant(int16_t *quant, int16_t *shift, int d) {
unsigned t;
int l;
t = d;
for (l = 0; t > 1; l++)
t >>= 1;
t = 1 + (1 << (16 + l)) / d;
*quant = (int16_t)(t - (1 << 16));
*shift = 1 << (16 - l);
}
void vp9_init_quantizer(VP9_COMP *cpi) {
int i, q;
VP9_COMMON *const cm = &cpi->common;
for (q = 0; q < QINDEX_RANGE; q++) {
const int qzbin_factor = q == 0 ? 64 : (vp9_dc_quant(q, 0) < 148 ? 84 : 80);
const int qrounding_factor = q == 0 ? 64 : 48;
// y
for (i = 0; i < 2; ++i) {
const int quant = i == 0 ? vp9_dc_quant(q, cm->y_dc_delta_q)
: vp9_ac_quant(q, 0);
invert_quant(&cpi->y_quant[q][i], &cpi->y_quant_shift[q][i], quant);
cpi->y_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
cpi->y_round[q][i] = (qrounding_factor * quant) >> 7;
cm->y_dequant[q][i] = quant;
}
// uv
for (i = 0; i < 2; ++i) {
const int quant = i == 0 ? vp9_dc_quant(q, cm->uv_dc_delta_q)
: vp9_ac_quant(q, cm->uv_ac_delta_q);
invert_quant(&cpi->uv_quant[q][i], &cpi->uv_quant_shift[q][i], quant);
cpi->uv_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
cpi->uv_round[q][i] = (qrounding_factor * quant) >> 7;
cm->uv_dequant[q][i] = quant;
}
#if CONFIG_ALPHA
// alpha
for (i = 0; i < 2; ++i) {
const int quant = i == 0 ? vp9_dc_quant(q, cm->a_dc_delta_q)
: vp9_ac_quant(q, cm->a_ac_delta_q);
invert_quant(&cpi->a_quant[q][i], &cpi->a_quant_shift[q][i], quant);
cpi->a_zbin[q][i] = ROUND_POWER_OF_TWO(qzbin_factor * quant, 7);
cpi->a_round[q][i] = (qrounding_factor * quant) >> 7;
cm->a_dequant[q][i] = quant;
}
#endif
for (i = 2; i < 8; i++) {
cpi->y_quant[q][i] = cpi->y_quant[q][1];
cpi->y_quant_shift[q][i] = cpi->y_quant_shift[q][1];
cpi->y_zbin[q][i] = cpi->y_zbin[q][1];
cpi->y_round[q][i] = cpi->y_round[q][1];
cm->y_dequant[q][i] = cm->y_dequant[q][1];
cpi->uv_quant[q][i] = cpi->uv_quant[q][1];
cpi->uv_quant_shift[q][i] = cpi->uv_quant_shift[q][1];
cpi->uv_zbin[q][i] = cpi->uv_zbin[q][1];
cpi->uv_round[q][i] = cpi->uv_round[q][1];
cm->uv_dequant[q][i] = cm->uv_dequant[q][1];
#if CONFIG_ALPHA
cpi->a_quant[q][i] = cpi->a_quant[q][1];
cpi->a_quant_shift[q][i] = cpi->a_quant_shift[q][1];
cpi->a_zbin[q][i] = cpi->a_zbin[q][1];
cpi->a_round[q][i] = cpi->a_round[q][1];
cm->a_dequant[q][i] = cm->a_dequant[q][1];
#endif
}
}
}
void vp9_mb_init_quantizer(VP9_COMP *cpi, MACROBLOCK *x) {
int i;
VP9_COMMON *const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
int zbin_extra;
int segment_id = xd->mi_8x8[0]->mbmi.segment_id;
const int qindex = vp9_get_qindex(&cpi->common.seg, segment_id,
cpi->common.base_qindex);
int rdmult = vp9_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q);
// Y
zbin_extra = (cpi->common.y_dequant[qindex][1] *
(cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
x->plane[0].quant = cpi->y_quant[qindex];
x->plane[0].quant_shift = cpi->y_quant_shift[qindex];
x->plane[0].zbin = cpi->y_zbin[qindex];
x->plane[0].round = cpi->y_round[qindex];
x->plane[0].zbin_extra = (int16_t)zbin_extra;
x->e_mbd.plane[0].dequant = cpi->common.y_dequant[qindex];
// UV
zbin_extra = (cpi->common.uv_dequant[qindex][1] *
(cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
for (i = 1; i < 3; i++) {
x->plane[i].quant = cpi->uv_quant[qindex];
x->plane[i].quant_shift = cpi->uv_quant_shift[qindex];
x->plane[i].zbin = cpi->uv_zbin[qindex];
x->plane[i].round = cpi->uv_round[qindex];
x->plane[i].zbin_extra = (int16_t)zbin_extra;
x->e_mbd.plane[i].dequant = cpi->common.uv_dequant[qindex];
}
#if CONFIG_ALPHA
x->plane[3].quant = cpi->a_quant[qindex];
x->plane[3].quant_shift = cpi->a_quant_shift[qindex];
x->plane[3].zbin = cpi->a_zbin[qindex];
x->plane[3].round = cpi->a_round[qindex];
x->plane[3].zbin_extra = (int16_t)zbin_extra;
x->e_mbd.plane[3].dequant = cpi->common.a_dequant[qindex];
#endif
x->skip_block = vp9_segfeature_active(&cpi->common.seg, segment_id,
SEG_LVL_SKIP);
/* save this macroblock QIndex for vp9_update_zbin_extra() */
x->e_mbd.q_index = qindex;
/* R/D setup */
cpi->mb.errorperbit = rdmult >> 6;
cpi->mb.errorperbit += (cpi->mb.errorperbit == 0);
vp9_initialize_me_consts(cpi, xd->q_index);
}
void vp9_update_zbin_extra(VP9_COMP *cpi, MACROBLOCK *x) {
const int qindex = x->e_mbd.q_index;
const int y_zbin_extra = (cpi->common.y_dequant[qindex][1] *
(cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
const int uv_zbin_extra = (cpi->common.uv_dequant[qindex][1] *
(cpi->zbin_mode_boost + x->act_zbin_adj)) >> 7;
x->plane[0].zbin_extra = (int16_t)y_zbin_extra;
x->plane[1].zbin_extra = (int16_t)uv_zbin_extra;
x->plane[2].zbin_extra = (int16_t)uv_zbin_extra;
}
void vp9_frame_init_quantizer(VP9_COMP *cpi) {
// Clear Zbin mode boost for default case
cpi->zbin_mode_boost = 0;
// MB level quantizer setup
vp9_mb_init_quantizer(cpi, &cpi->mb);
}
void vp9_set_quantizer(struct VP9_COMP *cpi, int q) {
VP9_COMMON *cm = &cpi->common;
cm->base_qindex = q;
// if any of the delta_q values are changing update flag will
// have to be set.
cm->y_dc_delta_q = 0;
cm->uv_dc_delta_q = 0;
cm->uv_ac_delta_q = 0;
// quantizer has to be reinitialized if any delta_q changes.
// As there are not any here for now this is inactive code.
// if(update)
// vp9_init_quantizer(cpi);
}