diff --git a/configure b/configure index 5d2910ba7..147901926 100755 --- a/configure +++ b/configure @@ -251,6 +251,7 @@ EXPERIMENT_LIST=" oneshotq sbsegment multiple_arf + code_zerogroup " CONFIG_LIST=" external_build diff --git a/vp9/common/vp9_blockd.h b/vp9/common/vp9_blockd.h index aa48958b0..b1915d18a 100644 --- a/vp9/common/vp9_blockd.h +++ b/vp9/common/vp9_blockd.h @@ -767,7 +767,7 @@ struct plane_block_idx { // 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) { + int b_idx) { const int v_offset = y_blocks * 5 / 4; struct plane_block_idx res; @@ -939,6 +939,9 @@ static INLINE void foreach_predicted_block_uv( } } - - +#if CONFIG_CODE_ZEROGROUP +static int get_zpc_used(TX_SIZE tx_size) { + return (tx_size >= TX_16X16); +} +#endif #endif // VP9_COMMON_VP9_BLOCKD_H_ diff --git a/vp9/common/vp9_coefupdateprobs.h b/vp9/common/vp9_coefupdateprobs.h index b4d892df9..a13f9b290 100644 --- a/vp9/common/vp9_coefupdateprobs.h +++ b/vp9/common/vp9_coefupdateprobs.h @@ -26,6 +26,10 @@ static const vp9_prob vp9_coef_update_prob[ENTROPY_NODES] = { #define NZC_UPDATE_PROB_PCAT 252 #endif +#if CONFIG_CODE_ZEROGROUP +#define ZPC_UPDATE_PROB 248 +#endif + #if CONFIG_MODELCOEFPROB #define COEF_MODEL_UPDATE_PROB 16 #endif diff --git a/vp9/common/vp9_default_coef_probs.h b/vp9/common/vp9_default_coef_probs.h index 5a781fb0a..9e105bd5c 100644 --- a/vp9/common/vp9_default_coef_probs.h +++ b/vp9/common/vp9_default_coef_probs.h @@ -995,3 +995,86 @@ static const vp9_prob default_nzc_pcat_probs[MAX_NZC_CONTEXTS] }; #endif // CONFIG_CODE_NONZEROCOUNT + +#if CONFIG_CODE_ZEROGROUP + +// There are two probs: the first is the prob(0) of the isolated zero bit, +// the second is the prob(0) of the end of orientation symbol [if 0 that +// indicates a zerotree root]. +static const vp9_zpc_probs default_zpc_probs_4x4 = { + { /* Intra */ + { /* Coeff Band 0 */ + { 1, }, { 1, }, { 1, }, + }, { /* Coeff Band 1 */ + { 1, }, { 1, }, { 1, }, + }, { /* Coeff Band 2 */ + { 1, }, { 1, }, { 1, }, + } + }, { /* Inter */ + { /* Coeff Band 0 */ + { 1, }, { 1, }, { 1, }, + }, { /* Coeff Band 1 */ + { 1, }, { 1, }, { 1, }, + }, { /* Coeff Band 2 */ + { 1, }, { 1, }, { 1, }, + } + } +}; +static const vp9_zpc_probs default_zpc_probs_8x8 = { + { /* Intra */ + { /* ZPC Band 0 */ + { 4, }, { 2, }, { 1, }, + }, { /* ZPC Band 1 */ + { 4, }, { 2, }, { 1, }, + }, { /* ZPC Band 2 */ + { 4, }, { 2, }, { 1, }, + } + }, { /* Inter */ + { /* ZPC Band 0 */ + { 4, }, { 2, }, { 1, }, + }, { /* ZPC Band 1 */ + { 4, }, { 2, }, { 1, }, + }, { /* ZPC Band 2 */ + { 4, }, { 2, }, { 1, }, + } + } +}; +static const vp9_zpc_probs default_zpc_probs_16x16 = { + { /* Intra */ + { /* ZPC Band 0 */ + { 57, }, { 30, }, { 13, }, + }, { /* ZPC Band 1 */ + { 46, }, { 23, }, { 4, }, + }, { /* ZPC Band 1 */ + { 36, }, { 11, }, { 2, }, + }, + }, { /* Inter */ + { /* ZPC Band 0 */ + { 45, }, { 21 }, { 10, }, + }, { /* ZPC Band 1 */ + { 24, }, { 14, }, { 3, }, + }, { /* ZPC Band 2 */ + { 16, }, { 6, }, { 1, }, + }, + }, +}; +static const vp9_zpc_probs default_zpc_probs_32x32 = { + { /* Intra */ + { /* ZPC Band 0 */ + { 132, }, { 60, }, { 19, }, + }, { /* ZPC Band 1 */ + { 64, }, { 32, }, { 8, }, + }, { /* ZPC Band 2 */ + { 25, }, { 11, }, { 1, }, + }, + }, { /* Inter */ + { /* ZPC Band 0 */ + { 134, }, { 39, }, { 25, }, + }, { /* ZPC Band 1 */ + { 64, }, { 24, }, { 12, }, + }, { /* ZPC Band 2 */ + { 21, }, { 10, }, { 1, }, + }, + }, +}; +#endif // CONFIG_CODE_ZEROGROUP diff --git a/vp9/common/vp9_entropy.c b/vp9/common/vp9_entropy.c index 5b3ddfbc2..cfd6a3cd1 100644 --- a/vp9/common/vp9_entropy.c +++ b/vp9/common/vp9_entropy.c @@ -1344,10 +1344,10 @@ int vp9_get_coef_context(const int *scan, const int *neighbors, int ctx; assert(neighbors[MAX_NEIGHBORS * c + 0] >= 0); if (neighbors[MAX_NEIGHBORS * c + 1] >= 0) { - ctx = (1 + token_cache[neighbors[MAX_NEIGHBORS * c + 0]] + - token_cache[neighbors[MAX_NEIGHBORS * c + 1]]) >> 1; + ctx = (1 + token_cache[scan[neighbors[MAX_NEIGHBORS * c + 0]]] + + token_cache[scan[neighbors[MAX_NEIGHBORS * c + 1]]]) >> 1; } else { - ctx = token_cache[neighbors[MAX_NEIGHBORS * c + 0]]; + ctx = token_cache[scan[neighbors[MAX_NEIGHBORS * c + 0]]]; } return vp9_pt_energy_class[ctx]; } @@ -1447,6 +1447,16 @@ void vp9_default_coef_probs(VP9_COMMON *pc) { vpx_memcpy(pc->fc.coef_probs_32x32, default_coef_probs_32x32, sizeof(pc->fc.coef_probs_32x32)); #endif +#if CONFIG_CODE_ZEROGROUP + vpx_memcpy(pc->fc.zpc_probs_4x4, default_zpc_probs_4x4, + sizeof(pc->fc.zpc_probs_4x4)); + vpx_memcpy(pc->fc.zpc_probs_8x8, default_zpc_probs_8x8, + sizeof(pc->fc.zpc_probs_8x8)); + vpx_memcpy(pc->fc.zpc_probs_16x16, default_zpc_probs_16x16, + sizeof(pc->fc.zpc_probs_16x16)); + vpx_memcpy(pc->fc.zpc_probs_32x32, default_zpc_probs_32x32, + sizeof(pc->fc.zpc_probs_32x32)); +#endif } // Neighborhood 5-tuples for various scans and blocksizes, @@ -2901,3 +2911,140 @@ void vp9_adapt_nzc_probs(VP9_COMMON *cm) { adapt_nzc_pcat(cm, count_sat, update_factor); } #endif // CONFIG_CODE_NONZEROCOUNT + +#if CONFIG_CODE_ZEROGROUP +OrientationType vp9_get_orientation(int rc, TX_SIZE tx_size) { + int i = rc >> (tx_size + 2); + int j = rc & ((4 << tx_size) - 1); + if (i > 2 * j) + return VERTICAL; + else if (j > 2 * i) + return HORIZONTAL; + else + return DIAGONAL; + /* + if (i == 0 && j == 0) return DIAGONAL; + while (i > 1 || j > 1) { + i >>= 1; + j >>= 1; + } + if (i == 0 && j == 1) + return HORIZONTAL; // horizontal + else if (i == 1 && j == 1) + return DIAGONAL; // diagonal + else if (i == 1 && j == 0) + return VERTICAL; // vertical + assert(0); + */ +} + +int vp9_use_eoo(int c, int seg_eob, const int *scan, + TX_SIZE tx_size, int *is_last_zero, int *is_eoo) { + // NOTE: returning 0 from this function will turn off eoo symbols + // For instance we can experiment with turning eoo off for smaller blocks + // and/or lower bands + int o = vp9_get_orientation(scan[c], tx_size); + int band = get_coef_band(scan, tx_size, c); + int use_eoo = (!is_last_zero[o] && + !is_eoo[o] && + band <= ZPC_EOO_BAND_UPPER && + band >= ZPC_EOO_BAND_LOWER && + get_zpc_used(tx_size) && + seg_eob - c > (ZPC_USEEOO_THRESH << tx_size) && + is_eoo[0] + is_eoo[1] + is_eoo[2] < 2); + return use_eoo; +} + +int vp9_is_eoo(int c, int eob, const int *scan, TX_SIZE tx_size, + const int16_t *qcoeff_ptr, int *last_nz_pos) { + int rc = scan[c]; + int o = vp9_get_orientation(rc, tx_size); + int eoo = c > last_nz_pos[o]; + return eoo; +} + +static void adapt_zpc_probs_common(VP9_COMMON *cm, + TX_SIZE tx_size, + int count_sat, + int update_factor) { + int r, b, p, n; + int count, factor; + vp9_zpc_probs *zpc_probs; + vp9_zpc_probs *pre_zpc_probs; + vp9_zpc_count *zpc_counts; + if (!get_zpc_used(tx_size)) return; + if (tx_size == TX_32X32) { + zpc_probs = &cm->fc.zpc_probs_32x32; + pre_zpc_probs = &cm->fc.pre_zpc_probs_32x32; + zpc_counts = &cm->fc.zpc_counts_32x32; + } else if (tx_size == TX_16X16) { + zpc_probs = &cm->fc.zpc_probs_16x16; + pre_zpc_probs = &cm->fc.pre_zpc_probs_16x16; + zpc_counts = &cm->fc.zpc_counts_16x16; + } else if (tx_size == TX_8X8) { + zpc_probs = &cm->fc.zpc_probs_8x8; + pre_zpc_probs = &cm->fc.pre_zpc_probs_8x8; + zpc_counts = &cm->fc.zpc_counts_8x8; + } else { + zpc_probs = &cm->fc.zpc_probs_4x4; + pre_zpc_probs = &cm->fc.pre_zpc_probs_4x4; + zpc_counts = &cm->fc.zpc_counts_4x4; + } + for (r = 0; r < REF_TYPES; ++r) { + for (b = 0; b < ZPC_BANDS; ++b) { + for (p = 0; p < ZPC_PTOKS; ++p) { + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob prob = get_binary_prob((*zpc_counts)[r][b][p][n][0], + (*zpc_counts)[r][b][p][n][1]); + count = (*zpc_counts)[r][b][p][n][0] + (*zpc_counts)[r][b][p][n][1]; + count = count > count_sat ? count_sat : count; + factor = (update_factor * count / count_sat); + (*zpc_probs)[r][b][p][n] = weighted_prob( + (*pre_zpc_probs)[r][b][p][n], prob, factor); + } + } + } + } +} + +// #define ZPC_COUNT_TESTING +void vp9_adapt_zpc_probs(VP9_COMMON *cm) { + int count_sat; + int update_factor; /* denominator 256 */ +#ifdef NZC_COUNT_TESTING + int r, b, p, n; + printf("\n"); + for (r = 0; r < REF_TYPES; ++r) { + printf("{"); + for (b = 0; b < ZPC_BANDS; ++b) { + printf(" {"); + for (p = 0; p < ZPC_PTOKS; ++p) { + printf(" {"); + for (n = 0; n < ZPC_NODES; ++n) { + printf(" %d,", cm->fc.zpc_counts_16x16[r][b][p][n]); + } + printf("},\n"); + } + printf(" },\n"); + } + printf("},\n"); + } +#endif + + if (cm->frame_type == KEY_FRAME) { + update_factor = COEF_MAX_UPDATE_FACTOR_KEY; + count_sat = COEF_COUNT_SAT_KEY; + } else if (cm->last_frame_type == KEY_FRAME) { + update_factor = COEF_MAX_UPDATE_FACTOR_AFTER_KEY; /* adapt quickly */ + count_sat = COEF_COUNT_SAT_AFTER_KEY; + } else { + update_factor = COEF_MAX_UPDATE_FACTOR; + count_sat = COEF_COUNT_SAT; + } + + adapt_zpc_probs_common(cm, TX_4X4, count_sat, update_factor); + adapt_zpc_probs_common(cm, TX_8X8, count_sat, update_factor); + adapt_zpc_probs_common(cm, TX_16X16, count_sat, update_factor); + adapt_zpc_probs_common(cm, TX_32X32, count_sat, update_factor); +} +#endif // CONFIG_CODE_ZEROGROUP diff --git a/vp9/common/vp9_entropy.h b/vp9/common/vp9_entropy.h index 3cae94649..6b24ffc94 100644 --- a/vp9/common/vp9_entropy.h +++ b/vp9/common/vp9_entropy.h @@ -250,6 +250,62 @@ extern const int vp9_basenzcvalue[NZC32X32_TOKENS]; #endif // CONFIG_CODE_NONZEROCOUNT +#if CONFIG_CODE_ZEROGROUP + +#define ZPC_STATS + +typedef enum { + HORIZONTAL = 0, + DIAGONAL, + VERTICAL, +} OrientationType; + +/* Note EOB should become part of this symbol eventually, + * but holding off on this for now because that is a major + * change in the rest of the codebase */ + +#define ZPC_ISOLATED (MAX_ENTROPY_TOKENS + 0) /* Isolated zero */ + +/* ZPC_EOORIENT: All remaining coefficients in the same orientation are 0. + * In other words all remaining coeffs in the current subband, and all + * children of the current subband are zero. Subbands are defined by + * dyadic partitioning in the coeff domain */ +#define ZPC_EOORIENT (MAX_ENTROPY_TOKENS + 1) /* End of Orientation */ + +/* Band limits over which the eoo bit is sent */ +#define ZPC_EOO_BAND_LOWER 0 +#define ZPC_EOO_BAND_UPPER 5 + +#define USE_ZPC_EOORIENT 1 /* 0: not used */ + /* 1: used */ +#define ZPC_NODES 1 + +#define UNKNOWN_TOKEN 255 /* Not signalled, encoder only */ + +#define ZPC_BANDS 3 /* context bands for izr */ +#define ZPC_PTOKS 3 /* context pt for zpcs */ + +#define coef_to_zpc_band(b) ((b) >> 1) +#define coef_to_zpc_ptok(p) ((p) > 2 ? 2 : (p)) + +typedef vp9_prob vp9_zpc_probs[REF_TYPES][ZPC_BANDS] + [ZPC_PTOKS][ZPC_NODES]; +typedef unsigned int vp9_zpc_count[REF_TYPES][ZPC_BANDS] + [ZPC_PTOKS][ZPC_NODES][2]; + +OrientationType vp9_get_orientation(int rc, TX_SIZE tx_size); +int vp9_use_eoo(int c, int eob, const int *scan, TX_SIZE tx_size, + int *is_last_zero, int *is_eoo); +int vp9_is_eoo(int c, int eob, const int *scan, TX_SIZE tx_size, + const int16_t *qcoeff_ptr, int *last_nz_pos); + +#define ZPC_USEEOO_THRESH 4 +#define ZPC_ZEROSSAVED_EOO 7 /* encoder only */ + +void vp9_adapt_zpc_probs(struct VP9Common *cm); + +#endif // CONFIG_CODE_ZEROGROUP + #include "vp9/common/vp9_coefupdateprobs.h" #endif // VP9_COMMON_VP9_ENTROPY_H_ diff --git a/vp9/common/vp9_onyxc_int.h b/vp9/common/vp9_onyxc_int.h index 13ec8657f..eb2a2c682 100644 --- a/vp9/common/vp9_onyxc_int.h +++ b/vp9/common/vp9_onyxc_int.h @@ -86,6 +86,12 @@ typedef struct frame_contexts { vp9_prob nzc_pcat_probs[MAX_NZC_CONTEXTS] [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA]; #endif +#if CONFIG_CODE_ZEROGROUP + vp9_zpc_probs zpc_probs_4x4; + vp9_zpc_probs zpc_probs_8x8; + vp9_zpc_probs zpc_probs_16x16; + vp9_zpc_probs zpc_probs_32x32; +#endif nmv_context nmvc; nmv_context pre_nmvc; @@ -122,6 +128,12 @@ typedef struct frame_contexts { vp9_prob pre_nzc_pcat_probs[MAX_NZC_CONTEXTS] [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA]; #endif +#if CONFIG_CODE_ZEROGROUP + vp9_zpc_probs pre_zpc_probs_4x4; + vp9_zpc_probs pre_zpc_probs_8x8; + vp9_zpc_probs pre_zpc_probs_16x16; + vp9_zpc_probs pre_zpc_probs_32x32; +#endif vp9_coeff_count coef_counts_4x4[BLOCK_TYPES]; vp9_coeff_count coef_counts_8x8[BLOCK_TYPES]; @@ -142,6 +154,12 @@ typedef struct frame_contexts { unsigned int nzc_pcat_counts[MAX_NZC_CONTEXTS] [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA][2]; #endif +#if CONFIG_CODE_ZEROGROUP + vp9_zpc_count zpc_counts_4x4; + vp9_zpc_count zpc_counts_8x8; + vp9_zpc_count zpc_counts_16x16; + vp9_zpc_count zpc_counts_32x32; +#endif nmv_context_counts NMVcount; vp9_prob switchable_interp_prob[VP9_SWITCHABLE_FILTERS + 1] @@ -377,4 +395,8 @@ static int get_mb_row(const MACROBLOCKD *xd) { static int get_mb_col(const MACROBLOCKD *xd) { return ((-xd->mb_to_left_edge) >> 7); } + +static int get_token_alloc(int mb_rows, int mb_cols) { + return mb_rows * mb_cols * (24 * 16 + 4); +} #endif // VP9_COMMON_VP9_ONYXC_INT_H_ diff --git a/vp9/decoder/vp9_decodframe.c b/vp9/decoder/vp9_decodframe.c index 6ceb94253..a13c4580a 100644 --- a/vp9/decoder/vp9_decodframe.c +++ b/vp9/decoder/vp9_decodframe.c @@ -995,6 +995,54 @@ static void init_frame(VP9D_COMP *pbi) { xd->corrupted = 0; } +#if CONFIG_CODE_ZEROGROUP +static void read_zpc_probs_common(VP9_COMMON *cm, + vp9_reader* bc, + TX_SIZE tx_size) { + int r, b, p, n; + vp9_zpc_probs *zpc_probs; + vp9_prob upd = ZPC_UPDATE_PROB; + if (!get_zpc_used(tx_size)) return; + if (!vp9_read_bit(bc)) return; + + if (tx_size == TX_32X32) { + zpc_probs = &cm->fc.zpc_probs_32x32; + } else if (tx_size == TX_16X16) { + zpc_probs = &cm->fc.zpc_probs_16x16; + } else if (tx_size == TX_8X8) { + zpc_probs = &cm->fc.zpc_probs_8x8; + } else { + zpc_probs = &cm->fc.zpc_probs_4x4; + } + for (r = 0; r < REF_TYPES; ++r) { + for (b = 0; b < ZPC_BANDS; ++b) { + for (p = 0; p < ZPC_PTOKS; ++p) { + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob *q = &(*zpc_probs)[r][b][p][n]; +#if USE_ZPC_EXTRA == 0 + if (n == 1) continue; +#endif + if (vp9_read(bc, upd)) { + *q = read_prob_diff_update(bc, *q); + } + } + } + } + } +} + +static void read_zpc_probs(VP9_COMMON *cm, + vp9_reader* bc) { + read_zpc_probs_common(cm, bc, TX_4X4); + if (cm->txfm_mode != ONLY_4X4) + read_zpc_probs_common(cm, bc, TX_8X8); + if (cm->txfm_mode > ALLOW_8X8) + read_zpc_probs_common(cm, bc, TX_16X16); + if (cm->txfm_mode > ALLOW_16X16) + read_zpc_probs_common(cm, bc, TX_32X32); +} +#endif // CONFIG_CODE_ZEROGROUP + #if CONFIG_CODE_NONZEROCOUNT static void read_nzc_probs_common(VP9_COMMON *cm, vp9_reader *rd, @@ -1404,6 +1452,17 @@ static void update_frame_context(VP9D_COMP *pbi) { vp9_zero(fc->nzc_counts_32x32); vp9_zero(fc->nzc_pcat_counts); #endif +#if CONFIG_CODE_ZEROGROUP + vp9_copy(fc->pre_zpc_probs_4x4, fc->zpc_probs_4x4); + vp9_copy(fc->pre_zpc_probs_8x8, fc->zpc_probs_8x8); + vp9_copy(fc->pre_zpc_probs_16x16, fc->zpc_probs_16x16); + vp9_copy(fc->pre_zpc_probs_32x32, fc->zpc_probs_32x32); + + vp9_zero(fc->zpc_counts_4x4); + vp9_zero(fc->zpc_counts_8x8); + vp9_zero(fc->zpc_counts_16x16); + vp9_zero(fc->zpc_counts_32x32); +#endif } static void decode_tiles(VP9D_COMP *pbi, @@ -1660,6 +1719,9 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) { #if CONFIG_CODE_NONZEROCOUNT read_nzc_probs(&pbi->common, &header_bc); #endif +#if CONFIG_CODE_ZEROGROUP + read_zpc_probs(&pbi->common, &header_bc); +#endif // Initialize xd pointers. Any reference should do for xd->pre, so use 0. vpx_memcpy(&xd->pre, &pc->yv12_fb[pc->active_ref_idx[0]], @@ -1711,6 +1773,9 @@ int vp9_decode_frame(VP9D_COMP *pbi, const uint8_t **p_data_end) { vp9_adapt_coef_probs(pc); #if CONFIG_CODE_NONZEROCOUNT vp9_adapt_nzc_probs(pc); +#endif +#if CONFIG_CODE_ZEROGROUP + vp9_adapt_zpc_probs(pc); #endif } diff --git a/vp9/decoder/vp9_detokenize.c b/vp9/decoder/vp9_detokenize.c index b3a6927c2..7cfc7dc65 100644 --- a/vp9/decoder/vp9_detokenize.c +++ b/vp9/decoder/vp9_detokenize.c @@ -60,14 +60,28 @@ static const vp9_prob cat6_prob[15] = { DECLARE_ALIGNED(16, extern const uint8_t, vp9_norm[256]); +#if CONFIG_CODE_ZEROGROUP +#define ZEROGROUP_ADVANCE() \ + do { \ + token_cache[scan[c]] = ZERO_TOKEN; \ + is_last_zero[o] = 1; \ + c++; \ + } while (0) +#define INCREMENT_COUNT(token) \ + do { \ + coef_counts[type][ref][get_coef_band(scan, txfm_size, c)] \ + [pt][token]++; \ + token_cache[scan[c]] = token; \ + is_last_zero[o] = (token == ZERO_TOKEN); \ + } while (0) +#else #define INCREMENT_COUNT(token) \ do { \ coef_counts[type][ref][get_coef_band(scan, txfm_size, c)] \ [pt][token]++; \ - token_cache[c] = token; \ - pt = vp9_get_coef_context(scan, nb, pad, token_cache, \ - c + 1, default_eob); \ + token_cache[scan[c]] = token; \ } while (0) +#endif #if CONFIG_CODE_NONZEROCOUNT #define WRITE_COEF_CONTINUE(val, token) \ @@ -88,6 +102,12 @@ DECLARE_ALIGNED(16, extern const uint8_t, vp9_norm[256]); } #endif // CONFIG_CODE_NONZEROCOUNT +#define WRITE_COEF_ONE() \ +{ \ + qcoeff_ptr[scan[c]] = vp9_read_and_apply_sign(br, 1); \ + INCREMENT_COUNT(ONE_TOKEN); \ +} + #define ADJUST_COEF(prob, bits_count) \ do { \ if (vp9_read(r, prob)) \ @@ -108,6 +128,16 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, vp9_prob *prob; vp9_coeff_count *coef_counts; const int ref = xd->mode_info_context->mbmi.ref_frame != INTRA_FRAME; + TX_TYPE tx_type = DCT_DCT; +#if CONFIG_CODE_ZEROGROUP + int is_eoo[3] = {0, 0, 0}; + int is_last_zero[3] = {0, 0, 0}; + int o, rc; + vp9_zpc_probs *zpc_probs; + vp9_zpc_count *zpc_count; + vp9_prob *zprobs; + int eoo = 0, use_eoo; +#endif #if CONFIG_CODE_NONZEROCOUNT const int nzc_used = get_nzc_used(txfm_size); uint16_t nzc = 0; @@ -116,6 +146,9 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, #endif const int *scan, *nb; uint8_t token_cache[1024]; +#if CONFIG_CODE_ZEROGROUP + vpx_memset(token_cache, UNKNOWN_TOKEN, sizeof(token_cache)); +#endif if (xd->mode_info_context->mbmi.sb_type == BLOCK_SIZE_SB64X64) { aidx = vp9_block2above_sb64[txfm_size][block_idx]; @@ -147,8 +180,8 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, switch (txfm_size) { default: case TX_4X4: { - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_4x4(xd, block_idx) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_4x4(xd, block_idx) : DCT_DCT; switch (tx_type) { default: scan = vp9_default_zig_zag1d_4x4; @@ -165,6 +198,10 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, coef_probs = fc->coef_probs_4x4; coef_counts = fc->coef_counts_4x4; default_eob = 16; +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &(fc->zpc_probs_4x4); + zpc_count = &(fc->zpc_counts_4x4); +#endif break; } case TX_8X8: { @@ -172,8 +209,8 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, const int sz = 3 + mb_width_log2(sb_type); const int x = block_idx & ((1 << sz) - 1); const int y = block_idx - x; - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_8x8(xd, y + (x >> 1)) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_8x8(xd, y + (x >> 1)) : DCT_DCT; switch (tx_type) { default: scan = vp9_default_zig_zag1d_8x8; @@ -190,6 +227,10 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, above_ec = (A0[aidx] + A0[aidx + 1]) != 0; left_ec = (L0[lidx] + L0[lidx + 1]) != 0; default_eob = 64; +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &(fc->zpc_probs_8x8); + zpc_count = &(fc->zpc_counts_8x8); +#endif break; } case TX_16X16: { @@ -197,8 +238,8 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, const int sz = 4 + mb_width_log2(sb_type); const int x = block_idx & ((1 << sz) - 1); const int y = block_idx - x; - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_16x16(xd, y + (x >> 2)) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_16x16(xd, y + (x >> 2)) : DCT_DCT; switch (tx_type) { default: scan = vp9_default_zig_zag1d_16x16; @@ -222,6 +263,10 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, left_ec = (L0[lidx] + L0[lidx + 1] + L0[lidx + 2] + L0[lidx + 3]) != 0; } default_eob = 256; +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &(fc->zpc_probs_16x16); + zpc_count = &(fc->zpc_counts_16x16); +#endif break; } case TX_32X32: @@ -248,6 +293,10 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, L1[lidx] + L1[lidx + 1] + L1[lidx + 2] + L1[lidx + 3]) != 0; } default_eob = 1024; +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &fc->zpc_probs_32x32; + zpc_count = &fc->zpc_counts_32x32; +#endif break; } @@ -256,35 +305,85 @@ static int decode_coefs(VP9D_COMP *dx, const MACROBLOCKD *xd, while (1) { int val; + int band; const uint8_t *cat6 = cat6_prob; - if (c >= seg_eob) break; #if CONFIG_CODE_NONZEROCOUNT if (nzc_used && nzc == nzc_expected) break; #endif - prob = coef_probs[type][ref][get_coef_band(scan, txfm_size, c)][pt]; - fc->eob_branch_counts[txfm_size][type][ref] - [get_coef_band(scan, txfm_size, c)][pt]++; + if (c) + pt = vp9_get_coef_context(scan, nb, pad, token_cache, + c, default_eob); + band = get_coef_band(scan, txfm_size, c); + prob = coef_probs[type][ref][band][pt]; + fc->eob_branch_counts[txfm_size][type][ref][band][pt]++; #if CONFIG_CODE_NONZEROCOUNT - if (!nzc_used) + if (!nzc_used) { #endif if (!vp9_read(r, prob[EOB_CONTEXT_NODE])) break; +#if CONFIG_CODE_ZEROGROUP + rc = scan[c]; + o = vp9_get_orientation(rc, txfm_size); + if (token_cache[rc] == ZERO_TOKEN || is_eoo[o]) { + coef_counts[type][ref][band][pt][ZERO_TOKEN]++; + ZEROGROUP_ADVANCE(); + goto SKIP_START; + } +#endif +#if CONFIG_CODE_NONZEROCOUNT + } +#endif + SKIP_START: if (c >= seg_eob) break; #if CONFIG_CODE_NONZEROCOUNT if (nzc_used && nzc == nzc_expected) break; +#endif + if (c) + pt = vp9_get_coef_context(scan, nb, pad, token_cache, + c, default_eob); + band = get_coef_band(scan, txfm_size, c); + prob = coef_probs[type][ref][band][pt]; +#if CONFIG_CODE_ZEROGROUP + rc = scan[c]; + o = vp9_get_orientation(rc, txfm_size); + if (token_cache[rc] == ZERO_TOKEN || is_eoo[o]) { + ZEROGROUP_ADVANCE(); + goto SKIP_START; + } + zprobs = (*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)]; +#endif +#if CONFIG_CODE_NONZEROCOUNT // decode zero node only if there are zeros left if (!nzc_used || seg_eob - nzc_expected - c + nzc > 0) #endif if (!vp9_read(r, prob[ZERO_CONTEXT_NODE])) { +#if CONFIG_CODE_ZEROGROUP + eoo = 0; +#if USE_ZPC_EOORIENT == 1 + use_eoo = vp9_use_eoo(c, seg_eob, scan, txfm_size, is_last_zero, is_eoo); +#else + use_eoo = 0; +#endif + if (use_eoo) { + eoo = !vp9_read(r, zprobs[0]); + ++(*zpc_count)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0][!eoo]; + if (eoo) { + is_eoo[o] = 1; + } + } +#endif INCREMENT_COUNT(ZERO_TOKEN); ++c; - prob = coef_probs[type][ref][get_coef_band(scan, txfm_size, c)][pt]; goto SKIP_START; } // ONE_CONTEXT_NODE_0_ diff --git a/vp9/encoder/vp9_bitstream.c b/vp9/encoder/vp9_bitstream.c index 95e05fd55..b12e28816 100644 --- a/vp9/encoder/vp9_bitstream.c +++ b/vp9/encoder/vp9_bitstream.c @@ -67,6 +67,17 @@ void update_nzcstats(VP9_COMMON *const cm); void print_nzcstats(); #endif #endif +#if CONFIG_CODE_ZEROGROUP +#ifdef ZPC_STATS +vp9_zpc_count zpc_stats_4x4; +vp9_zpc_count zpc_stats_8x8; +vp9_zpc_count zpc_stats_16x16; +vp9_zpc_count zpc_stats_32x32; +void init_zpcstats(); +void update_zpcstats(VP9_COMMON *const cm); +void print_zpcstats(); +#endif +#endif #ifdef MODE_STATS int count_mb_seg[4] = { 0, 0, 0, 0 }; @@ -427,24 +438,42 @@ static void pack_mb_tokens(vp9_writer* const bc, const unsigned char *pp = p->context_tree; int v = a->value; int n = a->len; + int ncount = n; if (t == EOSB_TOKEN) { ++p; break; } + assert(pp != 0); +#if CONFIG_CODE_ZEROGROUP + if (t == ZPC_ISOLATED || t == ZPC_EOORIENT) { + assert((p - 1)->token == ZERO_TOKEN); + encode_bool(bc, t == ZPC_ISOLATED, *pp); + ++p; + continue; + } else if (p->skip_coef_val) { + assert(p->skip_eob_node == 0); + assert(t == DCT_EOB_TOKEN || t == ZERO_TOKEN); + encode_bool(bc, t == ZERO_TOKEN, *pp); + ++p; + continue; + } +#endif /* skip one or two nodes */ if (p->skip_eob_node) { n -= p->skip_eob_node; i = 2 * p->skip_eob_node; + ncount -= p->skip_eob_node; } do { const int bb = (v >> --n) & 1; vp9_write(bc, bb, pp[i >> 1]); i = vp9_coef_tree[i + bb]; - } while (n); + ncount--; + } while (n && ncount); if (b->base_val) { @@ -1541,6 +1570,150 @@ void print_nzcstats() { #endif // CONFIG_CODE_NONZEROCOUNT +#if CONFIG_CODE_ZEROGROUP +#ifdef ZPC_STATS +void init_zpcstats() { + vp9_zero(zpc_stats_4x4); + vp9_zero(zpc_stats_8x8); + vp9_zero(zpc_stats_16x16); + vp9_zero(zpc_stats_32x32); +} + +void update_zpcstats(VP9_COMMON *const cm) { + int r, b, p, n; + for (r = 0; r < REF_TYPES; ++r) { + for (b = 0; b < ZPC_BANDS; ++b) { + for (p = 0; p < ZPC_PTOKS; ++p) { + for (n = 0; n < ZPC_NODES; ++n) { + zpc_stats_4x4[r][b][p][n][0] += cm->fc.zpc_counts_4x4[r][b][p][n][0]; + zpc_stats_4x4[r][b][p][n][1] += cm->fc.zpc_counts_4x4[r][b][p][n][1]; + zpc_stats_8x8[r][b][p][n][0] += cm->fc.zpc_counts_8x8[r][b][p][n][0]; + zpc_stats_8x8[r][b][p][n][1] += cm->fc.zpc_counts_8x8[r][b][p][n][1]; + zpc_stats_16x16[r][b][p][n][0] += + cm->fc.zpc_counts_16x16[r][b][p][n][0]; + zpc_stats_16x16[r][b][p][n][1] += + cm->fc.zpc_counts_16x16[r][b][p][n][1]; + zpc_stats_32x32[r][b][p][n][0] += + cm->fc.zpc_counts_32x32[r][b][p][n][0]; + zpc_stats_32x32[r][b][p][n][1] += + cm->fc.zpc_counts_32x32[r][b][p][n][1]; + } + } + } + } +} + +void print_zpcstats() { + int r, b, p, n; + FILE *f; + + printf( + "static const unsigned int default_zpc_probs_4x4[REF_TYPES]\n" + " [ZPC_BANDS]\n" + " [ZPC_PTOKS]\n" + " [ZPC_NODES] = {\n"); + for (r = 0; r < REF_TYPES; ++r) { + printf(" {\n"); + for (b = 0; b < ZPC_BANDS; ++b) { + printf(" {\n"); + for (p = 0; p < ZPC_PTOKS; ++p) { + printf(" {"); + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob prob = get_binary_prob(zpc_stats_4x4[r][b][p][n][0], + zpc_stats_4x4[r][b][p][n][1]); + printf(" %-3d [%d/%d],", prob, zpc_stats_4x4[r][b][p][n][0], + zpc_stats_4x4[r][b][p][n][1]); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf("};\n"); + printf( + "static const unsigned int default_zpc_probs_8x8[REF_TYPES]\n" + " [ZPC_BANDS]\n" + " [ZPC_PTOKS]\n" + " [ZPC_NODES] = {\n"); + for (r = 0; r < REF_TYPES; ++r) { + printf(" {\n"); + for (b = 0; b < ZPC_BANDS; ++b) { + printf(" {\n"); + for (p = 0; p < ZPC_PTOKS; ++p) { + printf(" {"); + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob prob = get_binary_prob(zpc_stats_8x8[r][b][p][n][0], + zpc_stats_8x8[r][b][p][n][1]); + printf(" %-3d [%d/%d],", prob, zpc_stats_8x8[r][b][p][n][0], + zpc_stats_8x8[r][b][p][n][1]); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf("};\n"); + printf( + "static const unsigned int default_zpc_probs_16x16[REF_TYPES]\n" + " [ZPC_BANDS]\n" + " [ZPC_PTOKS]\n" + " [ZPC_NODES] = {\n"); + for (r = 0; r < REF_TYPES; ++r) { + printf(" {\n"); + for (b = 0; b < ZPC_BANDS; ++b) { + printf(" {\n"); + for (p = 0; p < ZPC_PTOKS; ++p) { + printf(" {"); + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob prob = get_binary_prob(zpc_stats_16x16[r][b][p][n][0], + zpc_stats_16x16[r][b][p][n][1]); + printf(" %-3d [%d/%d],", prob, zpc_stats_16x16[r][b][p][n][0], + zpc_stats_16x16[r][b][p][n][1]); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf("};\n"); + printf( + "static const unsigned int default_zpc_probs_32x32[REF_TYPES]\n" + " [ZPC_BANDS]\n" + " [ZPC_PTOKS]\n" + " [ZPC_NODES] = {\n"); + for (r = 0; r < REF_TYPES; ++r) { + printf(" {\n"); + for (b = 0; b < ZPC_BANDS; ++b) { + printf(" {\n"); + for (p = 0; p < ZPC_PTOKS; ++p) { + printf(" {"); + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob prob = get_binary_prob(zpc_stats_32x32[r][b][p][n][0], + zpc_stats_32x32[r][b][p][n][1]); + printf(" %-3d [%d/%d],", prob, zpc_stats_32x32[r][b][p][n][0], + zpc_stats_32x32[r][b][p][n][1]); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf(" },\n"); + } + printf("};\n"); + + f = fopen("zpcstats.bin", "wb"); + fwrite(zpc_stats_4x4, sizeof(zpc_stats_4x4), 1, f); + fwrite(zpc_stats_8x8, sizeof(zpc_stats_8x8), 1, f); + fwrite(zpc_stats_16x16, sizeof(zpc_stats_16x16), 1, f); + fwrite(zpc_stats_32x32, sizeof(zpc_stats_32x32), 1, f); + fclose(f); +} +#endif +#endif // CONFIG_CODE_ZEROGROUP + static void write_modes_b(VP9_COMP *cpi, MODE_INFO *m, vp9_writer *bc, TOKENEXTRA **tok, TOKENEXTRA *tok_end, int mb_row, int mb_col) { @@ -1779,6 +1952,129 @@ static void build_coeff_contexts(VP9_COMP *cpi) { cpi->frame_branch_ct_32x32, BLOCK_TYPES); } +#if CONFIG_CODE_ZEROGROUP +static void update_zpc_probs_common(VP9_COMP* cpi, + vp9_writer* const bc, + TX_SIZE tx_size) { + int r, b, p, n; + VP9_COMMON *const cm = &cpi->common; + int update[2] = {0, 0}; + int savings = 0; + vp9_zpc_probs newprobs; + vp9_zpc_probs *zpc_probs; + vp9_zpc_count *zpc_counts; + vp9_prob upd = ZPC_UPDATE_PROB; + + if (!get_zpc_used(tx_size)) return; + if (tx_size == TX_32X32) { + zpc_probs = &cm->fc.zpc_probs_32x32; + zpc_counts = &cm->fc.zpc_counts_32x32; + } else if (tx_size == TX_16X16) { + zpc_probs = &cm->fc.zpc_probs_16x16; + zpc_counts = &cm->fc.zpc_counts_16x16; + } else if (tx_size == TX_8X8) { + zpc_probs = &cm->fc.zpc_probs_8x8; + zpc_counts = &cm->fc.zpc_counts_8x8; + } else { + zpc_probs = &cm->fc.zpc_probs_4x4; + zpc_counts = &cm->fc.zpc_counts_4x4; + } + for (r = 0; r < REF_TYPES; ++r) { + for (b = 0; b < ZPC_BANDS; ++b) { + for (p = 0; p < ZPC_PTOKS; ++p) { + for (n = 0; n < ZPC_NODES; ++n) { + newprobs[r][b][p][n] = get_binary_prob((*zpc_counts)[r][b][p][n][0], + (*zpc_counts)[r][b][p][n][1]); + } + } + } + } + for (r = 0; r < REF_TYPES; ++r) { + for (b = 0; b < ZPC_BANDS; ++b) { + for (p = 0; p < ZPC_PTOKS; ++p) { + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob newp = newprobs[r][b][p][n]; + vp9_prob oldp = (*zpc_probs)[r][b][p][n]; + int s, u = 0; +#if USE_ZPC_EXTRA == 0 + if (n == 1) continue; +#endif +#if defined(SEARCH_NEWP) + s = prob_diff_update_savings_search((*zpc_counts)[r][b][p][n], + oldp, &newp, upd); + if (s > 0 && newp != oldp) + u = 1; + if (u) + savings += s - (int)(vp9_cost_zero(upd)); + else + savings -= (int)(vp9_cost_zero(upd)); +#else + s = prob_update_savings((*zpc_counts)[r][b][p][n], + oldp, newp, upd); + if (s > 0) + u = 1; + if (u) + savings += s; +#endif + update[u]++; + } + } + } + } + if (update[1] == 0 || savings < 0) { + vp9_write_bit(bc, 0); + return; + } + vp9_write_bit(bc, 1); + for (r = 0; r < REF_TYPES; ++r) { + for (b = 0; b < ZPC_BANDS; ++b) { + for (p = 0; p < ZPC_PTOKS; ++p) { + for (n = 0; n < ZPC_NODES; ++n) { + vp9_prob newp = newprobs[r][b][p][n]; + vp9_prob *oldp = &(*zpc_probs)[r][b][p][n]; + int s, u = 0; +#if USE_ZPC_EXTRA == 0 + if (n == 1) continue; +#endif +#if defined(SEARCH_NEWP) + s = prob_diff_update_savings_search((*zpc_counts)[r][b][p][n], + *oldp, &newp, upd); + if (s > 0 && newp != *oldp) + u = 1; +#else + s = prob_update_savings((*zpc_counts)[r][b][p][n], + *oldp, newp, upd); + if (s > 0) + u = 1; +#endif + vp9_write(bc, u, upd); + if (u) { + /* send/use new probability */ + write_prob_diff_update(bc, newp, *oldp); + *oldp = newp; + } + } + } + } + } +} + +static void update_zpc_probs(VP9_COMP* cpi, + vp9_writer* const bc) { + update_zpc_probs_common(cpi, bc, TX_4X4); + if (cpi->common.txfm_mode != ONLY_4X4) + update_zpc_probs_common(cpi, bc, TX_8X8); + if (cpi->common.txfm_mode > ALLOW_8X8) + update_zpc_probs_common(cpi, bc, TX_16X16); + if (cpi->common.txfm_mode > ALLOW_16X16) + update_zpc_probs_common(cpi, bc, TX_32X32); +#ifdef ZPC_STATS + if (!cpi->dummy_packing) + update_zpcstats(&cpi->common); +#endif +} +#endif // CONFIG_CODE_ZEROGROUP + #if CONFIG_CODE_NONZEROCOUNT static void update_nzc_probs_common(VP9_COMP* cpi, vp9_writer* const bc, @@ -2690,6 +2986,16 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, vp9_zero(cpi->common.fc.nzc_counts_32x32); vp9_zero(cpi->common.fc.nzc_pcat_counts); */ +#endif +#if CONFIG_CODE_ZEROGROUP + vp9_copy(cpi->common.fc.pre_zpc_probs_4x4, + cpi->common.fc.zpc_probs_4x4); + vp9_copy(cpi->common.fc.pre_zpc_probs_8x8, + cpi->common.fc.zpc_probs_8x8); + vp9_copy(cpi->common.fc.pre_zpc_probs_16x16, + cpi->common.fc.zpc_probs_16x16); + vp9_copy(cpi->common.fc.pre_zpc_probs_32x32, + cpi->common.fc.zpc_probs_32x32); #endif vp9_copy(cpi->common.fc.pre_sb_ymode_prob, cpi->common.fc.sb_ymode_prob); vp9_copy(cpi->common.fc.pre_ymode_prob, cpi->common.fc.ymode_prob); @@ -2711,6 +3017,9 @@ void vp9_pack_bitstream(VP9_COMP *cpi, unsigned char *dest, #if CONFIG_CODE_NONZEROCOUNT update_nzc_probs(cpi, &header_bc); #endif +#if CONFIG_CODE_ZEROGROUP + update_zpc_probs(cpi, &header_bc); +#endif #ifdef ENTROPY_STATS active_section = 2; diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index e9612b988..dbd06a06c 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -1345,6 +1345,12 @@ static void encode_frame_internal(VP9_COMP *cpi) { vp9_zero(cm->fc.nzc_counts_32x32); vp9_zero(cm->fc.nzc_pcat_counts); #endif +#if CONFIG_CODE_ZEROGROUP + vp9_zero(cm->fc.zpc_counts_4x4); + vp9_zero(cm->fc.zpc_counts_8x8); + vp9_zero(cm->fc.zpc_counts_16x16); + vp9_zero(cm->fc.zpc_counts_32x32); +#endif cpi->mb.e_mbd.lossless = (cm->base_qindex == 0 && cm->y_dc_delta_q == 0 && @@ -1397,6 +1403,8 @@ static void encode_frame_internal(VP9_COMP *cpi) { encode_sb_row(cpi, mb_row, &tp, &totalrate); } cpi->tok_count[tile_col] = (unsigned int)(tp - tp_old); + assert(tp - cpi->tok <= + get_token_alloc(cm->mb_rows, cm->mb_cols)); } } } diff --git a/vp9/encoder/vp9_encodemb.c b/vp9/encoder/vp9_encodemb.c index f00646c16..c67207b48 100644 --- a/vp9/encoder/vp9_encodemb.c +++ b/vp9/encoder/vp9_encodemb.c @@ -295,10 +295,10 @@ static int trellis_get_coeff_context(const int *scan, int idx, int token, uint8_t *token_cache, int pad, int l) { - int bak = token_cache[idx], pt; - token_cache[idx] = token; + int bak = token_cache[scan[idx]], pt; + token_cache[scan[idx]] = token; pt = vp9_get_coef_context(scan, nb, pad, token_cache, idx + 1, l); - token_cache[idx] = bak; + token_cache[scan[idx]] = bak; return pt; } @@ -430,7 +430,7 @@ static void optimize_b(VP9_COMMON *const cm, *(tokens[eob] + 1) = *(tokens[eob] + 0); next = eob; for (i = 0; i < eob; i++) - token_cache[i] = vp9_dct_value_tokens_ptr[qcoeff_ptr[scan[i]]].token; + token_cache[scan[i]] = vp9_dct_value_tokens_ptr[qcoeff_ptr[scan[i]]].token; nb = vp9_get_coef_neighbors_handle(scan, &pad); for (i = eob; i-- > i0;) { @@ -590,6 +590,8 @@ static void optimize_b(VP9_COMMON *const cm, final_nzc_exp = (best ? nzc1 : nzc0); #endif final_eob = i0 - 1; + vpx_memset(qcoeff_ptr, 0, sizeof(*qcoeff_ptr) * (16 << (tx_size * 2))); + vpx_memset(dqcoeff_ptr, 0, sizeof(*dqcoeff_ptr) * (16 << (tx_size * 2))); for (i = next; i < eob; i = next) { x = tokens[i][best].qc; if (x) { diff --git a/vp9/encoder/vp9_onyx_if.c b/vp9/encoder/vp9_onyx_if.c index 66ed1da72..1c308af39 100644 --- a/vp9/encoder/vp9_onyx_if.c +++ b/vp9/encoder/vp9_onyx_if.c @@ -120,6 +120,12 @@ extern void init_nzcstats(); extern void print_nzcstats(); #endif #endif +#if CONFIG_CODE_ZEROGROUP +#ifdef ZPC_STATS +extern void init_zpcstats(); +extern void print_zpcstats(); +#endif +#endif #ifdef SPEEDSTATS unsigned int frames_at_speed[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -895,7 +901,7 @@ void vp9_alloc_compressor_data(VP9_COMP *cpi) { vpx_free(cpi->tok); { - unsigned int tokens = cm->mb_rows * cm->mb_cols * (24 * 16 + 1); + unsigned int tokens = get_token_alloc(cm->mb_rows, cm->mb_cols); CHECK_MEM_ERROR(cpi->tok, vpx_calloc(tokens, sizeof(*cpi->tok))); } @@ -1437,6 +1443,11 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) { #ifdef NZC_STATS init_nzcstats(); #endif +#endif +#if CONFIG_CODE_ZEROGROUP +#ifdef ZPC_STATS + init_zpcstats(); +#endif #endif /*Initialize the feed-forward activity masking.*/ @@ -1650,6 +1661,12 @@ VP9_PTR vp9_create_compressor(VP9_CONFIG *oxcf) { vp9_zero(cm->fc.nzc_counts_32x32); vp9_zero(cm->fc.nzc_pcat_counts); #endif +#if CONFIG_CODE_ZEROGROUP + vp9_zero(cm->fc.zpc_counts_4x4); + vp9_zero(cm->fc.zpc_counts_8x8); + vp9_zero(cm->fc.zpc_counts_16x16); + vp9_zero(cm->fc.zpc_counts_32x32); +#endif return (VP9_PTR) cpi; } @@ -1683,6 +1700,12 @@ void vp9_remove_compressor(VP9_PTR *ptr) { print_nzcstats(); #endif #endif +#if CONFIG_CODE_ZEROGROUP +#ifdef ZPC_STATS + if (cpi->pass != 1) + print_zpcstats(); +#endif +#endif #if CONFIG_INTERNAL_STATS @@ -3303,6 +3326,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, vp9_adapt_coef_probs(&cpi->common); #if CONFIG_CODE_NONZEROCOUNT vp9_adapt_nzc_probs(&cpi->common); +#endif +#if CONFIG_CODE_ZEROGROUP + vp9_adapt_zpc_probs(&cpi->common); #endif } if (cpi->common.frame_type != KEY_FRAME) { diff --git a/vp9/encoder/vp9_onyx_int.h b/vp9/encoder/vp9_onyx_int.h index 6d309c84d..a6cfe9367 100644 --- a/vp9/encoder/vp9_onyx_int.h +++ b/vp9/encoder/vp9_onyx_int.h @@ -126,6 +126,12 @@ typedef struct { vp9_prob nzc_pcat_probs[MAX_NZC_CONTEXTS] [NZC_TOKENS_EXTRA][NZC_BITS_EXTRA]; #endif +#if CONFIG_CODE_ZEROGROUP + vp9_zpc_probs zpc_probs_4x4; + vp9_zpc_probs zpc_probs_8x8; + vp9_zpc_probs zpc_probs_16x16; + vp9_zpc_probs zpc_probs_32x32; +#endif } CODING_CONTEXT; typedef struct { diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 96d857fe7..30889d3e8 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -179,6 +179,12 @@ void vp9_save_coding_context(VP9_COMP *cpi) { vp9_copy(cc->nzc_probs_32x32, cm->fc.nzc_probs_32x32); vp9_copy(cc->nzc_pcat_probs, cm->fc.nzc_pcat_probs); #endif +#if CONFIG_CODE_ZEROGROUP + vp9_copy(cc->zpc_probs_4x4, cm->fc.zpc_probs_4x4); + vp9_copy(cc->zpc_probs_8x8, cm->fc.zpc_probs_8x8); + vp9_copy(cc->zpc_probs_16x16, cm->fc.zpc_probs_16x16); + vp9_copy(cc->zpc_probs_32x32, cm->fc.zpc_probs_32x32); +#endif } void vp9_restore_coding_context(VP9_COMP *cpi) { @@ -242,6 +248,12 @@ void vp9_restore_coding_context(VP9_COMP *cpi) { vp9_copy(cm->fc.nzc_probs_32x32, cc->nzc_probs_32x32); vp9_copy(cm->fc.nzc_pcat_probs, cc->nzc_pcat_probs); #endif +#if CONFIG_CODE_ZEROGROUP + vp9_copy(cm->fc.zpc_probs_4x4, cc->zpc_probs_4x4); + vp9_copy(cm->fc.zpc_probs_8x8, cc->zpc_probs_8x8); + vp9_copy(cm->fc.zpc_probs_16x16, cc->zpc_probs_16x16); + vp9_copy(cm->fc.zpc_probs_32x32, cc->zpc_probs_32x32); +#endif } void vp9_setup_key_frame(VP9_COMP *cpi) { diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index d0678a319..87a6b6fab 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -374,11 +374,21 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, sizeof(ENTROPY_CONTEXT_PLANES)/sizeof(ENTROPY_CONTEXT); ENTROPY_CONTEXT *const l1 = l + sizeof(ENTROPY_CONTEXT_PLANES)/sizeof(ENTROPY_CONTEXT); + TX_TYPE tx_type = DCT_DCT; #if CONFIG_CODE_NONZEROCOUNT const int nzc_used = get_nzc_used(tx_size); int nzc_context = vp9_get_nzc_context(cm, xd, ib); unsigned int *nzc_cost; +#endif +#if CONFIG_CODE_ZEROGROUP + int last_nz_pos[3] = {-1, -1, -1}; // Encoder only + int is_eoo_list[3] = {0, 0, 0}; + int is_eoo_negative[3] = {0, 0, 0}; + int is_last_zero[3] = {0, 0, 0}; + int o, rc, skip_coef_val; + vp9_zpc_probs *zpc_probs; + uint8_t token_cache_full[1024]; #endif const int segment_id = xd->mode_info_context->mbmi.segment_id; vp9_prob (*coef_probs)[REF_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS] @@ -386,6 +396,10 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, int seg_eob, default_eob; uint8_t token_cache[1024]; +#if CONFIG_CODE_ZEROGROUP + vpx_memset(token_cache, UNKNOWN_TOKEN, sizeof(token_cache)); +#endif + // Check for consistency of tx_size with mode info assert((!type && !pb_idx.plane) || (type && pb_idx.plane)); if (type == PLANE_TYPE_Y_WITH_DC) { @@ -397,8 +411,8 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, switch (tx_size) { case TX_4X4: { - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_4x4(xd, ib) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_4x4(xd, ib) : DCT_DCT; a_ec = *a; l_ec = *l; #if CONFIG_CODE_NONZEROCOUNT @@ -413,14 +427,17 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, } else { scan = vp9_default_zig_zag1d_4x4; } +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &cm->fc.zpc_probs_4x4; +#endif break; } case TX_8X8: { const BLOCK_SIZE_TYPE sb_type = xd->mode_info_context->mbmi.sb_type; const int sz = 3 + mb_width_log2(sb_type); const int x = ib & ((1 << sz) - 1), y = ib - x; - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_8x8(xd, y + (x >> 1)) : DCT_DCT; + TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_8x8(xd, y + (x >> 1)) : DCT_DCT; a_ec = (a[0] + a[1]) != 0; l_ec = (l[0] + l[1]) != 0; if (tx_type == ADST_DCT) { @@ -435,14 +452,17 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, #endif coef_probs = cm->fc.coef_probs_8x8; seg_eob = 64; +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &cm->fc.zpc_probs_8x8; +#endif break; } case TX_16X16: { const BLOCK_SIZE_TYPE sb_type = xd->mode_info_context->mbmi.sb_type; const int sz = 4 + mb_width_log2(sb_type); const int x = ib & ((1 << sz) - 1), y = ib - x; - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_16x16(xd, y + (x >> 2)) : DCT_DCT; + TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_16x16(xd, y + (x >> 2)) : DCT_DCT; if (tx_type == ADST_DCT) { scan = vp9_row_scan_16x16; } else if (tx_type == DCT_ADST) { @@ -462,6 +482,9 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, a_ec = (a[0] + a[1] + a[2] + a[3]) != 0; l_ec = (l[0] + l[1] + l[2] + l[3]) != 0; } +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &cm->fc.zpc_probs_16x16; +#endif break; } case TX_32X32: @@ -487,6 +510,9 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, l_ec = (l[0] + l[1] + l[2] + l[3] + l1[0] + l1[1] + l1[2] + l1[3]) != 0; } +#if CONFIG_CODE_ZEROGROUP + zpc_probs = &cm->fc.zpc_probs_32x32; +#endif break; default: abort(); @@ -508,36 +534,116 @@ static INLINE int cost_coeffs(VP9_COMMON *const cm, MACROBLOCK *mb, if (eob < seg_eob) assert(qcoeff_ptr[scan[eob]] == 0); +#if CONFIG_CODE_ZEROGROUP + vpx_memset(token_cache_full, ZERO_TOKEN, sizeof(token_cache_full)); + for (c = 0; c < eob; ++c) { + rc = scan[c]; + token_cache_full[rc] = vp9_dct_value_tokens_ptr[qcoeff_ptr[rc]].token; + o = vp9_get_orientation(rc, tx_size); + if (qcoeff_ptr[rc] != 0) + last_nz_pos[o] = c; + } +#endif { #if CONFIG_CODE_NONZEROCOUNT int nzc = 0; #endif - for (; c < eob; c++) { + for (c = 0; c < eob; c++) { int v = qcoeff_ptr[scan[c]]; int t = vp9_dct_value_tokens_ptr[v].token; + int band = get_coef_band(scan, tx_size, c); #if CONFIG_CODE_NONZEROCOUNT nzc += (v != 0); #endif - token_cache[c] = t; - cost += token_costs[get_coef_band(scan, tx_size, c)][pt][t]; - cost += vp9_dct_value_cost_ptr[v]; -#if !CONFIG_CODE_NONZEROCOUNT - if (!c || token_cache[c - 1]) - cost += vp9_cost_bit(coef_probs[type][ref] - [get_coef_band(scan, tx_size, c)] - [pt][0], 1); + if (c) + pt = vp9_get_coef_context(scan, nb, pad, token_cache, c, default_eob); +#if CONFIG_CODE_ZEROGROUP + rc = scan[c]; + o = vp9_get_orientation(rc, tx_size); + skip_coef_val = (token_cache[rc] == ZERO_TOKEN || is_eoo_list[o]); + if (!skip_coef_val) { + cost += token_costs[band][pt][t] + vp9_dct_value_cost_ptr[v]; + } else { + assert(v == 0); + } +#else + cost += token_costs[band][pt][t] + vp9_dct_value_cost_ptr[v]; +#endif +#if CONFIG_CODE_NONZEROCOUNT + if (!nzc_used) +#endif + if (!c || token_cache[scan[c - 1]]) + cost += vp9_cost_bit(coef_probs[type][ref][band][pt][0], 1); + token_cache[scan[c]] = t; +#if CONFIG_CODE_ZEROGROUP + if (t == ZERO_TOKEN && !skip_coef_val) { + int eoo = 0, use_eoo; +#if USE_ZPC_EOORIENT == 1 + use_eoo = vp9_use_eoo(c, seg_eob, scan, tx_size, + is_last_zero, is_eoo_list); +#else + use_eoo = 0; +#endif + if (use_eoo) { + eoo = vp9_is_eoo(c, eob, scan, tx_size, qcoeff_ptr, last_nz_pos); + if (eoo && is_eoo_negative[o]) eoo = 0; + if (eoo) { + int c_; + int savings = 0; + int zsaved = 0; + savings = vp9_cost_bit((*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0], 1) - + vp9_cost_bit((*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0], 0); + for (c_ = c + 1; c_ < eob; ++c_) { + if (o == vp9_get_orientation(scan[c_], tx_size)) { + int pt_ = vp9_get_coef_context(scan, nb, pad, + token_cache_full, c_, + default_eob); + int band_ = get_coef_band(scan, tx_size, c_); + assert(token_cache_full[scan[c_]] == ZERO_TOKEN); + if (!c_ || token_cache_full[scan[c_ - 1]]) + savings += vp9_cost_bit( + coef_probs[type][ref][band_][pt_][0], 1); + savings += vp9_cost_bit( + coef_probs[type][ref][band_][pt_][1], 0); + zsaved++; + } + } + if (savings < 0) { + // if (zsaved < ZPC_ZEROSSAVED_EOO) { + eoo = 0; + is_eoo_negative[o] = 1; + } + } + } + if (use_eoo) { + cost += vp9_cost_bit((*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0], !eoo); + if (eoo) { + assert(is_eoo_list[o] == 0); + is_eoo_list[o] = 1; + } + } + } + is_last_zero[o] = (t == ZERO_TOKEN); #endif - pt = vp9_get_coef_context(scan, nb, pad, token_cache, c + 1, default_eob); } #if CONFIG_CODE_NONZEROCOUNT if (nzc_used) cost += nzc_cost[nzc]; else #endif - if (c < seg_eob) + if (c < seg_eob) { + if (c) + pt = vp9_get_coef_context(scan, nb, pad, token_cache, c, default_eob); cost += mb->token_costs[tx_size][type][ref] [get_coef_band(scan, tx_size, c)] [pt][DCT_EOB_TOKEN]; + } } // is eob first coefficient; diff --git a/vp9/encoder/vp9_tokenize.c b/vp9/encoder/vp9_tokenize.c index 398b4bbe6..dd9efe6db 100644 --- a/vp9/encoder/vp9_tokenize.c +++ b/vp9/encoder/vp9_tokenize.c @@ -121,7 +121,7 @@ static void tokenize_b(VP9_COMP *cpi, int dry_run) { MB_MODE_INFO *mbmi = &xd->mode_info_context->mbmi; int pt; /* near block/prev token context index */ - int c = 0; + int c = 0, rc = 0; TOKENEXTRA *t = *tp; /* store tokens starting here */ const struct plane_block_idx pb_idx = plane_block_idx(y_blocks, ib); const int eob = xd->plane[pb_idx.plane].eobs[pb_idx.block]; @@ -132,16 +132,30 @@ static void tokenize_b(VP9_COMP *cpi, const BLOCK_SIZE_TYPE sb_type = mbmi->sb_type; const int *scan, *nb; vp9_coeff_count *counts; - vp9_coeff_probs *probs; + vp9_coeff_probs *coef_probs; const int ref = mbmi->ref_frame != INTRA_FRAME; ENTROPY_CONTEXT *a, *l, *a1, *l1, *a2, *l2, *a3, *l3, a_ec, l_ec; uint8_t token_cache[1024]; + TX_TYPE tx_type = DCT_DCT; +#if CONFIG_CODE_ZEROGROUP + int last_nz_pos[3] = {-1, -1, -1}; // Encoder only + int is_eoo_list[3] = {0, 0, 0}; + int is_last_zero[3] = {0, 0, 0}; + int is_eoo_negative[3] = {0, 0, 0}; + int o; + vp9_zpc_probs *zpc_probs; + vp9_zpc_count *zpc_count; + uint8_t token_cache_full[1024]; +#endif #if CONFIG_CODE_NONZEROCOUNT const int nzc_used = get_nzc_used(tx_size); int zerosleft = 0, nzc = 0; if (eob == 0) assert(xd->nzcs[ib] == 0); #endif +#if CONFIG_CODE_ZEROGROUP + vpx_memset(token_cache, UNKNOWN_TOKEN, sizeof(token_cache)); +#endif assert((!type && !pb_idx.plane) || (type && pb_idx.plane)); if (sb_type == BLOCK_SIZE_SB64X64) { @@ -206,8 +220,8 @@ static void tokenize_b(VP9_COMP *cpi, switch (tx_size) { default: case TX_4X4: { - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_4x4(xd, ib) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_4x4(xd, ib) : DCT_DCT; a_ec = *a; l_ec = *l; seg_eob = 16; @@ -220,14 +234,18 @@ static void tokenize_b(VP9_COMP *cpi, } } counts = cpi->coef_counts_4x4; - probs = cpi->common.fc.coef_probs_4x4; + coef_probs = cpi->common.fc.coef_probs_4x4; +#if CONFIG_CODE_ZEROGROUP + zpc_count = &cpi->common.fc.zpc_counts_4x4; + zpc_probs = &cpi->common.fc.zpc_probs_4x4; +#endif break; } case TX_8X8: { const int sz = 3 + mb_width_log2(sb_type); const int x = ib & ((1 << sz) - 1), y = ib - x; - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_8x8(xd, y + (x >> 1)) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_8x8(xd, y + (x >> 1)) : DCT_DCT; a_ec = (a[0] + a[1]) != 0; l_ec = (l[0] + l[1]) != 0; seg_eob = 64; @@ -240,14 +258,18 @@ static void tokenize_b(VP9_COMP *cpi, } } counts = cpi->coef_counts_8x8; - probs = cpi->common.fc.coef_probs_8x8; + coef_probs = cpi->common.fc.coef_probs_8x8; +#if CONFIG_CODE_ZEROGROUP + zpc_count = &cpi->common.fc.zpc_counts_8x8; + zpc_probs = &cpi->common.fc.zpc_probs_8x8; +#endif break; } case TX_16X16: { const int sz = 4 + mb_width_log2(sb_type); const int x = ib & ((1 << sz) - 1), y = ib - x; - const TX_TYPE tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? - get_tx_type_16x16(xd, y + (x >> 2)) : DCT_DCT; + tx_type = (type == PLANE_TYPE_Y_WITH_DC) ? + get_tx_type_16x16(xd, y + (x >> 2)) : DCT_DCT; if (type != PLANE_TYPE_UV) { a_ec = (a[0] + a[1] + a[2] + a[3]) != 0; l_ec = (l[0] + l[1] + l[2] + l[3]) != 0; @@ -265,7 +287,11 @@ static void tokenize_b(VP9_COMP *cpi, } } counts = cpi->coef_counts_16x16; - probs = cpi->common.fc.coef_probs_16x16; + coef_probs = cpi->common.fc.coef_probs_16x16; +#if CONFIG_CODE_ZEROGROUP + zpc_count = &cpi->common.fc.zpc_counts_16x16; + zpc_probs = &cpi->common.fc.zpc_probs_16x16; +#endif break; } case TX_32X32: @@ -283,7 +309,11 @@ static void tokenize_b(VP9_COMP *cpi, seg_eob = 1024; scan = vp9_default_zig_zag1d_32x32; counts = cpi->coef_counts_32x32; - probs = cpi->common.fc.coef_probs_32x32; + coef_probs = cpi->common.fc.coef_probs_32x32; +#if CONFIG_CODE_ZEROGROUP + zpc_count = &cpi->common.fc.zpc_counts_32x32; + zpc_probs = &cpi->common.fc.zpc_probs_32x32; +#endif break; } @@ -294,16 +324,30 @@ static void tokenize_b(VP9_COMP *cpi, if (vp9_segfeature_active(xd, segment_id, SEG_LVL_SKIP)) seg_eob = 0; +#if CONFIG_CODE_ZEROGROUP + vpx_memset(token_cache_full, ZERO_TOKEN, sizeof(token_cache_full)); + for (c = 0; c < eob; ++c) { + rc = scan[c]; + token_cache_full[rc] = vp9_dct_value_tokens_ptr[qcoeff_ptr[rc]].token; + o = vp9_get_orientation(rc, tx_size); + if (qcoeff_ptr[rc] != 0) { + last_nz_pos[o] = c; + } + } +#endif + c = 0; do { const int band = get_coef_band(scan, tx_size, c); int token; int v = 0; + rc = scan[c]; + if (c) + pt = vp9_get_coef_context(scan, nb, pad, token_cache, c, default_eob); #if CONFIG_CODE_NONZEROCOUNT if (nzc_used) zerosleft = seg_eob - xd->nzcs[ib] - c + nzc; #endif if (c < eob) { - const int rc = scan[c]; v = qcoeff_ptr[rc]; assert(-DCT_MAX_VALUE <= v && v < DCT_MAX_VALUE); @@ -319,15 +363,29 @@ static void tokenize_b(VP9_COMP *cpi, } t->token = token; - t->context_tree = probs[type][ref][band][pt]; + t->context_tree = coef_probs[type][ref][band][pt]; #if CONFIG_CODE_NONZEROCOUNT // Skip zero node if there are no zeros left if (nzc_used) t->skip_eob_node = 1 + (zerosleft == 0); else #endif - t->skip_eob_node = (c > 0) && (token_cache[c - 1] == 0); + t->skip_eob_node = (c > 0) && (token_cache[scan[c - 1]] == 0); assert(vp9_coef_encodings[t->token].len - t->skip_eob_node > 0); +#if CONFIG_CODE_ZEROGROUP + o = vp9_get_orientation(rc, tx_size); + t->skip_coef_val = (token_cache[rc] == ZERO_TOKEN || is_eoo_list[o]); + if (t->skip_coef_val) { + assert(v == 0); + } + // No need to transmit any token + if (t->skip_eob_node && t->skip_coef_val) { + assert(token == ZERO_TOKEN); + is_last_zero[o] = 1; + token_cache[scan[c]] = ZERO_TOKEN; + continue; + } +#endif if (!dry_run) { ++counts[type][ref][band][pt][token]; if (!t->skip_eob_node) @@ -336,13 +394,79 @@ static void tokenize_b(VP9_COMP *cpi, #if CONFIG_CODE_NONZEROCOUNT nzc += (v != 0); #endif - token_cache[c] = token; - - pt = vp9_get_coef_context(scan, nb, pad, token_cache, c + 1, default_eob); + token_cache[scan[c]] = token; +#if CONFIG_CODE_ZEROGROUP + if (token == ZERO_TOKEN && !t->skip_coef_val) { + int eoo = 0, use_eoo; +#if USE_ZPC_EOORIENT == 1 + use_eoo = vp9_use_eoo(c, seg_eob, scan, tx_size, + is_last_zero, is_eoo_list); +#else + use_eoo = 0; +#endif + if (use_eoo) { + eoo = vp9_is_eoo(c, eob, scan, tx_size, qcoeff_ptr, last_nz_pos); + if (eoo && is_eoo_negative[o]) eoo = 0; + if (eoo) { + int c_; + int savings = 0; + int zsaved = 0; + savings = + vp9_cost_bit((*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0], 1) - + vp9_cost_bit((*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0], 0); + for (c_ = c + 1; c_ < eob; ++c_) { + if (o == vp9_get_orientation(scan[c_], tx_size)) { + int pt_ = vp9_get_coef_context(scan, nb, pad, token_cache_full, + c_, default_eob); + int band_ = get_coef_band(scan, tx_size, c_); + assert(token_cache_full[scan[c_]] == ZERO_TOKEN); + if (!c_ || token_cache_full[scan[c_ - 1]]) + savings += + vp9_cost_bit(coef_probs[type][ref][band_][pt_][0], 1); + savings += vp9_cost_bit(coef_probs[type][ref][band_][pt_][1], 0); + zsaved++; + } + } + /* + if (!dry_run) + if (savings > 0) + printf("savings %d zsaved %d (%d, %d)\n", + savings, zsaved, tx_size, band); + */ + if (savings < 0) { + eoo = 0; + is_eoo_negative[o] = 1; + } + } + } + if (use_eoo) { + t++; + t->skip_eob_node = t->skip_coef_val = 0; + // transmit the eoo symbol + t->token = !eoo ? ZPC_ISOLATED : ZPC_EOORIENT; + t->context_tree = &((*zpc_probs)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0]); + if (!dry_run) + (*zpc_count)[ref] + [coef_to_zpc_band(band)] + [coef_to_zpc_ptok(pt)][0][!eoo]++; + if (eoo) { + assert(is_eoo_list[o] == 0); + is_eoo_list[o] = 1; + } + } + } + is_last_zero[o] = (token == ZERO_TOKEN); +#endif ++t; - } while (c < eob && ++c < seg_eob); +} while (c < eob && ++c < seg_eob); #if CONFIG_CODE_NONZEROCOUNT - assert(nzc == xd->nzcs[ib]); +assert(nzc == xd->nzcs[ib]); #endif *tp = t; @@ -812,6 +936,9 @@ static void stuff_b(VP9_COMP *cpi, t->token = DCT_EOB_TOKEN; t->context_tree = probs[type][ref][band][pt]; t->skip_eob_node = 0; +#if CONFIG_CODE_ZEROGROUP + t->skip_coef_val = 0; +#endif ++t; *tp = t; if (!dry_run) { diff --git a/vp9/encoder/vp9_tokenize.h b/vp9/encoder/vp9_tokenize.h index 82d798e47..da1c817a2 100644 --- a/vp9/encoder/vp9_tokenize.h +++ b/vp9/encoder/vp9_tokenize.h @@ -26,6 +26,9 @@ typedef struct { int16_t extra; uint8_t token; uint8_t skip_eob_node; +#if CONFIG_CODE_ZEROGROUP + uint8_t skip_coef_val; +#endif } TOKENEXTRA; typedef int64_t vp9_coeff_accum[REF_TYPES][COEF_BANDS][PREV_COEF_CONTEXTS]