Files
vpx/vp9/decoder/vp9_detokenize.c
hui su bfc27bb614 tx-skip experiment: improve entropy coding of coeff tokens
This patch allows the prediction residues of tx-skipped blocks
to use probs that are different from regular transfrom
coefficients for token entropy coding. Prediction residues are
assumed as in band 6.

The initial value of probs is obtained with stats from limited
tests. The statistic model for constrained token nodes has not
been optimized. The probs for token extra bits have not been
optimized. These can be future work.

Certain coding improvment is observed:
derflr with all experiments:                +6.26%  (+0.10%)
screen_content with palette:               +22.48%  (+1.28%)

Change-Id: I1c0d78178ee9f3655febb6f30cdaef8ee9f8e3cc
2015-04-10 11:33:42 -07:00

269 lines
8.8 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 "vpx_mem/vpx_mem.h"
#include "vpx_ports/mem.h"
#include "vp9/common/vp9_blockd.h"
#include "vp9/common/vp9_common.h"
#include "vp9/common/vp9_entropy.h"
#include "vp9/decoder/vp9_detokenize.h"
#define EOB_CONTEXT_NODE 0
#define ZERO_CONTEXT_NODE 1
#define ONE_CONTEXT_NODE 2
#define LOW_VAL_CONTEXT_NODE 0
#define TWO_CONTEXT_NODE 1
#define THREE_CONTEXT_NODE 2
#define HIGH_LOW_CONTEXT_NODE 3
#define CAT_ONE_CONTEXT_NODE 4
#define CAT_THREEFOUR_CONTEXT_NODE 5
#define CAT_THREE_CONTEXT_NODE 6
#define CAT_FIVE_CONTEXT_NODE 7
#define INCREMENT_COUNT(token) \
do { \
if (!cm->frame_parallel_decoding_mode) \
++coef_counts[band][ctx][token]; \
} while (0)
static INLINE int read_coeff(const vp9_prob *probs, int n, vp9_reader *r) {
int i, val = 0;
for (i = 0; i < n; ++i)
val = (val << 1) | vp9_read(r, probs[i]);
return val;
}
static const vp9_tree_index coeff_subtree_high[TREE_SIZE(ENTROPY_TOKENS)] = {
2, 6, /* 0 = LOW_VAL */
-TWO_TOKEN, 4, /* 1 = TWO */
-THREE_TOKEN, -FOUR_TOKEN, /* 2 = THREE */
8, 10, /* 3 = HIGH_LOW */
-CATEGORY1_TOKEN, -CATEGORY2_TOKEN, /* 4 = CAT_ONE */
12, 14, /* 5 = CAT_THREEFOUR */
-CATEGORY3_TOKEN, -CATEGORY4_TOKEN, /* 6 = CAT_THREE */
-CATEGORY5_TOKEN, -CATEGORY6_TOKEN /* 7 = CAT_FIVE */
};
static int decode_coefs(VP9_COMMON *cm, const MACROBLOCKD *xd, PLANE_TYPE type,
tran_low_t *dqcoeff, TX_SIZE tx_size,
const int16_t *dq,
#if CONFIG_NEW_QUANT
const dequant_val_type_nuq *dq_val,
#endif // CONFIG_NEW_QUANT
int ctx, const int16_t *scan, const int16_t *nb,
vp9_reader *r) {
const int max_eob = 16 << (tx_size << 1);
const FRAME_CONTEXT *const fc = &cm->fc;
FRAME_COUNTS *const counts = &cm->counts;
const int ref = is_inter_block(&xd->mi[0].src_mi->mbmi);
int band, c = 0;
const vp9_prob (*coef_probs)[COEFF_CONTEXTS][UNCONSTRAINED_NODES] =
fc->coef_probs[tx_size][type][ref];
const vp9_prob *prob;
unsigned int (*coef_counts)[COEFF_CONTEXTS][UNCONSTRAINED_NODES + 1] =
counts->coef[tx_size][type][ref];
unsigned int (*eob_branch_count)[COEFF_CONTEXTS] =
counts->eob_branch[tx_size][type][ref];
uint8_t token_cache[MAX_NUM_COEFS];
const uint8_t *band_translate = get_band_translate(tx_size);
const int dq_shift = (tx_size > TX_16X16) ? tx_size - TX_16X16 : 0;
int v, token;
int16_t dqv = dq[0];
#if CONFIG_NEW_QUANT
#if CONFIG_TX_SKIP
const int use_rect_quant = is_rect_quant_used(&xd->mi[0].src_mi->mbmi, type);
#endif
const tran_low_t *dqv_val = &dq_val[0][0];
#endif // CONFIG_NEW_QUANT
const uint8_t *cat1_prob;
const uint8_t *cat2_prob;
const uint8_t *cat3_prob;
const uint8_t *cat4_prob;
const uint8_t *cat5_prob;
const uint8_t *cat6_prob;
#if CONFIG_VP9_HIGHBITDEPTH
if (cm->use_highbitdepth) {
if (cm->bit_depth == VPX_BITS_10) {
cat1_prob = vp9_cat1_prob_high10;
cat2_prob = vp9_cat2_prob_high10;
cat3_prob = vp9_cat3_prob_high10;
cat4_prob = vp9_cat4_prob_high10;
cat5_prob = vp9_cat5_prob_high10;
cat6_prob = vp9_cat6_prob_high10;
} else {
cat1_prob = vp9_cat1_prob_high12;
cat2_prob = vp9_cat2_prob_high12;
cat3_prob = vp9_cat3_prob_high12;
cat4_prob = vp9_cat4_prob_high12;
cat5_prob = vp9_cat5_prob_high12;
cat6_prob = vp9_cat6_prob_high12;
}
} else {
cat1_prob = vp9_cat1_prob;
cat2_prob = vp9_cat2_prob;
cat3_prob = vp9_cat3_prob;
cat4_prob = vp9_cat4_prob;
cat5_prob = vp9_cat5_prob;
cat6_prob = vp9_cat6_prob;
}
#else
cat1_prob = vp9_cat1_prob;
cat2_prob = vp9_cat2_prob;
cat3_prob = vp9_cat3_prob;
cat4_prob = vp9_cat4_prob;
cat5_prob = vp9_cat5_prob;
cat6_prob = vp9_cat6_prob;
#endif
#if CONFIG_TX_SKIP
if (xd->mi[0].src_mi->mbmi.tx_skip[type])
band_translate = vp9_coefband_tx_skip;
#endif // CONFIG_TX_SKIP
while (c < max_eob) {
int val = -1;
band = *band_translate++;
prob = coef_probs[band][ctx];
if (!cm->frame_parallel_decoding_mode)
++eob_branch_count[band][ctx];
if (!vp9_read(r, prob[EOB_CONTEXT_NODE])) {
INCREMENT_COUNT(EOB_MODEL_TOKEN);
break;
}
#if CONFIG_NEW_QUANT
dqv_val = &dq_val[band][0];
#endif // CONFIG_NEW_QUANT
while (!vp9_read(r, prob[ZERO_CONTEXT_NODE])) {
INCREMENT_COUNT(ZERO_TOKEN);
dqv = dq[1];
token_cache[scan[c]] = 0;
++c;
if (c >= max_eob)
return c; // zero tokens at the end (no eob token)
ctx = get_coef_context(nb, token_cache, c);
band = *band_translate++;
prob = coef_probs[band][ctx];
#if CONFIG_NEW_QUANT
dqv_val = &dq_val[band][0];
#endif // CONFIG_NEW_QUANT
}
if (!vp9_read(r, prob[ONE_CONTEXT_NODE])) {
INCREMENT_COUNT(ONE_TOKEN);
token = ONE_TOKEN;
val = 1;
} else {
INCREMENT_COUNT(TWO_TOKEN);
token = vp9_read_tree(r, coeff_subtree_high,
vp9_pareto8_full[prob[PIVOT_NODE] - 1]);
switch (token) {
case TWO_TOKEN:
case THREE_TOKEN:
case FOUR_TOKEN:
val = token;
break;
case CATEGORY1_TOKEN:
val = CAT1_MIN_VAL + read_coeff(cat1_prob, 1, r);
break;
case CATEGORY2_TOKEN:
val = CAT2_MIN_VAL + read_coeff(cat2_prob, 2, r);
break;
case CATEGORY3_TOKEN:
val = CAT3_MIN_VAL + read_coeff(cat3_prob, 3, r);
break;
case CATEGORY4_TOKEN:
val = CAT4_MIN_VAL + read_coeff(cat4_prob, 4, r);
break;
case CATEGORY5_TOKEN:
val = CAT5_MIN_VAL + read_coeff(cat5_prob, 5, r);
break;
case CATEGORY6_TOKEN:
#if CONFIG_VP9_HIGHBITDEPTH
switch (cm->bit_depth) {
case VPX_BITS_8:
val = CAT6_MIN_VAL + read_coeff(cat6_prob, NUM_CAT6_BITS, r);
break;
case VPX_BITS_10:
val = CAT6_MIN_VAL +
read_coeff(cat6_prob, NUM_CAT6_BITS_HIGH10, r);
break;
case VPX_BITS_12:
val = CAT6_MIN_VAL +
read_coeff(cat6_prob, NUM_CAT6_BITS_HIGH12, r);
break;
default:
assert(0);
return -1;
}
#else
val = CAT6_MIN_VAL + read_coeff(cat6_prob, NUM_CAT6_BITS, r);
#endif
break;
}
}
#if CONFIG_NEW_QUANT
#if CONFIG_TX_SKIP
if (use_rect_quant) {
v = (val * dqv) >> dq_shift;
} else {
v = vp9_dequant_abscoeff_nuq(val, dqv, dqv_val);
v = dq_shift ? ROUND_POWER_OF_TWO(v, dq_shift) : v;
}
#else
v = vp9_dequant_abscoeff_nuq(val, dqv, dqv_val);
v = dq_shift ? ROUND_POWER_OF_TWO(v, dq_shift) : v;
#endif // CONFIG_TX_SKIP
#else // CONFIG_NEW_QUANT
v = (val * dqv) >> dq_shift;
#endif // CONFIG_NEW_QUANT
#if CONFIG_COEFFICIENT_RANGE_CHECKING
dqcoeff[scan[c]] = check_range(vp9_read_bit(r) ? -v : v);
#else
dqcoeff[scan[c]] = vp9_read_bit(r) ? -v : v;
#endif
token_cache[scan[c]] = vp9_pt_energy_class[token];
++c;
ctx = get_coef_context(nb, token_cache, c);
dqv = dq[1];
}
return c;
}
int vp9_decode_block_tokens(VP9_COMMON *cm, MACROBLOCKD *xd,
int plane, int block, BLOCK_SIZE plane_bsize,
int x, int y, TX_SIZE tx_size, vp9_reader *r) {
struct macroblockd_plane *const pd = &xd->plane[plane];
const int ctx = get_entropy_context(tx_size, pd->above_context + x,
pd->left_context + y);
const scan_order *so = get_scan(xd, tx_size, pd->plane_type, block);
int eob;
eob = decode_coefs(cm, xd, pd->plane_type,
BLOCK_OFFSET(pd->dqcoeff, block), tx_size,
pd->dequant,
#if CONFIG_NEW_QUANT
pd->dequant_val_nuq,
#endif // CONFIG_NEW_QUANT
ctx, so->scan,
so->neighbors, r);
#if CONFIG_TX64X64
if (plane > 0) assert(tx_size != TX_64X64);
#endif // CONFIG_TX64X64
vp9_set_contexts(xd, pd, plane_bsize, tx_size, eob > 0, x, y);
return eob;
}