diff options
author | David Conrad <lessen42@gmail.com> | 2010-07-24 01:46:17 +0400 |
---|---|---|
committer | David Conrad <lessen42@gmail.com> | 2010-07-24 01:46:17 +0400 |
commit | fe1b5d974acf7736151e2e13f2498f4fbd6af765 (patch) | |
tree | a5135bb741533094e8824b8b9ff63659aa43a811 /libavcodec/vp8.c | |
parent | 5474ec2ac8a4964c4d6a0b51cd00a0ec2e7bb9a6 (diff) |
Decode DCT tokens by branching to a different code path for each branch
on the huffman tree, instead of traversing the tree in a while loop.
Based on the similar optimization in libvpx's detokenize.c
10% faster at normal bitrates, and 30% faster for high-bitrate intra-only
Originally committed as revision 24468 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/vp8.c')
-rw-r--r-- | libavcodec/vp8.c | 69 |
1 files changed, 47 insertions, 22 deletions
diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index 81447c4fd8..acdaf56b03 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -800,36 +800,61 @@ static int decode_block_coeffs(VP56RangeCoder *c, DCTELEM block[16], uint8_t probs[8][3][NUM_DCT_TOKENS-1], int i, int zero_nhood, int16_t qmul[2]) { - int token, nonzero = 0; - int offset = 0; + uint8_t *token_prob; + int nonzero = 0; + int coeff; - for (; i < 16; i++) { - token = vp8_rac_get_tree_with_offset(c, vp8_coeff_tree, probs[vp8_coeff_band[i]][zero_nhood], offset); + do { + token_prob = probs[vp8_coeff_band[i]][zero_nhood]; - if (token == DCT_EOB) - break; - else if (token >= DCT_CAT1) { - int cat = token-DCT_CAT1; - token = vp8_rac_get_coeff(c, vp8_dct_cat_prob[cat]); - token += 3 + (2<<cat); - } + if (!vp56_rac_get_prob_branchy(c, token_prob[0])) // DCT_EOB + return nonzero; - // after the first token, the non-zero prediction context becomes - // based on the last decoded coeff - if (!token) { +skip_eob: + if (!vp56_rac_get_prob_branchy(c, token_prob[1])) { // DCT_0 zero_nhood = 0; - offset = 1; - continue; - } else if (token == 1) + token_prob = probs[vp8_coeff_band[++i]][0]; + if (i < 16) + goto skip_eob; + return nonzero; // invalid input; blocks should end with EOB + } + + if (!vp56_rac_get_prob_branchy(c, token_prob[2])) { // DCT_1 + coeff = 1; zero_nhood = 1; - else + } else { zero_nhood = 2; + if (!vp56_rac_get_prob_branchy(c, token_prob[3])) { // DCT 2,3,4 + coeff = vp56_rac_get_prob(c, token_prob[4]); + if (coeff) + coeff += vp56_rac_get_prob(c, token_prob[5]); + coeff += 2; + } else { + // DCT_CAT* + if (!vp56_rac_get_prob_branchy(c, token_prob[6])) { + if (!vp56_rac_get_prob_branchy(c, token_prob[7])) { // DCT_CAT1 + coeff = 5 + vp56_rac_get_prob(c, vp8_dct_cat1_prob[0]); + } else { // DCT_CAT2 + coeff = 7; + coeff += vp56_rac_get_prob(c, vp8_dct_cat2_prob[0]) << 1; + coeff += vp56_rac_get_prob(c, vp8_dct_cat2_prob[1]); + } + } else { // DCT_CAT3 and up + int a = vp56_rac_get_prob(c, token_prob[8]); + int b = vp56_rac_get_prob(c, token_prob[9+a]); + int cat = (a<<1) + b; + coeff = 3 + (8<<cat); + coeff += vp8_rac_get_coeff(c, vp8_dct_cat_prob[cat]); + } + } + } + // todo: full [16] qmat? load into register? - block[zigzag_scan[i]] = (vp8_rac_get(c) ? -token : token) * qmul[!!i]; - nonzero = i+1; - offset = 0; - } + block[zigzag_scan[i]] = (vp8_rac_get(c) ? -coeff : coeff) * qmul[!!i]; + nonzero = ++i; + } while (i < 16); + return nonzero; } |