michael@0: /* michael@0: * Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license michael@0: * that can be found in the LICENSE file in the root of the source michael@0: * tree. An additional intellectual property rights grant can be found michael@0: * in the file PATENTS. All contributing project authors may michael@0: * be found in the AUTHORS file in the root of the source tree. michael@0: */ michael@0: michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include "onyx_int.h" michael@0: #include "tokenize.h" michael@0: #include "vpx_mem/vpx_mem.h" michael@0: michael@0: /* Global event counters used for accumulating statistics across several michael@0: compressions, then generating context.c = initial stats. */ michael@0: michael@0: #ifdef VP8_ENTROPY_STATS michael@0: _int64 context_counters[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS]; michael@0: #endif michael@0: void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) ; michael@0: void vp8_fix_contexts(MACROBLOCKD *x); michael@0: michael@0: #include "dct_value_tokens.h" michael@0: #include "dct_value_cost.h" michael@0: michael@0: const TOKENVALUE *const vp8_dct_value_tokens_ptr = dct_value_tokens + michael@0: DCT_MAX_VALUE; michael@0: const short *const vp8_dct_value_cost_ptr = dct_value_cost + DCT_MAX_VALUE; michael@0: michael@0: #if 0 michael@0: int skip_true_count = 0; michael@0: int skip_false_count = 0; michael@0: #endif michael@0: michael@0: /* function used to generate dct_value_tokens and dct_value_cost tables */ michael@0: /* michael@0: static void fill_value_tokens() michael@0: { michael@0: michael@0: TOKENVALUE *t = dct_value_tokens + DCT_MAX_VALUE; michael@0: const vp8_extra_bit_struct *e = vp8_extra_bits; michael@0: michael@0: int i = -DCT_MAX_VALUE; michael@0: int sign = 1; michael@0: michael@0: do michael@0: { michael@0: if (!i) michael@0: sign = 0; michael@0: michael@0: { michael@0: const int a = sign ? -i : i; michael@0: int eb = sign; michael@0: michael@0: if (a > 4) michael@0: { michael@0: int j = 4; michael@0: michael@0: while (++j < 11 && e[j].base_val <= a) {} michael@0: michael@0: t[i].Token = --j; michael@0: eb |= (a - e[j].base_val) << 1; michael@0: } michael@0: else michael@0: t[i].Token = a; michael@0: michael@0: t[i].Extra = eb; michael@0: } michael@0: michael@0: // initialize the cost for extra bits for all possible coefficient value. michael@0: { michael@0: int cost = 0; michael@0: const vp8_extra_bit_struct *p = vp8_extra_bits + t[i].Token; michael@0: michael@0: if (p->base_val) michael@0: { michael@0: const int extra = t[i].Extra; michael@0: const int Length = p->Len; michael@0: michael@0: if (Length) michael@0: cost += vp8_treed_cost(p->tree, p->prob, extra >> 1, Length); michael@0: michael@0: cost += vp8_cost_bit(vp8_prob_half, extra & 1); // sign michael@0: dct_value_cost[i + DCT_MAX_VALUE] = cost; michael@0: } michael@0: michael@0: } michael@0: michael@0: } michael@0: while (++i < DCT_MAX_VALUE); michael@0: michael@0: vp8_dct_value_tokens_ptr = dct_value_tokens + DCT_MAX_VALUE; michael@0: vp8_dct_value_cost_ptr = dct_value_cost + DCT_MAX_VALUE; michael@0: } michael@0: */ michael@0: michael@0: static void tokenize2nd_order_b michael@0: ( michael@0: MACROBLOCK *x, michael@0: TOKENEXTRA **tp, michael@0: VP8_COMP *cpi michael@0: ) michael@0: { michael@0: MACROBLOCKD *xd = &x->e_mbd; michael@0: int pt; /* near block/prev token context index */ michael@0: int c; /* start at DC */ michael@0: TOKENEXTRA *t = *tp;/* store tokens starting here */ michael@0: const BLOCKD *b; michael@0: const short *qcoeff_ptr; michael@0: ENTROPY_CONTEXT * a; michael@0: ENTROPY_CONTEXT * l; michael@0: int band, rc, v, token; michael@0: int eob; michael@0: michael@0: b = xd->block + 24; michael@0: qcoeff_ptr = b->qcoeff; michael@0: a = (ENTROPY_CONTEXT *)xd->above_context + 8; michael@0: l = (ENTROPY_CONTEXT *)xd->left_context + 8; michael@0: eob = xd->eobs[24]; michael@0: VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); michael@0: michael@0: if(!eob) michael@0: { michael@0: /* c = band for this case */ michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; michael@0: t->skip_eob_node = 0; michael@0: michael@0: ++x->coef_counts [1] [0] [pt] [DCT_EOB_TOKEN]; michael@0: t++; michael@0: *tp = t; michael@0: *a = *l = 0; michael@0: return; michael@0: } michael@0: michael@0: v = qcoeff_ptr[0]; michael@0: t->Extra = vp8_dct_value_tokens_ptr[v].Extra; michael@0: token = vp8_dct_value_tokens_ptr[v].Token; michael@0: t->Token = token; michael@0: michael@0: t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts [1] [0] [pt] [token]; michael@0: pt = vp8_prev_token_class[token]; michael@0: t++; michael@0: c = 1; michael@0: michael@0: for (; c < eob; c++) michael@0: { michael@0: rc = vp8_default_zig_zag1d[c]; michael@0: band = vp8_coef_bands[c]; michael@0: v = qcoeff_ptr[rc]; michael@0: michael@0: t->Extra = vp8_dct_value_tokens_ptr[v].Extra; michael@0: token = vp8_dct_value_tokens_ptr[v].Token; michael@0: michael@0: t->Token = token; michael@0: t->context_tree = cpi->common.fc.coef_probs [1] [band] [pt]; michael@0: michael@0: t->skip_eob_node = ((pt == 0)); michael@0: michael@0: ++x->coef_counts [1] [band] [pt] [token]; michael@0: michael@0: pt = vp8_prev_token_class[token]; michael@0: t++; michael@0: } michael@0: if (c < 16) michael@0: { michael@0: band = vp8_coef_bands[c]; michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [1] [band] [pt]; michael@0: michael@0: t->skip_eob_node = 0; michael@0: michael@0: ++x->coef_counts [1] [band] [pt] [DCT_EOB_TOKEN]; michael@0: michael@0: t++; michael@0: } michael@0: michael@0: *tp = t; michael@0: *a = *l = 1; michael@0: michael@0: } michael@0: michael@0: static void tokenize1st_order_b michael@0: ( michael@0: MACROBLOCK *x, michael@0: TOKENEXTRA **tp, michael@0: int type, /* which plane: 0=Y no DC, 1=Y2, 2=UV, 3=Y with DC */ michael@0: VP8_COMP *cpi michael@0: ) michael@0: { michael@0: MACROBLOCKD *xd = &x->e_mbd; michael@0: unsigned int block; michael@0: const BLOCKD *b; michael@0: int pt; /* near block/prev token context index */ michael@0: int c; michael@0: int token; michael@0: TOKENEXTRA *t = *tp;/* store tokens starting here */ michael@0: const short *qcoeff_ptr; michael@0: ENTROPY_CONTEXT * a; michael@0: ENTROPY_CONTEXT * l; michael@0: int band, rc, v; michael@0: int tmp1, tmp2; michael@0: michael@0: b = xd->block; michael@0: /* Luma */ michael@0: for (block = 0; block < 16; block++, b++) michael@0: { michael@0: tmp1 = vp8_block2above[block]; michael@0: tmp2 = vp8_block2left[block]; michael@0: qcoeff_ptr = b->qcoeff; michael@0: a = (ENTROPY_CONTEXT *)xd->above_context + tmp1; michael@0: l = (ENTROPY_CONTEXT *)xd->left_context + tmp2; michael@0: michael@0: VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); michael@0: michael@0: c = type ? 0 : 1; michael@0: michael@0: if(c >= *b->eob) michael@0: { michael@0: /* c = band for this case */ michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [type] [c] [pt]; michael@0: t->skip_eob_node = 0; michael@0: michael@0: ++x->coef_counts [type] [c] [pt] [DCT_EOB_TOKEN]; michael@0: t++; michael@0: *tp = t; michael@0: *a = *l = 0; michael@0: continue; michael@0: } michael@0: michael@0: v = qcoeff_ptr[c]; michael@0: michael@0: t->Extra = vp8_dct_value_tokens_ptr[v].Extra; michael@0: token = vp8_dct_value_tokens_ptr[v].Token; michael@0: t->Token = token; michael@0: michael@0: t->context_tree = cpi->common.fc.coef_probs [type] [c] [pt]; michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts [type] [c] [pt] [token]; michael@0: pt = vp8_prev_token_class[token]; michael@0: t++; michael@0: c++; michael@0: michael@0: for (; c < *b->eob; c++) michael@0: { michael@0: rc = vp8_default_zig_zag1d[c]; michael@0: band = vp8_coef_bands[c]; michael@0: v = qcoeff_ptr[rc]; michael@0: michael@0: t->Extra = vp8_dct_value_tokens_ptr[v].Extra; michael@0: token = vp8_dct_value_tokens_ptr[v].Token; michael@0: michael@0: t->Token = token; michael@0: t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; michael@0: michael@0: t->skip_eob_node = (pt == 0); michael@0: ++x->coef_counts [type] [band] [pt] [token]; michael@0: michael@0: pt = vp8_prev_token_class[token]; michael@0: t++; michael@0: } michael@0: if (c < 16) michael@0: { michael@0: band = vp8_coef_bands[c]; michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; michael@0: michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts [type] [band] [pt] [DCT_EOB_TOKEN]; michael@0: michael@0: t++; michael@0: } michael@0: *tp = t; michael@0: *a = *l = 1; michael@0: } michael@0: michael@0: /* Chroma */ michael@0: for (block = 16; block < 24; block++, b++) michael@0: { michael@0: tmp1 = vp8_block2above[block]; michael@0: tmp2 = vp8_block2left[block]; michael@0: qcoeff_ptr = b->qcoeff; michael@0: a = (ENTROPY_CONTEXT *)xd->above_context + tmp1; michael@0: l = (ENTROPY_CONTEXT *)xd->left_context + tmp2; michael@0: michael@0: VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); michael@0: michael@0: if(!(*b->eob)) michael@0: { michael@0: /* c = band for this case */ michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; michael@0: t->skip_eob_node = 0; michael@0: michael@0: ++x->coef_counts [2] [0] [pt] [DCT_EOB_TOKEN]; michael@0: t++; michael@0: *tp = t; michael@0: *a = *l = 0; michael@0: continue; michael@0: } michael@0: michael@0: v = qcoeff_ptr[0]; michael@0: michael@0: t->Extra = vp8_dct_value_tokens_ptr[v].Extra; michael@0: token = vp8_dct_value_tokens_ptr[v].Token; michael@0: t->Token = token; michael@0: michael@0: t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts [2] [0] [pt] [token]; michael@0: pt = vp8_prev_token_class[token]; michael@0: t++; michael@0: c = 1; michael@0: michael@0: for (; c < *b->eob; c++) michael@0: { michael@0: rc = vp8_default_zig_zag1d[c]; michael@0: band = vp8_coef_bands[c]; michael@0: v = qcoeff_ptr[rc]; michael@0: michael@0: t->Extra = vp8_dct_value_tokens_ptr[v].Extra; michael@0: token = vp8_dct_value_tokens_ptr[v].Token; michael@0: michael@0: t->Token = token; michael@0: t->context_tree = cpi->common.fc.coef_probs [2] [band] [pt]; michael@0: michael@0: t->skip_eob_node = (pt == 0); michael@0: michael@0: ++x->coef_counts [2] [band] [pt] [token]; michael@0: michael@0: pt = vp8_prev_token_class[token]; michael@0: t++; michael@0: } michael@0: if (c < 16) michael@0: { michael@0: band = vp8_coef_bands[c]; michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [2] [band] [pt]; michael@0: michael@0: t->skip_eob_node = 0; michael@0: michael@0: ++x->coef_counts [2] [band] [pt] [DCT_EOB_TOKEN]; michael@0: michael@0: t++; michael@0: } michael@0: *tp = t; michael@0: *a = *l = 1; michael@0: } michael@0: } michael@0: michael@0: michael@0: static int mb_is_skippable(MACROBLOCKD *x, int has_y2_block) michael@0: { michael@0: int skip = 1; michael@0: int i = 0; michael@0: michael@0: if (has_y2_block) michael@0: { michael@0: for (i = 0; i < 16; i++) michael@0: skip &= (x->eobs[i] < 2); michael@0: } michael@0: michael@0: for (; i < 24 + has_y2_block; i++) michael@0: skip &= (!x->eobs[i]); michael@0: michael@0: return skip; michael@0: } michael@0: michael@0: michael@0: void vp8_tokenize_mb(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) michael@0: { michael@0: MACROBLOCKD *xd = &x->e_mbd; michael@0: int plane_type; michael@0: int has_y2_block; michael@0: michael@0: has_y2_block = (xd->mode_info_context->mbmi.mode != B_PRED michael@0: && xd->mode_info_context->mbmi.mode != SPLITMV); michael@0: michael@0: xd->mode_info_context->mbmi.mb_skip_coeff = michael@0: mb_is_skippable(xd, has_y2_block); michael@0: if (xd->mode_info_context->mbmi.mb_skip_coeff) michael@0: { michael@0: if (!cpi->common.mb_no_coeff_skip) michael@0: { michael@0: vp8_stuff_mb(cpi, x, t); michael@0: } michael@0: else michael@0: { michael@0: vp8_fix_contexts(xd); michael@0: x->skip_true_count++; michael@0: } michael@0: michael@0: return; michael@0: } michael@0: michael@0: plane_type = 3; michael@0: if(has_y2_block) michael@0: { michael@0: tokenize2nd_order_b(x, t, cpi); michael@0: plane_type = 0; michael@0: } michael@0: michael@0: tokenize1st_order_b(x, t, plane_type, cpi); michael@0: } michael@0: michael@0: michael@0: #ifdef VP8_ENTROPY_STATS michael@0: michael@0: void init_context_counters(void) michael@0: { michael@0: vpx_memset(context_counters, 0, sizeof(context_counters)); michael@0: } michael@0: michael@0: void print_context_counters() michael@0: { michael@0: michael@0: int type, band, pt, t; michael@0: michael@0: FILE *const f = fopen("context.c", "w"); michael@0: michael@0: fprintf(f, "#include \"entropy.h\"\n"); michael@0: michael@0: fprintf(f, "\n/* *** GENERATED FILE: DO NOT EDIT *** */\n\n"); michael@0: michael@0: fprintf(f, "int Contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS];\n\n"); michael@0: michael@0: fprintf(f, "const int default_contexts[BLOCK_TYPES] [COEF_BANDS] [PREV_COEF_CONTEXTS] [MAX_ENTROPY_TOKENS] = {"); michael@0: michael@0: # define Comma( X) (X? ",":"") michael@0: michael@0: type = 0; michael@0: michael@0: do michael@0: { michael@0: fprintf(f, "%s\n { /* block Type %d */", Comma(type), type); michael@0: michael@0: band = 0; michael@0: michael@0: do michael@0: { michael@0: fprintf(f, "%s\n { /* Coeff Band %d */", Comma(band), band); michael@0: michael@0: pt = 0; michael@0: michael@0: do michael@0: { michael@0: fprintf(f, "%s\n {", Comma(pt)); michael@0: michael@0: t = 0; michael@0: michael@0: do michael@0: { michael@0: const _int64 x = context_counters [type] [band] [pt] [t]; michael@0: const int y = (int) x; michael@0: michael@0: assert(x == (_int64) y); /* no overflow handling yet */ michael@0: fprintf(f, "%s %d", Comma(t), y); michael@0: michael@0: } michael@0: while (++t < MAX_ENTROPY_TOKENS); michael@0: michael@0: fprintf(f, "}"); michael@0: } michael@0: while (++pt < PREV_COEF_CONTEXTS); michael@0: michael@0: fprintf(f, "\n }"); michael@0: michael@0: } michael@0: while (++band < COEF_BANDS); michael@0: michael@0: fprintf(f, "\n }"); michael@0: } michael@0: while (++type < BLOCK_TYPES); michael@0: michael@0: fprintf(f, "\n};\n"); michael@0: fclose(f); michael@0: } michael@0: #endif michael@0: michael@0: michael@0: static void stuff2nd_order_b michael@0: ( michael@0: TOKENEXTRA **tp, michael@0: ENTROPY_CONTEXT *a, michael@0: ENTROPY_CONTEXT *l, michael@0: VP8_COMP *cpi, michael@0: MACROBLOCK *x michael@0: ) michael@0: { michael@0: int pt; /* near block/prev token context index */ michael@0: TOKENEXTRA *t = *tp; /* store tokens starting here */ michael@0: VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); michael@0: michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [1] [0] [pt]; michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts [1] [0] [pt] [DCT_EOB_TOKEN]; michael@0: ++t; michael@0: michael@0: *tp = t; michael@0: pt = 0; michael@0: *a = *l = pt; michael@0: } michael@0: michael@0: static void stuff1st_order_b michael@0: ( michael@0: TOKENEXTRA **tp, michael@0: ENTROPY_CONTEXT *a, michael@0: ENTROPY_CONTEXT *l, michael@0: int type, michael@0: VP8_COMP *cpi, michael@0: MACROBLOCK *x michael@0: ) michael@0: { michael@0: int pt; /* near block/prev token context index */ michael@0: int band; michael@0: TOKENEXTRA *t = *tp; /* store tokens starting here */ michael@0: VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); michael@0: band = type ? 0 : 1; michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [type] [band] [pt]; michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts [type] [band] [pt] [DCT_EOB_TOKEN]; michael@0: ++t; michael@0: *tp = t; michael@0: pt = 0; /* 0 <-> all coeff data is zero */ michael@0: *a = *l = pt; michael@0: } michael@0: michael@0: static michael@0: void stuff1st_order_buv michael@0: ( michael@0: TOKENEXTRA **tp, michael@0: ENTROPY_CONTEXT *a, michael@0: ENTROPY_CONTEXT *l, michael@0: VP8_COMP *cpi, michael@0: MACROBLOCK *x michael@0: ) michael@0: { michael@0: int pt; /* near block/prev token context index */ michael@0: TOKENEXTRA *t = *tp; /* store tokens starting here */ michael@0: VP8_COMBINEENTROPYCONTEXTS(pt, *a, *l); michael@0: michael@0: t->Token = DCT_EOB_TOKEN; michael@0: t->context_tree = cpi->common.fc.coef_probs [2] [0] [pt]; michael@0: t->skip_eob_node = 0; michael@0: ++x->coef_counts[2] [0] [pt] [DCT_EOB_TOKEN]; michael@0: ++t; michael@0: *tp = t; michael@0: pt = 0; /* 0 <-> all coeff data is zero */ michael@0: *a = *l = pt; michael@0: } michael@0: michael@0: void vp8_stuff_mb(VP8_COMP *cpi, MACROBLOCK *x, TOKENEXTRA **t) michael@0: { michael@0: MACROBLOCKD *xd = &x->e_mbd; michael@0: ENTROPY_CONTEXT * A = (ENTROPY_CONTEXT *)xd->above_context; michael@0: ENTROPY_CONTEXT * L = (ENTROPY_CONTEXT *)xd->left_context; michael@0: int plane_type; michael@0: int b; michael@0: plane_type = 3; michael@0: if((xd->mode_info_context->mbmi.mode != B_PRED michael@0: && xd->mode_info_context->mbmi.mode != SPLITMV)) michael@0: { michael@0: stuff2nd_order_b(t, michael@0: A + vp8_block2above[24], L + vp8_block2left[24], cpi, x); michael@0: plane_type = 0; michael@0: } michael@0: michael@0: for (b = 0; b < 16; b++) michael@0: stuff1st_order_b(t, michael@0: A + vp8_block2above[b], michael@0: L + vp8_block2left[b], plane_type, cpi, x); michael@0: michael@0: for (b = 16; b < 24; b++) michael@0: stuff1st_order_buv(t, michael@0: A + vp8_block2above[b], michael@0: L + vp8_block2left[b], cpi, x); michael@0: michael@0: } michael@0: void vp8_fix_contexts(MACROBLOCKD *x) michael@0: { michael@0: /* Clear entropy contexts for Y2 blocks */ michael@0: if (x->mode_info_context->mbmi.mode != B_PRED && x->mode_info_context->mbmi.mode != SPLITMV) michael@0: { michael@0: vpx_memset(x->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); michael@0: vpx_memset(x->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)); michael@0: } michael@0: else michael@0: { michael@0: vpx_memset(x->above_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)-1); michael@0: vpx_memset(x->left_context, 0, sizeof(ENTROPY_CONTEXT_PLANES)-1); michael@0: } michael@0: michael@0: }