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 */