Mercurial > libavcodec.hg
changeset 5821:51918cb97f6f libavcodec
add support for VP6 with huffman encoded blocks
closes issue 104
author | aurel |
---|---|
date | Sun, 14 Oct 2007 22:30:59 +0000 |
parents | ffac546a3861 |
children | b49be74d387c |
files | Makefile vp5.c vp56.h vp56data.c vp6.c vp6data.h |
diffstat | 6 files changed, 148 insertions(+), 13 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Sun Oct 14 21:19:40 2007 +0000 +++ b/Makefile Sun Oct 14 22:30:59 2007 +0000 @@ -195,9 +195,9 @@ OBJS-$(CONFIG_VORBIS_ENCODER) += vorbis_enc.o vorbis.o vorbis_data.o mdct.o fft.o OBJS-$(CONFIG_VP3_DECODER) += vp3.o vp3dsp.o OBJS-$(CONFIG_VP5_DECODER) += vp5.o vp56.o vp56data.o vp3dsp.o -OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp3dsp.o -OBJS-$(CONFIG_VP6A_DECODER) += vp6.o vp56.o vp56data.o vp3dsp.o -OBJS-$(CONFIG_VP6F_DECODER) += vp6.o vp56.o vp56data.o vp3dsp.o +OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o vp3dsp.o huffman.o +OBJS-$(CONFIG_VP6A_DECODER) += vp6.o vp56.o vp56data.o vp3dsp.o huffman.o +OBJS-$(CONFIG_VP6F_DECODER) += vp6.o vp56.o vp56data.o vp3dsp.o huffman.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o OBJS-$(CONFIG_WMAV1_DECODER) += wmadec.o wma.o mdct.o fft.o
--- a/vp5.c Sun Oct 14 21:19:40 2007 +0000 +++ b/vp5.c Sun Oct 14 22:30:59 2007 +0000 @@ -205,7 +205,7 @@ s->coeff_ctx[vp56_b6to4[b]][coeff_idx] = 4; idx = vp56_rac_get_tree(c, vp56_pc_tree, model1); sign = vp56_rac_get(c); - coeff = vp56_coeff_bias[idx]; + coeff = vp56_coeff_bias[idx+5]; for (i=vp56_coeff_bit_length[idx]; i>=0; i--) coeff += vp56_rac_get_prob(c, vp56_coeff_parse_table[idx][i]) << i; } else {
--- a/vp56.h Sun Oct 14 21:19:40 2007 +0000 +++ b/vp56.h Sun Oct 14 22:30:59 2007 +0000 @@ -157,6 +157,14 @@ vp56_model_t *modelp; vp56_model_t models[2]; + + /* huffman decoding */ + int use_huffman; + GetBitContext gb; + VLC dccv_vlc[2]; + VLC runv_vlc[2]; + VLC ract_vlc[2][3][6]; + unsigned int nb_null[2][2]; /* number of consecutive NULL DC/AC */ };
--- a/vp56data.c Sun Oct 14 21:19:40 2007 +0000 +++ b/vp56data.c Sun Oct 14 22:30:59 2007 +0000 @@ -62,5 +62,5 @@ { 2,10}, {-4}, {-5}, }; -const uint8_t vp56_coeff_bias[] = { 5, 7, 11, 19, 35, 67 }; +const uint8_t vp56_coeff_bias[] = { 0, 1, 2, 3, 4, 5, 7, 11, 19, 35, 67 }; const uint8_t vp56_coeff_bit_length[] = { 0, 1, 2, 3, 4, 10 };
--- a/vp6.c Sun Oct 14 21:19:40 2007 +0000 +++ b/vp6.c Sun Oct 14 22:30:59 2007 +0000 @@ -30,6 +30,7 @@ #include "avcodec.h" #include "dsputil.h" #include "bitstream.h" +#include "huffman.h" #include "mpegvideo.h" #include "vp56.h" @@ -37,6 +38,9 @@ #include "vp6data.h" +static void vp6_parse_coeff(vp56_context_t *s); +static void vp6_parse_coeff_huffman(vp56_context_t *s); + static int vp6_parse_header(vp56_context_t *s, uint8_t *buf, int buf_size, int *golden_frame) { @@ -126,14 +130,19 @@ s->filter_selection = 16; } - if (vp56_rac_get(c)) - av_log(s->avctx, AV_LOG_WARNING, - "alternative entropy decoding not supported\n"); + s->use_huffman = vp56_rac_get(c); + s->parse_coeff = vp6_parse_coeff; if (coeff_offset) { - vp56_init_range_decoder(&s->cc, buf+coeff_offset, - buf_size-coeff_offset); - s->ccp = &s->cc; + buf += coeff_offset; + buf_size -= coeff_offset; + if (s->use_huffman) { + s->parse_coeff = vp6_parse_coeff_huffman; + init_get_bits(&s->gb, buf, buf_size); + } else { + vp56_init_range_decoder(&s->cc, buf, buf_size); + s->ccp = &s->cc; + } } else { s->ccp = &s->c; } @@ -194,6 +203,31 @@ model->vector_fdv[comp][node] = vp56_rac_gets_nn(c, 7); } +static int vp6_huff_cmp(const void *va, const void *vb) +{ + const Node *a = va, *b = vb; + return a->count >= b->count; +} + +static void vp6_build_huff_tree(vp56_context_t *s, uint8_t coeff_model[], + const uint8_t *map, unsigned size, VLC *vlc) +{ + Node nodes[2*size], *tmp = &nodes[size]; + int a, b, i; + + /* first compute probabilities from model */ + tmp[0].count = 256; + for (i=0; i<size-1; i++) { + a = tmp[i].count * coeff_model[i] >> 8; + b = tmp[i].count * (255 - coeff_model[i]) >> 8; + nodes[map[2*i ]].count = a + !a; + nodes[map[2*i+1]].count = b + !b; + } + + /* then build the huffman tree accodring to probabilities */ + ff_huff_build_tree(s->avctx, vlc, size, nodes, vp6_huff_cmp, 1); +} + static void vp6_parse_coeff_models(vp56_context_t *s) { vp56_range_coder_t *c = &s->c; @@ -237,11 +271,26 @@ model->coeff_ract[pt][ct][cg][node] = def_prob[node]; } + if (s->use_huffman) { + for (pt=0; pt<2; pt++) { + vp6_build_huff_tree(s, model->coeff_dccv[pt], + vp6_huff_coeff_map, 12, &s->dccv_vlc[pt]); + vp6_build_huff_tree(s, model->coeff_runv[pt], + vp6_huff_run_map, 9, &s->runv_vlc[pt]); + for (ct=0; ct<3; ct++) + for (cg = 0; cg < 6; cg++) + vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg], + vp6_huff_coeff_map, 12, + &s->ract_vlc[pt][ct][cg]); + } + memset(s->nb_null, 0, sizeof(s->nb_null)); + } else { /* coeff_dcct is a linear combination of coeff_dccv */ for (pt=0; pt<2; pt++) for (ctx=0; ctx<3; ctx++) for (node=0; node<5; node++) model->coeff_dcct[pt][ctx][node] = av_clip(((model->coeff_dccv[pt][node] * vp6_dccv_lc[ctx][node][0] + 128) >> 8) + vp6_dccv_lc[ctx][node][1], 1, 255); + } } static void vp6_parse_vector_adjustment(vp56_context_t *s, vp56_mv_t *vect) @@ -282,6 +331,77 @@ } } +/** + * Read number of consecutive blocks with null DC or AC. + * This value is < 74. + */ +static unsigned vp6_get_nb_null(vp56_context_t *s) +{ + unsigned val = get_bits(&s->gb, 2); + if (val == 2) + val += get_bits(&s->gb, 2); + else if (val == 3) { + val = get_bits1(&s->gb) << 2; + val = 6+val + get_bits(&s->gb, 2+val); + } + return val; +} + +static void vp6_parse_coeff_huffman(vp56_context_t *s) +{ + vp56_model_t *model = s->modelp; + uint8_t *permute = s->scantable.permutated; + VLC *vlc_coeff; + int coeff, sign, coeff_idx; + int b, cg, idx; + int pt = 0; /* plane type (0 for Y, 1 for U or V) */ + + for (b=0; b<6; b++) { + int ct = 0; /* code type */ + if (b > 3) pt = 1; + vlc_coeff = &s->dccv_vlc[pt]; + + for (coeff_idx=0; coeff_idx<64; ) { + int run = 1; + if (coeff_idx<2 && s->nb_null[coeff_idx][pt]) { + s->nb_null[coeff_idx][pt]--; + if (coeff_idx) + break; + } else { + coeff = get_vlc2(&s->gb, vlc_coeff->table, 9, 3); + if (coeff == 0) { + if (coeff_idx) { + int pt = (coeff_idx >= 6); + run += get_vlc2(&s->gb, s->runv_vlc[pt].table, 9, 3); + if (run >= 9) + run += get_bits(&s->gb, 6); + } else + s->nb_null[0][pt] = vp6_get_nb_null(s); + ct = 0; + } else if (coeff == 11) { /* end of block */ + if (coeff_idx == 1) /* first AC coeff ? */ + s->nb_null[1][pt] = vp6_get_nb_null(s); + break; + } else { + int coeff2 = vp56_coeff_bias[coeff]; + if (coeff > 4) + coeff2 += get_bits(&s->gb, coeff <= 9 ? coeff - 4 : 11); + ct = 1 + (coeff2 > 1); + sign = get_bits1(&s->gb); + coeff2 = (coeff2 ^ -sign) + sign; + if (coeff_idx) + coeff2 *= s->dequant_ac; + idx = model->coeff_index_to_pos[coeff_idx]; + s->block_coeff[b][permute[idx]] = coeff2; + } + } + coeff_idx+=run; + cg = FFMIN(vp6_coeff_groups[coeff_idx], 3); + vlc_coeff = &s->ract_vlc[pt][ct][cg]; + } + } +} + static void vp6_parse_coeff(vp56_context_t *s) { vp56_range_coder_t *c = s->ccp; @@ -309,7 +429,7 @@ if (vp56_rac_get_prob(c, model2[2])) { if (vp56_rac_get_prob(c, model2[3])) { idx = vp56_rac_get_tree(c, vp56_pc_tree, model1); - coeff = vp56_coeff_bias[idx]; + coeff = vp56_coeff_bias[idx+5]; for (i=vp56_coeff_bit_length[idx]; i>=0; i--) coeff += vp56_rac_get_prob(c, vp56_coeff_parse_table[idx][i]) << i; } else { @@ -500,7 +620,6 @@ s->parse_vector_adjustment = vp6_parse_vector_adjustment; s->adjust = vp6_adjust; s->filter = vp6_filter; - s->parse_coeff = vp6_parse_coeff; s->default_models_init = vp6_default_models_init; s->parse_vector_models = vp6_parse_vector_models; s->parse_coeff_models = vp6_parse_coeff_models;
--- a/vp6data.h Sun Oct 14 21:19:40 2007 +0000 +++ b/vp6data.h Sun Oct 14 22:30:59 2007 +0000 @@ -297,4 +297,12 @@ static const uint8_t vp6_coord_div[] = { 4, 4, 4, 4, 8, 8 }; +static const uint8_t vp6_huff_coeff_map[] = { + 13, 14, 11, 0, 1, 15, 16, 18, 2, 17, 3, 4, 19, 20, 5, 6, 21, 22, 7, 8, 9, 10 +}; + +static const uint8_t vp6_huff_run_map[] = { + 10, 13, 11, 12, 0, 1, 2, 3, 14, 8, 15, 16, 4, 5, 6, 7 +}; + #endif /* VP6DATA_H */