diff mbox

[FFmpeg-devel,PATCHv4] VP4 video decoder

Message ID cc16ab5c75f74f98576b566470bf2a90a16a7fb9.1558424325.git.pross@xvid.org
State New
Headers show

Commit Message

Peter Ross May 21, 2019, 7:44 a.m. UTC
---

what's changed:
* apply #if CONFIG_VP4_DECODER around large vp4 code blocks
* improved vp4_read_mb_value thanks to reminars suggestions
* improved configure vp3_decoder_select


 Changelog               |    1 +
 configure               |    1 +
 doc/general.texi        |    2 +
 libavcodec/Makefile     |    1 +
 libavcodec/allcodecs.c  |    1 +
 libavcodec/avcodec.h    |    1 +
 libavcodec/codec_desc.c |    7 +
 libavcodec/vp3.c        |  746 ++++++++++++++++++++++--
 libavcodec/vp4data.h    | 1186 +++++++++++++++++++++++++++++++++++++++
 9 files changed, 1911 insertions(+), 35 deletions(-)
 create mode 100644 libavcodec/vp4data.h

Comments

Tomas Härdin May 21, 2019, 9:34 a.m. UTC | #1
tis 2019-05-21 klockan 17:44 +1000 skrev Peter Ross:
> ---
> 
> what's changed:
> * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
> * improved vp4_read_mb_value thanks to reminars suggestions
> * improved configure vp3_decoder_select
> 
> [...]
>  
> +#define BLOCK_X (2 * mb_x + (k & 1))
> +#define BLOCK_Y (2 * mb_y + (k >> 1))
> +
> +#if CONFIG_VP4_DECODER
> +static int vp4_read_mb_value(GetBitContext *gb)
> +{
> +    int v = 1;
> +    int bits = show_bits(gb, 9);

This call to show_bits() looks unnecessary

> +    while ((bits = show_bits(gb, 9)) == 0x1ff) {
> +        skip_bits(gb, 9);
> +        v += 256;
> +    }

I have a feeling this loop should have a stop condition like v <
SOME_LARGE_VALUE, say INT_MAX-255 or yuv_macroblock_count, to reject
corrupt/malicious files and not cause undefined behavior

> +    if (bits < 0x100) {
> +        skip_bits(gb, 1);
> +    } else if (bits < 0x180) {
> +        skip_bits(gb, 2);
> +        v += 1;
> +    }
> +#define body(n) { \
> +    skip_bits(gb, 2 + n); \
> +    v += (1 << n) + get_bits(gb, n); }
> +#define else_if(thresh, n) else if (bits < thresh) body(n)
> +    else_if(0x1c0, 1)
> +    else_if(0x1e0, 2)
> +    else_if(0x1f0, 3)
> +    else_if(0x1f8, 4)
> +    else_if(0x1fc, 5)
> +    else_if(0x1fe, 6)
> +    else body(7)
> +#undef body
> +#undef else_if
> +    return v;
> +}

> @@ -1012,8 +1214,8 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
>              bits_to_get = coeff_get_bits[token];
>              if (bits_to_get)
>                  bits_to_get = get_bits(gb, bits_to_get);
> -            coeff = coeff_tables[token][bits_to_get];
>  
> +            coeff = coeff_tables[token][bits_to_get];

Stray hunk

> +#if CONFIG_VP4_DECODER
> +            if (s->version >= 2) {
> +                int mb_height, mb_width;
> +                int mb_width_mul, mb_width_div, mb_height_mul, mb_height_div;
> +
> +                mb_height = get_bits(&gb, 8);
> +                mb_width  = get_bits(&gb, 8);
> +                if (mb_height != s->macroblock_height ||
> +                    mb_width != s->macroblock_width)
> +                    av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, macroblock dimension mismatch");
> +
> +                mb_width_mul = get_bits(&gb, 5);
> +                mb_width_div = get_bits(&gb, 3);
> +                mb_height_mul = get_bits(&gb, 5);
> +                mb_height_div = get_bits(&gb, 3);
> +                if (mb_width_mul != 1 || mb_width_div != 1 || mb_height_mul != 1 || mb_height_div != 1)
> +                      av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, unexpected macroblock dimension multipler/divider");
> +
> +                if (get_bits(&gb, 2))
> +                    av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, unknown bits set");

Maybe these should be errors and/or requests for samples? It macroblock
count changes that may indicate a resolution change

/Tomas
James Almer May 21, 2019, 2:15 p.m. UTC | #2
On 5/21/2019 6:34 AM, Tomas Härdin wrote:
> tis 2019-05-21 klockan 17:44 +1000 skrev Peter Ross:
>> ---
>>
>> what's changed:
>> * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
>> * improved vp4_read_mb_value thanks to reminars suggestions
>> * improved configure vp3_decoder_select
>>
>> [...]
>>  
>> +#define BLOCK_X (2 * mb_x + (k & 1))
>> +#define BLOCK_Y (2 * mb_y + (k >> 1))
>> +
>> +#if CONFIG_VP4_DECODER
>> +static int vp4_read_mb_value(GetBitContext *gb)
>> +{
>> +    int v = 1;
>> +    int bits = show_bits(gb, 9);
> 
> This call to show_bits() looks unnecessary
> 
>> +    while ((bits = show_bits(gb, 9)) == 0x1ff) {
>> +        skip_bits(gb, 9);
>> +        v += 256;
>> +    }
> 
> I have a feeling this loop should have a stop condition like v <
> SOME_LARGE_VALUE, say INT_MAX-255 or yuv_macroblock_count, to reject
> corrupt/malicious files and not cause undefined behavior

Using get_bits_left(gb) would be better than an arbitrary large value.
Lynne May 21, 2019, 5:17 p.m. UTC | #3
May 21, 2019, 8:44 AM by pross@xvid.org <mailto:pross@xvid.org>:

> ---
>
> what's changed:
> * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
> * improved vp4_read_mb_value thanks to reminars suggestions
> * improved configure vp3_decoder_select
>
>
> Changelog               |    1 +
> configure               |    1 +
> doc/general.texi        |    2 +
> libavcodec/Makefile     |    1 +
> libavcodec/allcodecs.c  |    1 +
> libavcodec/avcodec.h    |    1 +
> libavcodec/codec_desc.c |    7 +
> libavcodec/vp3.c        |  746 ++++++++++++++++++++++--
> libavcodec/vp4data.h    | 1186 +++++++++++++++++++++++++++++++++++++++
> 9 files changed, 1911 insertions(+), 35 deletions(-)
> create mode 100644 libavcodec/vp4data.h
>

Just remove CONFIG_VP4_DECODER and make it part of the vp3 decoder.
Its unnecessary and the tables aren't big at all.
Reimar Döffinger May 21, 2019, 6:38 p.m. UTC | #4
On Tue, May 21, 2019 at 11:15:03AM -0300, James Almer wrote:
> > I have a feeling this loop should have a stop condition like v <
> > SOME_LARGE_VALUE, say INT_MAX-255 or yuv_macroblock_count, to reject
> > corrupt/malicious files and not cause undefined behavior
>
> Using get_bits_left(gb) would be better than an arbitrary large value.

It seems the original comment wasn't preserved, but get_bits_left
is fairly pointless because the 0-padding will cause loop exit
anyway.
Also get_bits_left wouldn't address the point that a 2GB input frame
of all-1s from the right position would here end up reading 2GB
9 bits at a time.
Overflow by my calculations would only happen after > 500 GB,
so not sure that's a worry.
But depending on the contexts in which this function is used,
there might be obvious limits for v, in which case an early
exit would make sense (even when not, runs > 250 bytes can
likely safely assumed broken).
Carl Eugen Hoyos May 21, 2019, 6:39 p.m. UTC | #5
Am Di., 21. Mai 2019 um 19:18 Uhr schrieb Lynne <dev@lynne.ee>:
>
> May 21, 2019, 8:44 AM by pross@xvid.org <mailto:pross@xvid.org>:
>
> > ---
> >
> > what's changed:
> > * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
> > * improved vp4_read_mb_value thanks to reminars suggestions
> > * improved configure vp3_decoder_select
> >
> >
> > Changelog               |    1 +
> > configure               |    1 +
> > doc/general.texi        |    2 +
> > libavcodec/Makefile     |    1 +
> > libavcodec/allcodecs.c  |    1 +
> > libavcodec/avcodec.h    |    1 +
> > libavcodec/codec_desc.c |    7 +
> > libavcodec/vp3.c        |  746 ++++++++++++++++++++++--
> > libavcodec/vp4data.h    | 1186 +++++++++++++++++++++++++++++++++++++++
> > 9 files changed, 1911 insertions(+), 35 deletions(-)
> > create mode 100644 libavcodec/vp4data.h
> >
>
> Just remove CONFIG_VP4_DECODER and make it part of the vp3 decoder.

Wasn't this explicitly requested in an earlier review?
(And it is common within FFmpeg)

Carl Eugen
Carl Eugen Hoyos May 21, 2019, 6:42 p.m. UTC | #6
Am Di., 21. Mai 2019 um 09:45 Uhr schrieb Peter Ross <pross@xvid.org>:

> diff --git a/configure b/configure
> index 9b4305cf0d..61eb774116 100755
> --- a/configure
> +++ b/configure
> @@ -2825,6 +2825,7 @@ vc1image_decoder_select="vc1_decoder"
>  vorbis_decoder_select="mdct"
>  vorbis_encoder_select="audio_frame_queue mdct"
>  vp3_decoder_select="hpeldsp vp3dsp videodsp"
> +vp4_decoder_select="vp3_decoder"
>  vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp"
>  vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp"
>  vp6a_decoder_select="vp6_decoder"

> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index edccd73037..d76f392f1e 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -663,6 +663,7 @@ OBJS-$(CONFIG_VORBIS_DECODER)          += vorbisdec.o vorbisdsp.o vorbis.o \
>  OBJS-$(CONFIG_VORBIS_ENCODER)          += vorbisenc.o vorbis.o \
>                                            vorbis_data.o
>  OBJS-$(CONFIG_VP3_DECODER)             += vp3.o
> +OBJS-$(CONFIG_VP4_DECODER)             += vp3.o

Imo, exactly one of these hunks should be committed.

Do you know if the claim on Wikipedia that "VP4" was only an encoder
(for VP3) was true for the actual sold software or if Wikipedia is just
wrong?

Thank you, Carl Eugen
Reimar Döffinger May 21, 2019, 7:30 p.m. UTC | #7
On Tue, May 21, 2019 at 05:44:20PM +1000, Peter Ross wrote:
> +    if (bits < 0x100) {
> +        skip_bits(gb, 1);
> +    } else if (bits < 0x180) {
> +        skip_bits(gb, 2);
> +        v += 1;
> +    }
> +#define body(n) { \
> +    skip_bits(gb, 2 + n); \
> +    v += (1 << n) + get_bits(gb, n); }
> +#define else_if(thresh, n) else if (bits < thresh) body(n)

Not sure I think the defines are great for readability,
but if you want to fully encode the logic, you could go for
e.g.
#define else_if(n) else if (bits < (0x200 - (0x80 >> n))) body(n)
Also as to the earlier discussed early bailout for the +257 case:
it seems sensible values can't really be larger than yuv_macroblock_count
and I think FFmpeg has defines for maximum frame width/height that
you could thus use to have a non-arbitrary bailout value?

> +    has_partial = 0;
> +    bit         = get_bits1(gb);
> +    current_run = vp4_read_mb_value(gb);
> +
> +    for (i = 0; i < s->yuv_macroblock_count; i++) {
> +        if (!current_run) {
> +            bit ^= 1;
> +            current_run = vp4_read_mb_value(gb);
> +        }
> +        s->superblock_coding[i] = 2 * bit;
> +        has_partial |= bit == 0;
> +        current_run--;
> +    }

This code doesn't quite look right to me.
For both of the vp4_read_mb_value weird stuff
seems to happen when it returns 0,
in the first case it directly flips bit
and reads a new value, which is stupid wasteful
encoding, in the second case current_run underflows
on current_run--, which is undefined behaviour
- or at least weird?

Except for that, isn't that the same as
   bit         = get_bits1(gb);
   for (i = 0; i < s->yuv_macroblock_count; ) {
       current_run = vp4_read_mb_value(gb);
       if (current_run > s->yuv_macroblock_count - i) -> report error?
       if (current_run == 0) current_run = s->yuv_macroblock_count - i; // maybe??
       memset(s->superblock_coding + i, 2*bit, current_run);
       has_partial |= bit == 0;
       i += current_run;
       bit ^= 1;
   }

Hm, admittedly this doesn't really make much
sense as you can't apply this trick to the has_partial
case.
But still maybe the current_run too large and 0
cases could be clarified at least.

> +                    int mb_y = 2 * sb_y + (((j >> 1) + j) & 1);

Is ^ potentially clearer than + here?

> +                    for (k = 0; k < 4; k++) {
> +                        if (BLOCK_X >= fragment_width || BLOCK_Y >= fragment_height)
> +                            continue;
> +                        fragment = s->fragment_start[plane] + BLOCK_Y * fragment_width + BLOCK_X;
> +
> +                        coded = pattern & (1 << (3 - k));

coded = pattern & (8 >> k);
maybe?

> +    if (last_motion < 0)
> +        v = -v;
> +    return v;

I'd probably be partial to using ?: here, but your decision.

> +                    if (coding_mode == 2) { /* VP4 */
> +                        motion_x[0] = vp4_get_mv(s, gb, 0, last_gold_motion_x);
> +                        motion_y[0] = vp4_get_mv(s, gb, 1, last_gold_motion_y);
> +                        last_gold_motion_x = motion_x[0];
> +                        last_gold_motion_y = motion_y[0];

Could write as
last_gold_motion_x =
motion_x[0] = vp4_get_mv(s, gb, 0, last_gold_motion_x);
I think?
But no strong opinion either.

> @@ -1012,8 +1214,8 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
>              bits_to_get = coeff_get_bits[token];
>              if (bits_to_get)
>                  bits_to_get = get_bits(gb, bits_to_get);
> -            coeff = coeff_tables[token][bits_to_get];
>
> +            coeff = coeff_tables[token][bits_to_get];

cosmetic?

> +            eob_run = eob_run_base[token];
> +            if (eob_run_get_bits[token])
[...]
> +            zero_run = zero_run_base[token];
> +            if (zero_run_get_bits[token])

If _run_base and _run_get_bits are always used together like this,
wouldn't it for readability and cache locality be better to
make it an array of structs so they are next to each other in memory?

> +            vp4_dc_predictor_reset(&dc_pred[j * 6 + i + 7]);
> +        s->dc_pred_row[sb_x * 4 + i] = dc_pred[25 + i];
> +        dc_pred[6 * i] = dc_pred[6 * i + 4];

If there's an easy way to make those constants like 6, 7 and 25
more obvious that might be a good idea.

> +    if (dc_pred[idx - 6].type == type) {
> +        dc += dc_pred[idx - 6].dc;
> +        count++;
> +    }
> +
> +    if (dc_pred[idx + 6].type == type) {
> +        dc += dc_pred[idx + 6].dc;
> +        count++;
> +    }
> +
> +    if (count != 2 && dc_pred[idx - 1].type == type) {
> +        dc += dc_pred[idx - 1].dc;
> +        count++;
> +    }
> +
> +    if (count != 2 && dc_pred[idx + 1].type == type) {
> +        dc += dc_pred[idx + 1].dc;
> +        count++;
> +    }

Maybe do dc_pred += idx at the start and then
only dc_pred[-6], dc_pred[6] etc?

> +#define loop_stride 12
> +    uint8_t loop[12 * loop_stride];

Hm, at 144 bytes, might it make sense to have in context
instead of on stack?

> +#define SHIFT(v, shift) ((v) >> (shift))
> +#define ABS_SHIFT(v, shift) ((v) > 0 ? SHIFT(v, shift) : -SHIFT(-v, shift))

Don't we have something like that already?
I think this should rather be:
(v - (v >> 31)) >> shift
?

Best regards,
Reimar Döffinger
James Almer May 21, 2019, 8:01 p.m. UTC | #8
On 5/21/2019 3:42 PM, Carl Eugen Hoyos wrote:
> Am Di., 21. Mai 2019 um 09:45 Uhr schrieb Peter Ross <pross@xvid.org>:
> 
>> diff --git a/configure b/configure
>> index 9b4305cf0d..61eb774116 100755
>> --- a/configure
>> +++ b/configure
>> @@ -2825,6 +2825,7 @@ vc1image_decoder_select="vc1_decoder"
>>  vorbis_decoder_select="mdct"
>>  vorbis_encoder_select="audio_frame_queue mdct"
>>  vp3_decoder_select="hpeldsp vp3dsp videodsp"
>> +vp4_decoder_select="vp3_decoder"
>>  vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp"
>>  vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp"
>>  vp6a_decoder_select="vp6_decoder"
> 
>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
>> index edccd73037..d76f392f1e 100644
>> --- a/libavcodec/Makefile
>> +++ b/libavcodec/Makefile
>> @@ -663,6 +663,7 @@ OBJS-$(CONFIG_VORBIS_DECODER)          += vorbisdec.o vorbisdsp.o vorbis.o \
>>  OBJS-$(CONFIG_VORBIS_ENCODER)          += vorbisenc.o vorbis.o \
>>                                            vorbis_data.o
>>  OBJS-$(CONFIG_VP3_DECODER)             += vp3.o
>> +OBJS-$(CONFIG_VP4_DECODER)             += vp3.o
> 
> Imo, exactly one of these hunks should be committed.

The configure one. It would then be the same as with the Theora decoder.

> 
> Do you know if the claim on Wikipedia that "VP4" was only an encoder
> (for VP3) was true for the actual sold software or if Wikipedia is just
> wrong?
> 
> Thank you, Carl Eugen
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
Reimar Döffinger May 22, 2019, 7:45 p.m. UTC | #9
On Tue, May 21, 2019 at 09:30:54PM +0200, Reimar Döffinger wrote:
> > +#define SHIFT(v, shift) ((v) >> (shift))
> > +#define ABS_SHIFT(v, shift) ((v) > 0 ? SHIFT(v, shift) : -SHIFT(-v, shift))
>
> Don't we have something like that already?

Seems we don't

> I think this should rather be:
> (v - (v >> 31)) >> shift
> ?

Not right for shift > 1.
But this one according to my testing is equivalent:
((a + (a >> 31)) >> b) - (a >> 31)
Not certain it will be fewer instructions,
but it is branchless.
On some ISAs the simple
a / (1 << b)
might even be faster, so maybe worth
going for that...
Peter Ross May 23, 2019, 11:22 a.m. UTC | #10
On Tue, May 21, 2019 at 08:39:59PM +0200, Carl Eugen Hoyos wrote:
> Am Di., 21. Mai 2019 um 19:18 Uhr schrieb Lynne <dev@lynne.ee>:
> >
> > May 21, 2019, 8:44 AM by pross@xvid.org <mailto:pross@xvid.org>:
> >
> > > ---
> > >
> > > what's changed:
> > > * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
> > > * improved vp4_read_mb_value thanks to reminars suggestions
> > > * improved configure vp3_decoder_select
> > >
> > >
> > > Changelog               |    1 +
> > > configure               |    1 +
> > > doc/general.texi        |    2 +
> > > libavcodec/Makefile     |    1 +
> > > libavcodec/allcodecs.c  |    1 +
> > > libavcodec/avcodec.h    |    1 +
> > > libavcodec/codec_desc.c |    7 +
> > > libavcodec/vp3.c        |  746 ++++++++++++++++++++++--
> > > libavcodec/vp4data.h    | 1186 +++++++++++++++++++++++++++++++++++++++
> > > 9 files changed, 1911 insertions(+), 35 deletions(-)
> > > create mode 100644 libavcodec/vp4data.h
> > >
> >
> > Just remove CONFIG_VP4_DECODER and make it part of the vp3 decoder.
> 
> Wasn't this explicitly requested in an earlier review?
> (And it is common within FFmpeg)

i'll leave the ifdefs inplace.

lynne has a point though, disabling vp4 only reduces the final ffmpeg binary by 25 kilobytes.

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Peter Ross May 23, 2019, 11:47 a.m. UTC | #11
On Tue, May 21, 2019 at 08:42:17PM +0200, Carl Eugen Hoyos wrote:
> Am Di., 21. Mai 2019 um 09:45 Uhr schrieb Peter Ross <pross@xvid.org>:
> 
> > diff --git a/configure b/configure
> > index 9b4305cf0d..61eb774116 100755
> > --- a/configure
> > +++ b/configure
> > @@ -2825,6 +2825,7 @@ vc1image_decoder_select="vc1_decoder"
> >  vorbis_decoder_select="mdct"
> >  vorbis_encoder_select="audio_frame_queue mdct"
> >  vp3_decoder_select="hpeldsp vp3dsp videodsp"
> > +vp4_decoder_select="vp3_decoder"
> >  vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp"
> >  vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp"
> >  vp6a_decoder_select="vp6_decoder"
> 
> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > index edccd73037..d76f392f1e 100644
> > --- a/libavcodec/Makefile
> > +++ b/libavcodec/Makefile
> > @@ -663,6 +663,7 @@ OBJS-$(CONFIG_VORBIS_DECODER)          += vorbisdec.o vorbisdsp.o vorbis.o \
> >  OBJS-$(CONFIG_VORBIS_ENCODER)          += vorbisenc.o vorbis.o \
> >                                            vorbis_data.o
> >  OBJS-$(CONFIG_VP3_DECODER)             += vp3.o
> > +OBJS-$(CONFIG_VP4_DECODER)             += vp3.o
> 
> Imo, exactly one of these hunks should be committed.

thanks.

> Do you know if the claim on Wikipedia that "VP4" was only an encoder
> (for VP3) was true for the actual sold software or if Wikipedia is just
> wrong?

VP4 was a "new" encoder and decoder. New in quotes because nothing is truely
new in this industry.

the VP4 software was initially not available to the public. eventually on2
provided a community version. there were VfW binaries. thre was also a
real-media player plugin dll, but unfortunately i have no content for it.

yes, the VP4 bitstream is similar to VP3, but so were the VP5/6 and
VP7/8 and VP9/10 bitstreams.

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Peter Ross May 23, 2019, 11:55 a.m. UTC | #12
On Tue, May 21, 2019 at 08:38:02PM +0200, Reimar Döffinger wrote:
> On Tue, May 21, 2019 at 11:15:03AM -0300, James Almer wrote:
> > > I have a feeling this loop should have a stop condition like v <
> > > SOME_LARGE_VALUE, say INT_MAX-255 or yuv_macroblock_count, to reject
> > > corrupt/malicious files and not cause undefined behavior
> >
> > Using get_bits_left(gb) would be better than an arbitrary large value.
> 
> It seems the original comment wasn't preserved, but get_bits_left
> is fairly pointless because the 0-padding will cause loop exit
> anyway.
> Also get_bits_left wouldn't address the point that a 2GB input frame
> of all-1s from the right position would here end up reading 2GB
> 9 bits at a time.
> Overflow by my calculations would only happen after > 500 GB,
> so not sure that's a worry.
> But depending on the contexts in which this function is used,
> there might be obvious limits for v, in which case an early
> exit would make sense (even when not, runs > 250 bytes can
> likely safely assumed broken).

x/y macroblock counts are limited 8-bit, so yuv_macroblock_count never
exceeds (255 * 255 * 3/2 = 97537). i this kind of check will suffice
and speed up fuzzing tests.

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Peter Ross May 23, 2019, 11:57 a.m. UTC | #13
On Wed, May 22, 2019 at 09:45:46PM +0200, Reimar Döffinger wrote:
> On Tue, May 21, 2019 at 09:30:54PM +0200, Reimar Döffinger wrote:
> > > +#define SHIFT(v, shift) ((v) >> (shift))
> > > +#define ABS_SHIFT(v, shift) ((v) > 0 ? SHIFT(v, shift) : -SHIFT(-v, shift))
> >
> > Don't we have something like that already?
> 
> Seems we don't
> 
> > I think this should rather be:
> > (v - (v >> 31)) >> shift
> > ?
> 
> Not right for shift > 1.
> But this one according to my testing is equivalent:
> ((a + (a >> 31)) >> b) - (a >> 31)
> Not certain it will be fewer instructions,
> but it is branchless.

> On some ISAs the simple
> a / (1 << b)

this is best, and the compiler can decode. thanks.

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Peter Ross May 23, 2019, noon UTC | #14
On Tue, May 21, 2019 at 11:34:34AM +0200, Tomas Härdin wrote:
> tis 2019-05-21 klockan 17:44 +1000 skrev Peter Ross:
> > ---
> > 
> > what's changed:
> > * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
> > * improved vp4_read_mb_value thanks to reminars suggestions
> > * improved configure vp3_decoder_select

> > +#if CONFIG_VP4_DECODER
> > +            if (s->version >= 2) {
> > +                int mb_height, mb_width;
> > +                int mb_width_mul, mb_width_div, mb_height_mul, mb_height_div;
> > +
> > +                mb_height = get_bits(&gb, 8);
> > +                mb_width  = get_bits(&gb, 8);
> > +                if (mb_height != s->macroblock_height ||
> > +                    mb_width != s->macroblock_width)
> > +                    av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, macroblock dimension mismatch");
> > +
> > +                mb_width_mul = get_bits(&gb, 5);
> > +                mb_width_div = get_bits(&gb, 3);
> > +                mb_height_mul = get_bits(&gb, 5);
> > +                mb_height_div = get_bits(&gb, 3);
> > +                if (mb_width_mul != 1 || mb_width_div != 1 || mb_height_mul != 1 || mb_height_div != 1)
> > +                      av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, unexpected macroblock dimension multipler/divider");
> > +
> > +                if (get_bits(&gb, 2))
> > +                    av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, unknown bits set");
> 
> Maybe these should be errors and/or requests for samples? It macroblock
> count changes that may indicate a resolution change

agree. and no need for "VP4...:"  as it will print the context as vp4.

other items fixed. thanks.

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Lynne May 23, 2019, 12:51 p.m. UTC | #15
May 23, 2019, 12:22 PM by pross@xvid.org:

> On Tue, May 21, 2019 at 08:39:59PM +0200, Carl Eugen Hoyos wrote:
>
>> Am Di., 21. Mai 2019 um 19:18 Uhr schrieb Lynne <dev@lynne.ee>:
>> >
>> > May 21, 2019, 8:44 AM by pross@xvid.org <mailto:pross@xvid.org>:
>> >
>> > > ---
>> > >
>> > > what's changed:
>> > > * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
>> > > * improved vp4_read_mb_value thanks to reminars suggestions
>> > > * improved configure vp3_decoder_select
>> > >
>> > >
>> > > Changelog               |    1 +
>> > > configure               |    1 +
>> > > doc/general.texi        |    2 +
>> > > libavcodec/Makefile     |    1 +
>> > > libavcodec/allcodecs.c  |    1 +
>> > > libavcodec/avcodec.h    |    1 +
>> > > libavcodec/codec_desc.c |    7 +
>> > > libavcodec/vp3.c        |  746 ++++++++++++++++++++++--
>> > > libavcodec/vp4data.h    | 1186 +++++++++++++++++++++++++++++++++++++++
>> > > 9 files changed, 1911 insertions(+), 35 deletions(-)
>> > > create mode 100644 libavcodec/vp4data.h
>> > >
>> >
>> > Just remove CONFIG_VP4_DECODER and make it part of the vp3 decoder.
>>
>> Wasn't this explicitly requested in an earlier review?
>> (And it is common within FFmpeg)
>>
>
> i'll leave the ifdefs inplace.
>
> lynne has a point though, disabling vp4 only reduces the final ffmpeg binary by 25 kilobytes.
>

Do remove them then, its not that much, regardless of what was said in a previous review,
even you think so.
James Almer May 23, 2019, 1:33 p.m. UTC | #16
On 5/23/2019 9:51 AM, Lynne wrote:
> May 23, 2019, 12:22 PM by pross@xvid.org:
> 
>> On Tue, May 21, 2019 at 08:39:59PM +0200, Carl Eugen Hoyos wrote:
>>
>>> Am Di., 21. Mai 2019 um 19:18 Uhr schrieb Lynne <dev@lynne.ee>:
>>>>
>>>> May 21, 2019, 8:44 AM by pross@xvid.org <mailto:pross@xvid.org>:
>>>>
>>>>> ---
>>>>>
>>>>> what's changed:
>>>>> * apply #if CONFIG_VP4_DECODER around large vp4 code blocks
>>>>> * improved vp4_read_mb_value thanks to reminars suggestions
>>>>> * improved configure vp3_decoder_select
>>>>>
>>>>>
>>>>> Changelog               |    1 +
>>>>> configure               |    1 +
>>>>> doc/general.texi        |    2 +
>>>>> libavcodec/Makefile     |    1 +
>>>>> libavcodec/allcodecs.c  |    1 +
>>>>> libavcodec/avcodec.h    |    1 +
>>>>> libavcodec/codec_desc.c |    7 +
>>>>> libavcodec/vp3.c        |  746 ++++++++++++++++++++++--
>>>>> libavcodec/vp4data.h    | 1186 +++++++++++++++++++++++++++++++++++++++
>>>>> 9 files changed, 1911 insertions(+), 35 deletions(-)
>>>>> create mode 100644 libavcodec/vp4data.h
>>>>>
>>>>
>>>> Just remove CONFIG_VP4_DECODER and make it part of the vp3 decoder.
>>>
>>> Wasn't this explicitly requested in an earlier review?
>>> (And it is common within FFmpeg)
>>>
>>
>> i'll leave the ifdefs inplace.
>>
>> lynne has a point though, disabling vp4 only reduces the final ffmpeg binary by 25 kilobytes.
>>
> 
> Do remove them then, its not that much, regardless of what was said in a previous review,
> even you think so.

No, if the vp4 decoder can't be merged into the vp3 one, then code
exclusive for it should be wrapped in preprocessor checks, same as we're
doing with Theora.

There's a reason libavcodec is so modularized.
Peter Ross May 23, 2019, 1:38 p.m. UTC | #17
On Tue, May 21, 2019 at 09:30:54PM +0200, Reimar Döffinger wrote:
> On Tue, May 21, 2019 at 05:44:20PM +1000, Peter Ross wrote:
> > +    if (bits < 0x100) {
> > +        skip_bits(gb, 1);
> > +    } else if (bits < 0x180) {
> > +        skip_bits(gb, 2);
> > +        v += 1;
> > +    }
> > +#define body(n) { \
> > +    skip_bits(gb, 2 + n); \
> > +    v += (1 << n) + get_bits(gb, n); }
> > +#define else_if(thresh, n) else if (bits < thresh) body(n)
> 
> Not sure I think the defines are great for readability,
> but if you want to fully encode the logic, you could go for
> e.g.
> #define else_if(n) else if (bits < (0x200 - (0x80 >> n))) body(n)
> Also as to the earlier discussed early bailout for the +257 case:
> it seems sensible values can't really be larger than yuv_macroblock_count
> and I think FFmpeg has defines for maximum frame width/height that
> you could thus use to have a non-arbitrary bailout value?

discussed in other email.

> > +    has_partial = 0;
> > +    bit         = get_bits1(gb);
> > +    current_run = vp4_read_mb_value(gb);
> > +
> > +    for (i = 0; i < s->yuv_macroblock_count; i++) {
> > +        if (!current_run) {
> > +            bit ^= 1;
> > +            current_run = vp4_read_mb_value(gb);
> > +        }
> > +        s->superblock_coding[i] = 2 * bit;
> > +        has_partial |= bit == 0;
> > +        current_run--;
> > +    }
> 
> This code doesn't quite look right to me.
> For both of the vp4_read_mb_value weird stuff
> seems to happen when it returns 0,
i in the first case it directly flips bit
> and reads a new value, which is stupid wasteful
> encoding, in the second case current_run underflows
> on current_run--, which is undefined behaviour
> - or at least weird?

not quite that wasteful. vp4_read_mb_value() always returns >0.
the ==0 test occurs only when the current_run counter is exahusted, and needs to be
reloaded with vp4_read_mb_value().
with your optimisation below the ==0 test is not needed.

> Except for that, isn't that the same as
>    bit         = get_bits1(gb);
>    for (i = 0; i < s->yuv_macroblock_count; ) {
>        current_run = vp4_read_mb_value(gb);
>        if (current_run > s->yuv_macroblock_count - i) -> report error?
>        if (current_run == 0) current_run = s->yuv_macroblock_count - i; // maybe??
>        memset(s->superblock_coding + i, 2*bit, current_run);
>        has_partial |= bit == 0;
>        i += current_run;
>        bit ^= 1;
>    }

this is far nicer. i will squish the i += part into the for loop.

> Hm, admittedly this doesn't really make much
> sense as you can't apply this trick to the has_partial
> case.
> But still maybe the current_run too large and 0
> cases could be clarified at least.

done.

> > +                    int mb_y = 2 * sb_y + (((j >> 1) + j) & 1);
> 
> Is ^ potentially clearer than + here?

yes:  int mb_y = 2 * sb_y + (j >> 1) ^ (j & 1);


> > +                    for (k = 0; k < 4; k++) {
> > +                        if (BLOCK_X >= fragment_width || BLOCK_Y >= fragment_height)
> > +                            continue;
> > +                        fragment = s->fragment_start[plane] + BLOCK_Y * fragment_width + BLOCK_X;
> > +
> > +                        coded = pattern & (1 << (3 - k));
> 
> coded = pattern & (8 >> k);
> maybe?
> 
> > +    if (last_motion < 0)
> > +        v = -v;
> > +    return v;
> 
> I'd probably be partial to using ?: here, but your decision.

agree. leftover from when i had #ifdef trace line everywhere.

> > +                    if (coding_mode == 2) { /* VP4 */
> > +                        motion_x[0] = vp4_get_mv(s, gb, 0, last_gold_motion_x);
> > +                        motion_y[0] = vp4_get_mv(s, gb, 1, last_gold_motion_y);
> > +                        last_gold_motion_x = motion_x[0];
> > +                        last_gold_motion_y = motion_y[0];
> 
> Could write as
> last_gold_motion_x =
> motion_x[0] = vp4_get_mv(s, gb, 0, last_gold_motion_x);
> I think?
> But no strong opinion either.

agree.

> > @@ -1012,8 +1214,8 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
> >              bits_to_get = coeff_get_bits[token];
> >              if (bits_to_get)
> >                  bits_to_get = get_bits(gb, bits_to_get);
> > -            coeff = coeff_tables[token][bits_to_get];
> >
> > +            coeff = coeff_tables[token][bits_to_get];
> 
> cosmetic?

yes.

> > +            eob_run = eob_run_base[token];
> > +            if (eob_run_get_bits[token])
> [...]
> > +            zero_run = zero_run_base[token];
> > +            if (zero_run_get_bits[token])
> 
> If _run_base and _run_get_bits are always used together like this,
> wouldn't it for readability and cache locality be better to
> make it an array of structs so they are next to each other in memory?

readability, yes. performance, maybe as those arrays are only seven bytes each.
this change also touches VP3/Theora. i want to benchmark it.

> > +            vp4_dc_predictor_reset(&dc_pred[j * 6 + i + 7]);
> > +        s->dc_pred_row[sb_x * 4 + i] = dc_pred[25 + i];
> > +        dc_pred[6 * i] = dc_pred[6 * i + 4];
> 
> If there's an easy way to make those constants like 6, 7 and 25
> more obvious that might be a good idea.

i have rewritten it as dc_pred[6][6]. this avoids all those special numbers.

> > +    if (dc_pred[idx - 6].type == type) {
> > +        dc += dc_pred[idx - 6].dc;
> > +        count++;
> > +    }
> > +
> > +    if (dc_pred[idx + 6].type == type) {
> > +        dc += dc_pred[idx + 6].dc;
> > +        count++;
> > +    }
> > +
> > +    if (count != 2 && dc_pred[idx - 1].type == type) {
> > +        dc += dc_pred[idx - 1].dc;
> > +        count++;
> > +    }
> > +
> > +    if (count != 2 && dc_pred[idx + 1].type == type) {
> > +        dc += dc_pred[idx + 1].dc;
> > +        count++;
> > +    }
> 
> Maybe do dc_pred += idx at the start and then
> only dc_pred[-6], dc_pred[6] etc?

we can go one step further and remove idx, by using a pointer to the current block:

VP4Predictor *this_dc_pred = &dc_pred[hy + 1][hx + 1];
...
vp4_dc_pred(s, this_dc_pred, last_dc, dc_block_type, plane);


remiar greatly appreciate yours (and others) time taken to review this stuff.
in a few days i will post the revised patch.

cheers,

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
diff mbox

Patch

diff --git a/Changelog b/Changelog
index e6b209ae0a..1c4e02d3aa 100644
--- a/Changelog
+++ b/Changelog
@@ -30,6 +30,7 @@  version <next>:
 - colorhold filter
 - xmedian filter
 - asr filter
+- VP4 video decoder
 
 
 version 4.1:
diff --git a/configure b/configure
index 9b4305cf0d..61eb774116 100755
--- a/configure
+++ b/configure
@@ -2825,6 +2825,7 @@  vc1image_decoder_select="vc1_decoder"
 vorbis_decoder_select="mdct"
 vorbis_encoder_select="audio_frame_queue mdct"
 vp3_decoder_select="hpeldsp vp3dsp videodsp"
+vp4_decoder_select="vp3_decoder"
 vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp"
 vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp"
 vp6a_decoder_select="vp6_decoder"
diff --git a/doc/general.texi b/doc/general.texi
index ec437230e3..ed3cdfcf99 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -944,6 +944,8 @@  following image formats are supported:
     @tab Video encoding used in NuppelVideo files.
 @item On2 VP3                @tab     @tab  X
     @tab still experimental
+@item On2 VP4                @tab     @tab  X
+    @tab fourcc: VP40
 @item On2 VP5                @tab     @tab  X
     @tab fourcc: VP50
 @item On2 VP6                @tab     @tab  X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index edccd73037..d76f392f1e 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -663,6 +663,7 @@  OBJS-$(CONFIG_VORBIS_DECODER)          += vorbisdec.o vorbisdsp.o vorbis.o \
 OBJS-$(CONFIG_VORBIS_ENCODER)          += vorbisenc.o vorbis.o \
                                           vorbis_data.o
 OBJS-$(CONFIG_VP3_DECODER)             += vp3.o
+OBJS-$(CONFIG_VP4_DECODER)             += vp3.o
 OBJS-$(CONFIG_VP5_DECODER)             += vp5.o vp56.o vp56data.o vp56rac.o
 OBJS-$(CONFIG_VP6_DECODER)             += vp6.o vp56.o vp56data.o \
                                           vp6dsp.o vp56rac.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 6178d31b5c..d2f9a39ce5 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -330,6 +330,7 @@  extern AVCodec ff_vcr1_decoder;
 extern AVCodec ff_vmdvideo_decoder;
 extern AVCodec ff_vmnc_decoder;
 extern AVCodec ff_vp3_decoder;
+extern AVCodec ff_vp4_decoder;
 extern AVCodec ff_vp5_decoder;
 extern AVCodec ff_vp6_decoder;
 extern AVCodec ff_vp6a_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index b749946633..586bbbca4e 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -456,6 +456,7 @@  enum AVCodecID {
     AV_CODEC_ID_ARBC,
     AV_CODEC_ID_AGM,
     AV_CODEC_ID_LSCR,
+    AV_CODEC_ID_VP4,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 621b16e160..4d033c20ff 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1719,6 +1719,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"),
         .props     = AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_VP4,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "vp4",
+        .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* various PCM "codecs" */
     {
diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c
index b248c90413..5fe2c2477c 100644
--- a/libavcodec/vp3.c
+++ b/libavcodec/vp3.c
@@ -1,5 +1,6 @@ 
 /*
  * Copyright (C) 2003-2004 The FFmpeg project
+ * Copyright (C) 2019 Peter Ross
  *
  * This file is part of FFmpeg.
  *
@@ -20,7 +21,7 @@ 
 
 /**
  * @file
- * On2 VP3 Video Decoder
+ * On2 VP3/VP4 Video Decoder
  *
  * VP3 Video Decoder by Mike Melanson (mike at multimedia.cx)
  * For more information about the VP3 coding process, visit:
@@ -43,6 +44,7 @@ 
 #include "thread.h"
 #include "videodsp.h"
 #include "vp3data.h"
+#include "vp4data.h"
 #include "vp3dsp.h"
 #include "xiph.h"
 
@@ -127,6 +129,30 @@  static const uint8_t hilbert_offset[16][2] = {
     { 3, 1 }, { 2, 1 }, { 2, 0 }, { 3, 0 }
 };
 
+enum {
+    VP4_DC_INTRA  = 0,
+    VP4_DC_INTER  = 1,
+    VP4_DC_GOLDEN = 2,
+    NB_VP4_DC_TYPES,
+    VP4_DC_UNDEFINED = NB_VP4_DC_TYPES
+};
+
+static const uint8_t vp4_pred_block_type_map[8] = {
+    [MODE_INTER_NO_MV]      = VP4_DC_INTER,
+    [MODE_INTRA]            = VP4_DC_INTRA,
+    [MODE_INTER_PLUS_MV]    = VP4_DC_INTER,
+    [MODE_INTER_LAST_MV]    = VP4_DC_INTER,
+    [MODE_INTER_PRIOR_LAST] = VP4_DC_INTER,
+    [MODE_USING_GOLDEN]     = VP4_DC_GOLDEN,
+    [MODE_GOLDEN_MV]        = VP4_DC_GOLDEN,
+    [MODE_INTER_FOURMV]     = VP4_DC_INTER,
+};
+
+typedef struct {
+    int dc;
+    int type;
+} VP4Predictor;
+
 #define MIN_DEQUANT_VAL 2
 
 typedef struct Vp3DecodeContext {
@@ -164,9 +190,13 @@  typedef struct Vp3DecodeContext {
     int v_superblock_start;
     unsigned char *superblock_coding;
 
-    int macroblock_count;
+    int macroblock_count; /* y macroblock count */
     int macroblock_width;
     int macroblock_height;
+    int c_macroblock_count;
+    int c_macroblock_width;
+    int c_macroblock_height;
+    int yuv_macroblock_count; /* y+u+v macroblock count */
 
     int fragment_count;
     int fragment_width[2];
@@ -182,7 +212,7 @@  typedef struct Vp3DecodeContext {
     int8_t (*motion_val[2])[2];
 
     /* tables */
-    uint16_t coded_dc_scale_factor[64];
+    uint16_t coded_dc_scale_factor[2][64];
     uint32_t coded_ac_scale_factor[64];
     uint8_t base_matrix[384][64];
     uint8_t qr_count[2][3];
@@ -233,10 +263,12 @@  typedef struct Vp3DecodeContext {
     VLC ac_vlc_3[16];
     VLC ac_vlc_4[16];
 
-    VLC superblock_run_length_vlc;
-    VLC fragment_run_length_vlc;
+    VLC superblock_run_length_vlc; /* version < 2 */
+    VLC fragment_run_length_vlc; /* version < 2 */
+    VLC block_pattern_vlc[2]; /* version >= 2*/
     VLC mode_code_vlc;
-    VLC motion_vector_vlc;
+    VLC motion_vector_vlc; /* version < 2 */
+    VLC vp4_mv_vlc[2][7]; /* version >=2 */
 
     /* these arrays need to be on 16-byte boundaries since SSE2 operations
      * index into them */
@@ -263,6 +295,8 @@  typedef struct Vp3DecodeContext {
 
     uint8_t filter_limit_values[64];
     DECLARE_ALIGNED(8, int, bounding_values_array)[256 + 2];
+
+    VP4Predictor * dc_pred_row; /* dc_pred_row[y_superblock_width * 4] */
 } Vp3DecodeContext;
 
 /************************************************************************
@@ -280,6 +314,7 @@  static av_cold void free_tables(AVCodecContext *avctx)
     av_freep(&s->dct_tokens_base);
     av_freep(&s->superblock_fragments);
     av_freep(&s->macroblock_coding);
+    av_freep(&s->dc_pred_row);
     av_freep(&s->motion_val[0]);
     av_freep(&s->motion_val[1]);
 }
@@ -299,7 +334,7 @@  static void vp3_decode_flush(AVCodecContext *avctx)
 static av_cold int vp3_decode_end(AVCodecContext *avctx)
 {
     Vp3DecodeContext *s = avctx->priv_data;
-    int i;
+    int i, j;
 
     free_tables(avctx);
     av_freep(&s->edge_emu_buffer);
@@ -328,6 +363,12 @@  static av_cold int vp3_decode_end(AVCodecContext *avctx)
     ff_free_vlc(&s->mode_code_vlc);
     ff_free_vlc(&s->motion_vector_vlc);
 
+    for (j = 0; j < 2; j++)
+        for (i = 0; i < 7; i++)
+            ff_free_vlc(&s->vp4_mv_vlc[j][i]);
+
+    for (i = 0; i < 2; i++)
+        ff_free_vlc(&s->block_pattern_vlc[i]);
     return 0;
 }
 
@@ -375,11 +416,11 @@  static int init_block_mapping(Vp3DecodeContext *s)
 static void init_dequantizer(Vp3DecodeContext *s, int qpi)
 {
     int ac_scale_factor = s->coded_ac_scale_factor[s->qps[qpi]];
-    int dc_scale_factor = s->coded_dc_scale_factor[s->qps[qpi]];
     int i, plane, inter, qri, bmi, bmj, qistart;
 
     for (inter = 0; inter < 2; inter++) {
         for (plane = 0; plane < 3; plane++) {
+            int dc_scale_factor = s->coded_dc_scale_factor[!!plane][s->qps[qpi]];
             int sum = 0;
             for (qri = 0; qri < s->qr_count[inter][plane]; qri++) {
                 sum += s->qr_size[inter][plane][qri];
@@ -397,9 +438,10 @@  static void init_dequantizer(Vp3DecodeContext *s, int qpi)
 
                 int qmin   = 8 << (inter + !i);
                 int qscale = i ? ac_scale_factor : dc_scale_factor;
-
+                int qbias = (1 + inter) * 3;
                 s->qmat[qpi][inter][plane][s->idct_permutation[i]] =
-                    av_clip((qscale * coeff) / 100 * 4, qmin, 4096);
+                    (i == 0 || s->version < 2) ? av_clip((qscale * coeff) / 100 * 4, qmin, 4096)
+                                               : (qscale * (coeff - qbias) / 100 + qbias) * 4;
             }
             /* all DC coefficients use the same quant so as not to interfere
              * with DC prediction */
@@ -598,6 +640,141 @@  static int unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb)
     return 0;
 }
 
+#define BLOCK_X (2 * mb_x + (k & 1))
+#define BLOCK_Y (2 * mb_y + (k >> 1))
+
+#if CONFIG_VP4_DECODER
+static int vp4_read_mb_value(GetBitContext *gb)
+{
+    int v = 1;
+    int bits = show_bits(gb, 9);
+    while ((bits = show_bits(gb, 9)) == 0x1ff) {
+        skip_bits(gb, 9);
+        v += 256;
+    }
+    if (bits < 0x100) {
+        skip_bits(gb, 1);
+    } else if (bits < 0x180) {
+        skip_bits(gb, 2);
+        v += 1;
+    }
+#define body(n) { \
+    skip_bits(gb, 2 + n); \
+    v += (1 << n) + get_bits(gb, n); }
+#define else_if(thresh, n) else if (bits < thresh) body(n)
+    else_if(0x1c0, 1)
+    else_if(0x1e0, 2)
+    else_if(0x1f0, 3)
+    else_if(0x1f8, 4)
+    else_if(0x1fc, 5)
+    else_if(0x1fe, 6)
+    else body(7)
+#undef body
+#undef else_if
+    return v;
+}
+
+static int vp4_get_block_pattern(Vp3DecodeContext *s, GetBitContext *gb, int *next_block_pattern_table)
+{
+    int v = get_vlc2(gb, s->block_pattern_vlc[*next_block_pattern_table].table, 3, 2);
+    if (v == -1) {
+        av_log(s->avctx, AV_LOG_ERROR, "Invalid block pattern\n");
+        *next_block_pattern_table = 0;
+        return 0;
+    }
+    *next_block_pattern_table = vp4_block_pattern_table_selector[v];
+    return v + 1;
+}
+
+static int vp4_unpack_macroblocks(Vp3DecodeContext *s, GetBitContext *gb)
+{
+    int plane, i, j, k, fragment;
+    int next_block_pattern_table;
+    int bit, current_run, has_partial;
+
+    memset(s->macroblock_coding, MODE_COPY, s->macroblock_count);
+
+    if (s->keyframe)
+        return 0;
+
+    has_partial = 0;
+    bit         = get_bits1(gb);
+    current_run = vp4_read_mb_value(gb);
+
+    for (i = 0; i < s->yuv_macroblock_count; i++) {
+        if (!current_run) {
+            bit ^= 1;
+            current_run = vp4_read_mb_value(gb);
+        }
+        s->superblock_coding[i] = 2 * bit;
+        has_partial |= bit == 0;
+        current_run--;
+    }
+
+    if (has_partial) {
+        bit  = get_bits1(gb);
+        current_run = vp4_read_mb_value(gb);
+        for (i = 0; i < s->yuv_macroblock_count; i++) {
+            if (!s->superblock_coding[i]) {
+                if (!current_run) {
+                    bit ^= 1;
+                    current_run = vp4_read_mb_value(gb);
+                }
+                s->superblock_coding[i] = bit;
+                current_run--;
+            }
+        }
+    }
+
+    next_block_pattern_table = 0;
+    i = 0;
+    for (plane = 0; plane < 3; plane++) {
+        int sb_x, sb_y;
+        int sb_width = plane ? s->c_superblock_width : s->y_superblock_width;
+        int sb_height = plane ? s->c_superblock_height : s->y_superblock_height;
+        int mb_width = plane ? s->c_macroblock_width : s->macroblock_width;
+        int mb_height = plane ? s->c_macroblock_height : s->macroblock_height;
+        int fragment_width = s->fragment_width[!!plane];
+        int fragment_height = s->fragment_height[!!plane];
+
+        for (sb_y = 0; sb_y < sb_height; sb_y++) {
+            for (sb_x = 0; sb_x < sb_width; sb_x++) {
+                for (j = 0; j < 4; j++) {
+                    int mb_x = 2 * sb_x + (j >> 1);
+                    int mb_y = 2 * sb_y + (((j >> 1) + j) & 1);
+                    int mb_coded, pattern, coded;
+
+                    if (mb_x >= mb_width || mb_y >= mb_height)
+                        continue;
+
+                    mb_coded = s->superblock_coding[i++];
+
+                    if (mb_coded == SB_FULLY_CODED)
+                        pattern = 0xF;
+                    else if (mb_coded == SB_PARTIALLY_CODED)
+                        pattern = vp4_get_block_pattern(s, gb, &next_block_pattern_table);
+                    else
+                        pattern = 0;
+
+                    for (k = 0; k < 4; k++) {
+                        if (BLOCK_X >= fragment_width || BLOCK_Y >= fragment_height)
+                            continue;
+                        fragment = s->fragment_start[plane] + BLOCK_Y * fragment_width + BLOCK_X;
+
+                        coded = pattern & (1 << (3 - k));
+
+                        /* MODE_INTER_NO_MV is the default for coded fragments.
+                           the actual method is decoded in the next phase. */
+                        s->all_fragments[fragment].coding_method = coded ? MODE_INTER_NO_MV : MODE_COPY;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+#endif
+
 /*
  * This function unpacks all the coding mode data for individual macroblocks
  * from the bitstream.
@@ -646,8 +823,6 @@  static int unpack_modes(Vp3DecodeContext *s, GetBitContext *gb)
                         mb_y >= s->macroblock_height)
                         continue;
 
-#define BLOCK_X (2 * mb_x + (k & 1))
-#define BLOCK_Y (2 * mb_y + (k >> 1))
                     /* coding modes are only stored if the macroblock has
                      * at least one luma block coded, otherwise it must be
                      * INTER_NO_MV */
@@ -707,6 +882,15 @@  static int unpack_modes(Vp3DecodeContext *s, GetBitContext *gb)
     return 0;
 }
 
+static int vp4_get_mv(Vp3DecodeContext *s, GetBitContext *gb, int axis, int last_motion)
+{
+    int v = get_vlc2(gb, s->vp4_mv_vlc[axis][vp4_mv_table_selector[FFABS(last_motion)]].table, 6, 2);
+    v -= 31;
+    if (last_motion < 0)
+        v = -v;
+    return v;
+}
+
 /*
  * This function unpacks all the motion vectors for the individual
  * macroblocks from the bitstream.
@@ -721,6 +905,8 @@  static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
     int last_motion_y = 0;
     int prior_last_motion_x = 0;
     int prior_last_motion_y = 0;
+    int last_gold_motion_x = 0;
+    int last_gold_motion_y = 0;
     int current_macroblock;
     int current_fragment;
     int frag;
@@ -728,8 +914,8 @@  static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
     if (s->keyframe)
         return 0;
 
-    /* coding mode 0 is the VLC scheme; 1 is the fixed code scheme */
-    coding_mode = get_bits1(gb);
+    /* coding mode 0 is the VLC scheme; 1 is the fixed code scheme; 2 is VP4 code scheme */
+    coding_mode = s->version < 2 ? get_bits1(gb) : 2;
 
     /* iterate through all of the macroblocks that contain 1 or more
      * coded fragments */
@@ -749,15 +935,25 @@  static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
                     continue;
 
                 switch (s->macroblock_coding[current_macroblock]) {
-                case MODE_INTER_PLUS_MV:
                 case MODE_GOLDEN_MV:
+                    if (coding_mode == 2) { /* VP4 */
+                        motion_x[0] = vp4_get_mv(s, gb, 0, last_gold_motion_x);
+                        motion_y[0] = vp4_get_mv(s, gb, 1, last_gold_motion_y);
+                        last_gold_motion_x = motion_x[0];
+                        last_gold_motion_y = motion_y[0];
+                        break;
+                    } /* otherwise fall through */
+                case MODE_INTER_PLUS_MV:
                     /* all 6 fragments use the same motion vector */
                     if (coding_mode == 0) {
                         motion_x[0] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)];
                         motion_y[0] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)];
-                    } else {
+                    } else if (coding_mode == 1) {
                         motion_x[0] = fixed_motion_vector_table[get_bits(gb, 6)];
                         motion_y[0] = fixed_motion_vector_table[get_bits(gb, 6)];
+                    } else { /* VP4 */
+                        motion_x[0] = vp4_get_mv(s, gb, 0, last_motion_x);
+                        motion_y[0] = vp4_get_mv(s, gb, 1, last_motion_y);
                     }
 
                     /* vector maintenance, only on MODE_INTER_PLUS_MV */
@@ -782,9 +978,12 @@  static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
                             if (coding_mode == 0) {
                                 motion_x[k] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)];
                                 motion_y[k] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)];
-                            } else {
+                            } else if (coding_mode == 1) {
                                 motion_x[k] = fixed_motion_vector_table[get_bits(gb, 6)];
                                 motion_y[k] = fixed_motion_vector_table[get_bits(gb, 6)];
+                            } else { /* VP4 */
+                                motion_x[k] = vp4_get_mv(s, gb, 0, prior_last_motion_x);
+                                motion_y[k] = vp4_get_mv(s, gb, 1, prior_last_motion_y);
                             }
                             last_motion_x = motion_x[k];
                             last_motion_y = motion_y[k];
@@ -846,8 +1045,10 @@  static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
                         motion_y[0] = RSHIFT(motion_y[0] + motion_y[1] +
                                              motion_y[2] + motion_y[3], 2);
                     }
-                    motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1);
-                    motion_y[0] = (motion_y[0] >> 1) | (motion_y[0] & 1);
+                    if (s->version <= 2) {
+                        motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1);
+                        motion_y[0] = (motion_y[0] >> 1) | (motion_y[0] & 1);
+                    }
                     frag = mb_y * s->fragment_width[1] + mb_x;
                     s->motion_val[1][frag][0] = motion_x[0];
                     s->motion_val[1][frag][1] = motion_y[0];
@@ -861,9 +1062,10 @@  static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb)
                         motion_x[1] = motion_x[0];
                         motion_y[1] = motion_y[0];
                     }
-                    motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1);
-                    motion_x[1] = (motion_x[1] >> 1) | (motion_x[1] & 1);
-
+                    if (s->version <= 2) {
+                        motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1);
+                        motion_x[1] = (motion_x[1] >> 1) | (motion_x[1] & 1);
+                    }
                     frag = 2 * mb_y * s->fragment_width[1] + mb_x;
                     for (k = 0; k < 2; k++) {
                         s->motion_val[1][frag][0] = motion_x[k];
@@ -1012,8 +1214,8 @@  static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
             bits_to_get = coeff_get_bits[token];
             if (bits_to_get)
                 bits_to_get = get_bits(gb, bits_to_get);
-            coeff = coeff_tables[token][bits_to_get];
 
+            coeff = coeff_tables[token][bits_to_get];
             zero_run = zero_run_base[token];
             if (zero_run_get_bits[token])
                 zero_run += get_bits(gb, zero_run_get_bits[token]);
@@ -1168,6 +1370,244 @@  static int unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb)
     return 0;
 }
 
+#if CONFIG_VP4_DECODER
+/**
+ * eob_tracker[] is instead of TOKEN_EOB(value)
+ * a dummy TOKEN_EOB(0) value is used to make vp3_dequant work
+ *
+ * @return < 0 on error
+ */
+static int vp4_unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb,
+                       VLC *vlc_tables[64],
+                       int plane, int eob_tracker[64], int fragment)
+{
+    int token;
+    int zero_run  = 0;
+    int16_t coeff = 0;
+    int bits_to_get;
+    int coeff_i = 0;
+    int eob_run;
+
+    while (!eob_tracker[coeff_i]) {
+
+        token = get_vlc2(gb, vlc_tables[coeff_i]->table, 11, 3);
+
+        /* use the token to get a zero run, a coefficient, and an eob run */
+        if ((unsigned) token <= 6U) {
+            eob_run = eob_run_base[token];
+            if (eob_run_get_bits[token])
+                eob_run += get_bits(gb, eob_run_get_bits[token]);
+            *s->dct_tokens[plane][coeff_i]++ = TOKEN_EOB(0);
+            eob_tracker[coeff_i] = eob_run - 1;
+            return 0;
+        } else if (token >= 0) {
+            bits_to_get = coeff_get_bits[token];
+
+            if (bits_to_get)
+                bits_to_get = get_bits(gb, bits_to_get);
+            coeff = coeff_tables[token][bits_to_get];
+
+            zero_run = zero_run_base[token];
+            if (zero_run_get_bits[token])
+                zero_run += get_bits(gb, zero_run_get_bits[token]);
+
+            if (zero_run) {
+                if (coeff_i + zero_run > 64) {
+                    av_log(s->avctx, AV_LOG_DEBUG,
+                        "Invalid zero run of %d with %d coeffs left\n",
+                        zero_run, 64 - coeff_i);
+                    zero_run = 64 - coeff_i;
+                }
+                *s->dct_tokens[plane][coeff_i]++ = TOKEN_ZERO_RUN(coeff, zero_run);
+                coeff_i += zero_run;
+            } else {
+                if (!coeff_i)
+                    s->all_fragments[fragment].dc = coeff;
+
+                *s->dct_tokens[plane][coeff_i]++ = TOKEN_COEFF(coeff);
+            }
+            coeff_i++;
+            if (coeff_i >= 64) /* > 64 occurs when there is a zero_run overflow */
+                return 0; /* stop */
+        } else {
+            av_log(s->avctx, AV_LOG_ERROR, "Invalid token %d\n", token);
+            return -1;
+        }
+    }
+    *s->dct_tokens[plane][coeff_i]++ = TOKEN_EOB(0);
+    eob_tracker[coeff_i]--;
+    return 0;
+}
+
+static void vp4_dc_predictor_reset(VP4Predictor *p)
+{
+    p->dc = 0;
+    p->type = VP4_DC_UNDEFINED;
+}
+
+static void vp4_dc_pred_before(const Vp3DecodeContext *s, VP4Predictor * dc_pred, int sb_x)
+{
+    int i, j;
+
+    for (i = 0; i < 4; i++)
+        dc_pred[i + 1] = s->dc_pred_row[sb_x * 4 + i];
+
+    for (j = 0; j < 4; j++)
+        for (i = 0; i < 4; i++)
+            vp4_dc_predictor_reset(&dc_pred[j * 6 + i + 7]);
+}
+
+static void vp4_dc_pred_after(Vp3DecodeContext *s, VP4Predictor * dc_pred, int sb_x)
+{
+    int i;
+
+    for (i = 0; i < 4; i++)
+        s->dc_pred_row[sb_x * 4 + i] = dc_pred[25 + i];
+
+    for (i = 1; i < 5; i++)
+        dc_pred[6 * i] = dc_pred[6 * i + 4];
+}
+
+static int vp4_dc_pred(const Vp3DecodeContext *s, const VP4Predictor * dc_pred, const int * last_dc, int idx, int type, int plane)
+{
+    int count = 0;
+    int dc = 0;
+
+    if (dc_pred[idx - 6].type == type) {
+        dc += dc_pred[idx - 6].dc;
+        count++;
+    }
+
+    if (dc_pred[idx + 6].type == type) {
+        dc += dc_pred[idx + 6].dc;
+        count++;
+    }
+
+    if (count != 2 && dc_pred[idx - 1].type == type) {
+        dc += dc_pred[idx - 1].dc;
+        count++;
+    }
+
+    if (count != 2 && dc_pred[idx + 1].type == type) {
+        dc += dc_pred[idx + 1].dc;
+        count++;
+    }
+
+    return count == 2 ? dc / count : last_dc[type];
+}
+
+static void vp4_set_tokens_base(Vp3DecodeContext *s)
+{
+    int plane, i;
+    int16_t *base = s->dct_tokens_base;
+    for (plane = 0; plane < 3; plane++) {
+        for (i = 0; i < 64; i++) {
+            s->dct_tokens[plane][i] = base;
+            base += s->fragment_width[!!plane] * s->fragment_height[!!plane];
+        }
+    }
+}
+
+static int vp4_unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb)
+{
+    int i, j;
+    int dc_y_table;
+    int dc_c_table;
+    int ac_y_table;
+    int ac_c_table;
+    VLC *tables[2][64];
+    int plane, sb_y, sb_x;
+    int eob_tracker[64];
+    VP4Predictor dc_pred[6 * 6];
+    int last_dc[NB_VP4_DC_TYPES];
+
+    if (get_bits_left(gb) < 16)
+        return AVERROR_INVALIDDATA;
+
+    /* fetch the DC table indexes */
+    dc_y_table = get_bits(gb, 4);
+    dc_c_table = get_bits(gb, 4);
+
+    ac_y_table = get_bits(gb, 4);
+    ac_c_table = get_bits(gb, 4);
+
+    /* build tables of DC/AC VLC tables */
+
+    tables[0][0] = &s->dc_vlc[dc_y_table];
+    tables[1][0] = &s->dc_vlc[dc_c_table];
+    for (i = 1; i <= 5; i++) {
+        tables[0][i] = &s->ac_vlc_1[ac_y_table];
+        tables[1][i] = &s->ac_vlc_1[ac_c_table];
+    }
+    for (i = 6; i <= 14; i++) {
+        tables[0][i] = &s->ac_vlc_2[ac_y_table];
+        tables[1][i] = &s->ac_vlc_2[ac_c_table];
+    }
+    for (i = 15; i <= 27; i++) {
+        tables[0][i] = &s->ac_vlc_3[ac_y_table];
+        tables[1][i] = &s->ac_vlc_3[ac_c_table];
+    }
+    for (i = 28; i <= 63; i++) {
+        tables[0][i] = &s->ac_vlc_4[ac_y_table];
+        tables[1][i] = &s->ac_vlc_4[ac_c_table];
+    }
+
+    vp4_set_tokens_base(s);
+
+    memset(last_dc, 0, sizeof(last_dc));
+
+    for (plane = 0; plane < ((s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 1 : 3); plane++) {
+        memset(eob_tracker, 0, sizeof(eob_tracker));
+
+        /* initialise dc prediction */
+        for (i = 0; i < s->fragment_width[!!plane]; i++)
+            vp4_dc_predictor_reset(&s->dc_pred_row[i]);
+
+        for (i = 1; i < 35; i++)
+            vp4_dc_predictor_reset(&dc_pred[i]);
+
+        for (sb_y = 0; sb_y * 4 < s->fragment_height[!!plane]; sb_y++) {
+            for (sb_x = 0; sb_x *4 < s->fragment_width[!!plane]; sb_x++) {
+                vp4_dc_pred_before(s, dc_pred, sb_x);
+                for (j = 0; j < 16; j++) {
+                        int hx = hilbert_offset[j][0];
+                        int hy = hilbert_offset[j][1];
+                        int x  = 4 * sb_x + hilbert_offset[j][0];
+                        int y  = 4 * sb_y + hilbert_offset[j][1];
+                        int fragment, dc_block_idx, dc_block_type;
+
+                        if (x >= s->fragment_width[!!plane] || y >= s->fragment_height[!!plane])
+                            continue;
+
+                        fragment = s->fragment_start[plane] + y * s->fragment_width[!!plane] + x;
+
+                        if (s->all_fragments[fragment].coding_method == MODE_COPY)
+                            continue;
+
+                        if (vp4_unpack_vlcs(s, gb, tables[!!plane], plane, eob_tracker, fragment) < 0)
+                            return -1;
+
+                        dc_block_idx = 6 * (hy + 1) + (hx + 1);
+                        dc_block_type = vp4_pred_block_type_map[s->all_fragments[fragment].coding_method];
+
+                        s->all_fragments[fragment].dc +=
+                            vp4_dc_pred(s, dc_pred, last_dc, dc_block_idx, dc_block_type, plane);
+
+                        dc_pred[dc_block_idx].type = dc_block_type;
+                        dc_pred[dc_block_idx].dc   =
+                        last_dc[dc_block_type]     = s->all_fragments[fragment].dc;
+                }
+                vp4_dc_pred_after(s, dc_pred, sb_x);
+            }
+        }
+    }
+
+    vp4_set_tokens_base(s);
+
+    return 0;
+}
+#endif
+
 /*
  * This function reverses the DC prediction for each coded fragment in
  * the frame. Much of this function is adapted directly from the original
@@ -1500,6 +1940,100 @@  static void await_reference_row(Vp3DecodeContext *s, Vp3Fragment *fragment,
     ff_thread_await_progress(ref_frame, ref_row, 0);
 }
 
+#if CONFIG_VP4_DECODER
+/**
+ * @return non-zero if temp (edge_emu_buffer) was populated
+ */
+static int vp4_mc_loop_filter(Vp3DecodeContext *s, int plane, int motion_x, int motion_y, int bx, int by,
+       uint8_t * motion_source, int stride, int src_x, int src_y, uint8_t *temp)
+{
+    static const int motion_shift[2] = { 1, 2 };
+    static const int subpel_mask[2]  = { 1, 3 };
+    int *bounding_values = s->bounding_values_array + 127;
+
+    int i;
+    int x, y;
+    int x2, y2;
+    int x_subpel, y_subpel;
+    int x_offset, y_offset;
+
+    int block_width = plane ? 8 : 16;
+    int plane_width  = s->width  >> (plane && s->chroma_x_shift);
+    int plane_height = s->height >> (plane && s->chroma_y_shift);
+
+#define loop_stride 12
+    uint8_t loop[12 * loop_stride];
+
+#define SHIFT(v, shift) ((v) >> (shift))
+#define ABS_SHIFT(v, shift) ((v) > 0 ? SHIFT(v, shift) : -SHIFT(-v, shift))
+    x = 8 * bx + ABS_SHIFT(motion_x, motion_shift[!!plane]);
+    y = 8 * by + ABS_SHIFT(motion_y, motion_shift[!!plane]);
+
+    x_subpel = motion_x & subpel_mask[!!plane];
+    y_subpel = motion_y & subpel_mask[!!plane];
+
+    if (x_subpel || y_subpel) {
+        x--;
+        y--;
+
+        if (x_subpel)
+            x = FFMIN(x, x + FFSIGN(motion_x));
+
+        if (y_subpel)
+            y = FFMIN(y, y + FFSIGN(motion_y));
+
+        x2 = x + block_width;
+        y2 = y + block_width;
+
+        if (x2 < 0 || x2 >= plane_width || y2 < 0 || y2 >= plane_height)
+            return 0;
+
+        x_offset = (-(x + 2) & 7) + 2;
+        y_offset = (-(y + 2) & 7) + 2;
+
+        if (x_offset > 8 + x_subpel && y_offset > 8 + y_subpel)
+            return 0;
+
+        s->vdsp.emulated_edge_mc(loop, motion_source - stride - 1,
+             loop_stride, stride,
+             12, 12, src_x - 1, src_y - 1,
+             plane_width,
+             plane_height);
+
+        if (x_offset <= 8 + x_subpel)
+            ff_vp3dsp_h_loop_filter_12(loop + x_offset, loop_stride, bounding_values);
+
+        if (y_offset <= 8 + y_subpel)
+            ff_vp3dsp_v_loop_filter_12(loop + y_offset*loop_stride, loop_stride, bounding_values);
+
+    } else {
+
+        x_offset = -x & 7;
+        y_offset = -y & 7;
+
+        if (!x_offset && !y_offset)
+            return 0;
+
+        s->vdsp.emulated_edge_mc(loop, motion_source - stride - 1,
+             loop_stride, stride,
+             12, 12, src_x - 1, src_y - 1,
+             plane_width,
+             plane_height);
+
+        if (x_offset)
+            s->vp3dsp.h_loop_filter(loop + loop_stride + x_offset + 1, loop_stride, bounding_values);
+
+        if (y_offset)
+            s->vp3dsp.v_loop_filter(loop + (y_offset + 1)*loop_stride + 1, loop_stride, bounding_values);
+    }
+
+    for (i = 0; i < 9; i++)
+        memcpy(temp + i*stride, loop + (i + 1) * loop_stride + 1, 9);
+
+    return 1;
+}
+#endif
+
 /*
  * Perform the final rendering for a particular slice of data.
  * The slice number ranges from 0..(c_superblock_height - 1).
@@ -1585,8 +2119,15 @@  static void render_slice(Vp3DecodeContext *s, int slice)
                         if ((s->all_fragments[i].coding_method > MODE_INTRA) &&
                             (s->all_fragments[i].coding_method != MODE_USING_GOLDEN)) {
                             int src_x, src_y;
+                            int standard_mc = 1;
                             motion_x = motion_val[fragment][0];
                             motion_y = motion_val[fragment][1];
+#if CONFIG_VP4_DECODER
+                            if (plane && s->version >= 2) {
+                                motion_x = (motion_x >> 1) | (motion_x & 1);
+                                motion_y = (motion_y >> 1) | (motion_y & 1);
+                            }
+#endif
 
                             src_x = (motion_x >> 1) + 8 * x;
                             src_y = (motion_y >> 1) + 8 * y;
@@ -1597,9 +2138,22 @@  static void render_slice(Vp3DecodeContext *s, int slice)
                             motion_halfpel_index |= (motion_y & 0x01) << 1;
                             motion_source        += ((motion_y >> 1) * stride);
 
-                            if (src_x < 0 || src_y < 0 ||
+#if CONFIG_VP4_DECODER
+                            if (s->version >= 2) {
+                                uint8_t *temp = s->edge_emu_buffer;
+                                if (stride < 0)
+                                    temp -= 8 * stride;
+                                if (vp4_mc_loop_filter(s, plane, motion_val[fragment][0], motion_val[fragment][1], x, y, motion_source, stride, src_x, src_y, temp)) {
+                                    motion_source = temp;
+                                    standard_mc = 0;
+                                }
+                            }
+#endif
+
+                            if (standard_mc && (
+                                src_x < 0 || src_y < 0 ||
                                 src_x + 9 >= plane_width ||
-                                src_y + 9 >= plane_height) {
+                                src_y + 9 >= plane_height)) {
                                 uint8_t *temp = s->edge_emu_buffer;
                                 if (stride < 0)
                                     temp -= 8 * stride;
@@ -1665,7 +2219,7 @@  static void render_slice(Vp3DecodeContext *s, int slice)
             }
 
             // Filter up to the last row in the superblock row
-            if (!s->skip_loop_filter)
+            if (s->version < 2 && !s->skip_loop_filter)
                 apply_loop_filter(s, plane, 4 * sb_y - !!sb_y,
                                   FFMIN(4 * sb_y + 3, fragment_height - 1));
         }
@@ -1694,7 +2248,8 @@  static av_cold int allocate_tables(AVCodecContext *avctx)
     y_fragment_count = s->fragment_width[0] * s->fragment_height[0];
     c_fragment_count = s->fragment_width[1] * s->fragment_height[1];
 
-    s->superblock_coding = av_mallocz(s->superblock_count);
+    /* superblock_coding is used by unpack_superblocks (VP3/Theora) and vp4_unpack_macroblocks (VP4) */
+    s->superblock_coding = av_mallocz(FFMAX(s->superblock_count, s->yuv_macroblock_count));
     s->all_fragments     = av_mallocz_array(s->fragment_count, sizeof(Vp3Fragment));
 
     s-> kf_coded_fragment_list = av_mallocz_array(s->fragment_count, sizeof(int));
@@ -1710,10 +2265,13 @@  static av_cold int allocate_tables(AVCodecContext *avctx)
     s->superblock_fragments = av_mallocz_array(s->superblock_count, 16 * sizeof(int));
     s->macroblock_coding    = av_mallocz(s->macroblock_count + 1);
 
+    s->dc_pred_row = av_malloc_array(s->y_superblock_width * 4, sizeof(*s->dc_pred_row));
+
     if (!s->superblock_coding    || !s->all_fragments          ||
         !s->dct_tokens_base      || !s->kf_coded_fragment_list ||
         !s->nkf_coded_fragment_list ||
         !s->superblock_fragments || !s->macroblock_coding      ||
+        !s->dc_pred_row ||
         !s->motion_val[0]        || !s->motion_val[1]) {
         vp3_decode_end(avctx);
         return -1;
@@ -1747,6 +2305,9 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
     int c_width;
     int c_height;
     int y_fragment_count, c_fragment_count;
+#if CONFIG_VP4_DECODER
+    int j;
+#endif
 
     ret = init_frames(s);
     if (ret < 0)
@@ -1754,7 +2315,9 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
 
     avctx->internal->allocate_progress = 1;
 
-    if (avctx->codec_tag == MKTAG('V', 'P', '3', '0'))
+    if (avctx->codec_tag == MKTAG('V', 'P', '4', '0'))
+        s->version = 3;
+    else if (avctx->codec_tag == MKTAG('V', 'P', '3', '0'))
         s->version = 0;
     else
         s->version = 1;
@@ -1803,6 +2366,10 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
     s->macroblock_width  = (s->width  + 15) / 16;
     s->macroblock_height = (s->height + 15) / 16;
     s->macroblock_count  = s->macroblock_width * s->macroblock_height;
+    s->c_macroblock_width  = (c_width  + 15) / 16;
+    s->c_macroblock_height = (c_height + 15) / 16;
+    s->c_macroblock_count  = s->c_macroblock_width * s->c_macroblock_height;
+    s->yuv_macroblock_count = s->macroblock_count + 2 * s->c_macroblock_count;
 
     s->fragment_width[0]  = s->width / FRAGMENT_PIXELS;
     s->fragment_height[0] = s->height / FRAGMENT_PIXELS;
@@ -1818,12 +2385,13 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
 
     if (!s->theora_tables) {
         for (i = 0; i < 64; i++) {
-            s->coded_dc_scale_factor[i] = vp31_dc_scale_factor[i];
-            s->coded_ac_scale_factor[i] = vp31_ac_scale_factor[i];
-            s->base_matrix[0][i]        = vp31_intra_y_dequant[i];
-            s->base_matrix[1][i]        = vp31_intra_c_dequant[i];
-            s->base_matrix[2][i]        = vp31_inter_dequant[i];
-            s->filter_limit_values[i]   = vp31_filter_limit_values[i];
+            s->coded_dc_scale_factor[0][i] = s->version < 2 ? vp31_dc_scale_factor[i] : vp4_y_dc_scale_factor[i];
+            s->coded_dc_scale_factor[1][i] = s->version < 2 ? vp31_dc_scale_factor[i] : vp4_uv_dc_scale_factor[i];
+            s->coded_ac_scale_factor[i] = s->version < 2 ? vp31_ac_scale_factor[i] : vp4_ac_scale_factor[i];
+            s->base_matrix[0][i]        = s->version < 2 ? vp31_intra_y_dequant[i] : vp4_generic_dequant[i];
+            s->base_matrix[1][i]        = s->version < 2 ? vp31_intra_c_dequant[i] : vp4_generic_dequant[i];
+            s->base_matrix[2][i]        = s->version < 2 ? vp31_inter_dequant[i]   : vp4_generic_dequant[i];
+            s->filter_limit_values[i]   = s->version < 2 ? vp31_filter_limit_values[i] : vp4_filter_limit_values[i];
         }
 
         for (inter = 0; inter < 2; inter++) {
@@ -1836,6 +2404,7 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
         }
 
         /* init VLC tables */
+        if (s->version < 2) {
         for (i = 0; i < 16; i++) {
             /* DC histograms */
             init_vlc(&s->dc_vlc[i], 11, 32,
@@ -1862,6 +2431,36 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
                      &ac_bias_3[i][0][1], 4, 2,
                      &ac_bias_3[i][0][0], 4, 2, 0);
         }
+#if CONFIG_VP4_DECODER
+        } else { /* version >= 2 */
+            for (i = 0; i < 16; i++) {
+                /* DC histograms */
+                init_vlc(&s->dc_vlc[i], 11, 32,
+                         &vp4_dc_bias[i][0][1], 4, 2,
+                         &vp4_dc_bias[i][0][0], 4, 2, 0);
+
+                /* group 1 AC histograms */
+                init_vlc(&s->ac_vlc_1[i], 11, 32,
+                         &vp4_ac_bias_0[i][0][1], 4, 2,
+                         &vp4_ac_bias_0[i][0][0], 4, 2, 0);
+
+                /* group 2 AC histograms */
+                init_vlc(&s->ac_vlc_2[i], 11, 32,
+                         &vp4_ac_bias_1[i][0][1], 4, 2,
+                         &vp4_ac_bias_1[i][0][0], 4, 2, 0);
+
+                /* group 3 AC histograms */
+                init_vlc(&s->ac_vlc_3[i], 11, 32,
+                         &vp4_ac_bias_2[i][0][1], 4, 2,
+                         &vp4_ac_bias_2[i][0][0], 4, 2, 0);
+
+                /* group 4 AC histograms */
+                init_vlc(&s->ac_vlc_4[i], 11, 32,
+                         &vp4_ac_bias_3[i][0][1], 4, 2,
+                         &vp4_ac_bias_3[i][0][0], 4, 2, 0);
+            }
+#endif
+        }
     } else {
         for (i = 0; i < 16; i++) {
             /* DC histograms */
@@ -1912,6 +2511,20 @@  static av_cold int vp3_decode_init(AVCodecContext *avctx)
              &motion_vector_vlc_table[0][1], 2, 1,
              &motion_vector_vlc_table[0][0], 2, 1, 0);
 
+#if CONFIG_VP4_DECODER
+    for (j = 0; j < 2; j++)
+        for (i = 0; i < 7; i++)
+            init_vlc(&s->vp4_mv_vlc[j][i], 6, 63,
+                 &vp4_mv_vlc[j][i][0][1], 4, 2,
+                 &vp4_mv_vlc[j][i][0][0], 4, 2, 0);
+
+    /* version >= 2 */
+    for (i = 0; i < 2; i++)
+        init_vlc(&s->block_pattern_vlc[i], 3, 14,
+             &vp4_block_pattern_vlc[i][0][1], 2, 1,
+             &vp4_block_pattern_vlc[i][0][0], 2, 1, 0);
+#endif
+
     return allocate_tables(avctx);
 
 vlc_fail:
@@ -2135,6 +2748,29 @@  static int vp3_decode_frame(AVCodecContext *avctx,
                 av_log(s->avctx, AV_LOG_ERROR,
                        "Warning, unsupported keyframe coding type?!\n");
             skip_bits(&gb, 2); /* reserved? */
+
+#if CONFIG_VP4_DECODER
+            if (s->version >= 2) {
+                int mb_height, mb_width;
+                int mb_width_mul, mb_width_div, mb_height_mul, mb_height_div;
+
+                mb_height = get_bits(&gb, 8);
+                mb_width  = get_bits(&gb, 8);
+                if (mb_height != s->macroblock_height ||
+                    mb_width != s->macroblock_width)
+                    av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, macroblock dimension mismatch");
+
+                mb_width_mul = get_bits(&gb, 5);
+                mb_width_div = get_bits(&gb, 3);
+                mb_height_mul = get_bits(&gb, 5);
+                mb_height_div = get_bits(&gb, 3);
+                if (mb_width_mul != 1 || mb_width_div != 1 || mb_height_mul != 1 || mb_height_div != 1)
+                      av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, unexpected macroblock dimension multipler/divider");
+
+                if (get_bits(&gb, 2))
+                    av_log(s->avctx, AV_LOG_WARNING, "VP4 header: Warning, unknown bits set");
+            }
+#endif
         }
     } else {
         if (!s->golden_frame.f->data[0]) {
@@ -2156,10 +2792,19 @@  static int vp3_decode_frame(AVCodecContext *avctx,
     memset(s->all_fragments, 0, s->fragment_count * sizeof(Vp3Fragment));
     ff_thread_finish_setup(avctx);
 
+    if (s->version < 2) {
     if (unpack_superblocks(s, &gb)) {
         av_log(s->avctx, AV_LOG_ERROR, "error in unpack_superblocks\n");
         goto error;
     }
+#if CONFIG_VP4_DECODER
+    } else {
+        if (vp4_unpack_macroblocks(s, &gb)) {
+            av_log(s->avctx, AV_LOG_ERROR, "error in vp4_unpack_macroblocks\n");
+            goto error;
+    }
+#endif
+    }
     if (unpack_modes(s, &gb)) {
         av_log(s->avctx, AV_LOG_ERROR, "error in unpack_modes\n");
         goto error;
@@ -2172,10 +2817,20 @@  static int vp3_decode_frame(AVCodecContext *avctx,
         av_log(s->avctx, AV_LOG_ERROR, "error in unpack_block_qpis\n");
         goto error;
     }
+
+    if (s->version < 2) {
     if (unpack_dct_coeffs(s, &gb)) {
         av_log(s->avctx, AV_LOG_ERROR, "error in unpack_dct_coeffs\n");
         goto error;
     }
+#if CONFIG_VP4_DECODER
+    } else {
+        if (vp4_unpack_dct_coeffs(s, &gb)) {
+            av_log(s->avctx, AV_LOG_ERROR, "error in vp4_unpack_dct_coeffs\n");
+            goto error;
+        }
+#endif
+    }
 
     for (i = 0; i < 3; i++) {
         int height = s->height >> (i && s->chroma_y_shift);
@@ -2190,6 +2845,7 @@  static int vp3_decode_frame(AVCodecContext *avctx,
         render_slice(s, i);
 
     // filter the last row
+    if (s->version < 2)
     for (i = 0; i < 3; i++) {
         int row = (s->height >> (3 + (i && s->chroma_y_shift))) - 1;
         apply_loop_filter(s, i, row, row + 1);
@@ -2274,6 +2930,7 @@  static int vp3_init_thread_copy(AVCodecContext *avctx)
     s->motion_val[0]          = NULL;
     s->motion_val[1]          = NULL;
     s->edge_emu_buffer        = NULL;
+    s->dc_pred_row            = NULL;
 
     return init_frames(s);
 }
@@ -2422,7 +3079,8 @@  static int theora_decode_tables(AVCodecContext *avctx, GetBitContext *gb)
         n = 16;
     /* dc scale factor table */
     for (i = 0; i < 64; i++)
-        s->coded_dc_scale_factor[i] = get_bits(gb, n);
+        s->coded_dc_scale_factor[0][i] =
+        s->coded_dc_scale_factor[1][i] = get_bits(gb, n);
 
     if (s->theora >= 0x030200)
         matrices = get_bits(gb, 9) + 1;
@@ -2608,3 +3266,21 @@  AVCodec ff_vp3_decoder = {
     .init_thread_copy      = ONLY_IF_THREADS_ENABLED(vp3_init_thread_copy),
     .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context),
 };
+
+#if CONFIG_VP4_DECODER
+AVCodec ff_vp4_decoder = {
+    .name                  = "vp4",
+    .long_name             = NULL_IF_CONFIG_SMALL("On2 VP4"),
+    .type                  = AVMEDIA_TYPE_VIDEO,
+    .id                    = AV_CODEC_ID_VP4,
+    .priv_data_size        = sizeof(Vp3DecodeContext),
+    .init                  = vp3_decode_init,
+    .close                 = vp3_decode_end,
+    .decode                = vp3_decode_frame,
+    .capabilities          = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DRAW_HORIZ_BAND |
+                             AV_CODEC_CAP_FRAME_THREADS,
+    .flush                 = vp3_decode_flush,
+    .init_thread_copy      = ONLY_IF_THREADS_ENABLED(vp3_init_thread_copy),
+    .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context),
+};
+#endif
diff --git a/libavcodec/vp4data.h b/libavcodec/vp4data.h
new file mode 100644
index 0000000000..69a009eff1
--- /dev/null
+++ b/libavcodec/vp4data.h
@@ -0,0 +1,1186 @@ 
+/*
+ * Copyright (C) 2019 Peter Ross
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * VP4 video decoder
+ */
+
+#ifndef AVCODEC_VP4DATA_H
+#define AVCODEC_VP4DATA_H
+
+#include <stdint.h>
+
+static const uint8_t vp4_generic_dequant[64] = {
+    16, 17, 18, 20, 22, 24, 26, 28,
+    17, 18, 20, 22, 24, 26, 28, 32,
+    18, 20, 22, 24, 26, 28, 32, 36,
+    20, 22, 24, 26, 28, 32, 36, 40,
+    22, 24, 26, 28, 32, 36, 40, 44,
+    24, 26, 28, 32, 36, 40, 44, 48,
+    26, 28, 32, 36, 40, 44, 48, 52,
+    28, 32, 36, 40, 44, 48, 52, 56
+};
+
+static const uint8_t vp4_y_dc_scale_factor[64] = {
+    180, 180, 180, 180, 180, 180, 175, 170,
+    165, 160, 157, 155, 152, 150, 147, 145,
+    142, 140, 137, 135, 132, 130, 127, 125,
+    122, 120, 117, 115, 112, 110, 107, 105,
+    102, 100,  97,  95,  92,  90,  87,  85,
+     82,  80,  77,  75,  72,  70,  67,  65,
+     62,  60,  57,  55,  52,  50,  47,  45,
+     42,  40,  37,  35,  32,  30,  27,  25
+};
+
+static const uint8_t vp4_uv_dc_scale_factor[64] = {
+    150, 150, 150, 150, 150, 150, 150, 150,
+    150, 150, 150, 150, 150, 150, 147, 145,
+    142, 140, 137, 135, 132, 130, 127, 125,
+    122, 120, 117, 115, 112, 110, 107, 105,
+    102, 100,  97,  95,  92,  90,  87,  85,
+     82,  80,  77,  75,  72,  70,  67,  65,
+     62,  60,  57,  55,  52,  50,  47,  45,
+     42,  40,  37,  35,  32,  30,  27,  25
+};
+
+static const uint16_t vp4_ac_scale_factor[64] = {
+    500, 475, 450, 430, 410, 390, 370, 350,
+    330, 315, 300, 285, 270, 260, 250, 240,
+    230, 220, 210, 200, 190, 185, 180, 170,
+    160, 150, 143, 135, 128, 120, 113, 106,
+    100,  94,  90,  85,  80,  75,  70,  66,
+     62,  57,  52,  49,  45,  41,  38,  35,
+     33,  30,  27,  24,  22,  20,  18,  16,
+     14,  12,  10,   9,   7,   6,   4,   1
+};
+
+static const uint8_t vp4_filter_limit_values[64] = {
+    30, 25, 20, 20, 15, 15, 14, 14,
+    13, 13, 12, 12, 11, 11, 10, 10,
+     9,  9,  8,  8,  7,  7,  7,  7,
+     6,  6,  6,  6,  5,  5,  5,  5,
+     4,  4,  4,  4,  3,  3,  3,  3,
+     2,  2,  2,  2,  2,  2,  2,  2,
+     2,  2,  2,  2,  2,  2,  2,  2,
+     1,  1,  1,  1,  1,  1,  1,  1
+};
+
+static const uint8_t vp4_block_pattern_table_selector[14] = {
+    0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1
+};
+
+static const uint8_t vp4_block_pattern_vlc[2][14][2] = {
+    {
+        { 0x0, 3 }, { 0xf, 4 }, { 0x9, 4 }, { 0x2, 3 },
+        { 0xd, 4 }, { 0xe, 5 }, { 0xb, 4 }, { 0x1, 3 },
+        { 0xf, 5 }, { 0x8, 4 }, { 0x6, 4 }, { 0xe, 4 },
+        { 0xc, 4 }, { 0xa, 4 }
+    },
+    {
+        { 0x7, 4 }, { 0xa, 4 }, { 0x9, 4 }, { 0xc, 4 },
+        { 0x8, 4 }, { 0xd, 5 }, { 0x0, 3 }, { 0xe, 4 },
+        { 0xc, 5 }, { 0xd, 4 }, { 0x1, 3 }, { 0xb, 4 },
+        { 0xf, 4 }, { 0x2, 3 }
+    }
+};
+
+static const uint8_t vp4_mv_table_selector[32] = {
+    0, 1, 2, 2, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4,
+    5, 5, 5, 5, 5, 5, 5, 5,
+    6, 6, 6, 6, 6, 6, 6, 6,
+};
+
+static const uint16_t vp4_mv_vlc[2][7][63][2] = {
+    { /* x-axis tables */
+        {
+            {   0x6A,  7 }, {  0x11A,  9 }, {  0x18E,  9 }, {  0x237, 10 },
+            {   0x4A,  8 }, {  0x236, 10 }, {   0x7A,  8 }, {   0xD6,  9 },
+            {   0x7E,  8 }, {  0x1FD, 10 }, {   0x8C,  8 }, {   0xD7,  9 },
+            {   0x87,  8 }, {  0x183,  9 }, {   0x3C,  7 }, {   0x61,  7 },
+            {   0x47,  7 }, {   0x69,  8 }, {   0x40,  7 }, {   0x48,  8 },
+            {   0x49,  7 }, {   0x86,  8 }, {   0x13,  6 }, {   0xD2,  8 },
+            {   0x1C,  6 }, {   0x42,  7 }, {   0x25,  6 }, {   0x1B,  6 },
+            {   0x13,  5 }, {    0x5,  4 }, {    0x0,  2 }, {    0x7,  3 },
+            {    0x5,  3 }, {   0x1B,  5 }, {   0x19,  5 }, {   0x19,  6 },
+            {    0x8,  5 }, {   0x45,  7 }, {   0x1D,  6 }, {   0xC6,  8 },
+            {   0x68,  7 }, {   0x90,  8 }, {   0x41,  7 }, {   0x4B,  8 },
+            {   0x31,  7 }, {  0x18F,  9 }, {   0x62,  7 }, {   0x3E,  7 },
+            {   0x44,  7 }, {   0x68,  8 }, {   0x30,  7 }, {  0x182,  9 },
+            {   0xC0,  8 }, {  0x1A7,  9 }, {   0x91,  8 }, {   0x92,  9 },
+            {   0x7B,  8 }, {   0xFF,  9 }, {  0x1A6,  9 }, {  0x1FC, 10 },
+            {   0x6A,  8 }, {   0x93,  9 }, {   0x6B,  7 }
+        },
+        {
+            {   0x39,  7 }, {  0x259, 10 }, {   0x1B,  8 }, {  0x1D1, 10 },
+            {  0x137,  9 }, {  0x1D0, 10 }, {   0x1A,  8 }, {  0x1B5, 10 },
+            {   0x1D,  8 }, {  0x4BC, 11 }, {   0x6C,  8 }, {   0x38,  9 },
+            {   0x71,  8 }, {   0x2D,  9 }, {   0x7D,  8 }, {   0x75,  8 },
+            {   0x19,  7 }, {   0xE9,  9 }, {   0x37,  7 }, {   0x15,  8 },
+            {   0x1E,  7 }, {   0xDB,  9 }, {   0x4C,  7 }, {   0x70,  8 },
+            {    0xD,  6 }, {    0xC,  7 }, {   0x27,  6 }, {    0x4,  6 },
+            {    0x2,  4 }, {    0x0,  4 }, {    0x5,  3 }, {    0x7,  3 },
+            {    0x6,  3 }, {    0x2,  3 }, {    0x8,  4 }, {   0x24,  6 },
+            {    0xC,  5 }, {   0x3B,  7 }, {   0x1E,  6 }, {   0x9A,  8 },
+            {    0xE,  6 }, {   0x69,  8 }, {   0x4A,  7 }, {  0x12D,  9 },
+            {   0x35,  7 }, {   0xF9,  9 }, {   0x18,  7 }, {   0x7F,  8 },
+            {    0xF,  7 }, {   0xF8,  9 }, {   0x7E,  8 }, {  0x25F, 10 },
+            {   0x68,  8 }, {   0x2C,  9 }, {   0x14,  8 }, {  0x258, 10 },
+            {  0x136,  9 }, {  0x4BD, 11 }, {  0x12E,  9 }, {  0x1B4, 10 },
+            {   0x17,  8 }, {   0x39,  9 }, {   0x1F,  7 }
+        },
+        {
+            {   0x29,  7 }, {  0x3CB, 10 }, {  0x1F5,  9 }, {  0x263, 10 },
+            {  0x1F4,  9 }, {  0x3DA, 10 }, {   0x50,  8 }, {  0x260, 10 },
+            {  0x1EC,  9 }, {  0x3D3, 10 }, {  0x109,  9 }, {  0x3D2, 10 },
+            {   0x51,  8 }, {  0x792, 11 }, {   0xF3,  8 }, {   0x9A,  8 },
+            {   0xF7,  8 }, {  0x132,  9 }, {   0xC1,  8 }, {  0x1E8,  9 },
+            {   0x2A,  7 }, {   0x85,  8 }, {   0x61,  7 }, {  0x1F7,  9 },
+            {   0x78,  7 }, {   0xC7,  8 }, {   0x23,  6 }, {   0x7C,  7 },
+            {   0x12,  5 }, {    0xB,  5 }, {    0xE,  4 }, {    0xD,  4 },
+            {    0x0,  2 }, {    0x5,  3 }, {    0x3,  3 }, {    0x4,  4 },
+            {   0x19,  5 }, {   0x20,  6 }, {   0x3F,  6 }, {   0x43,  7 },
+            {   0x62,  7 }, {   0x9F,  8 }, {   0x4E,  7 }, {  0x181,  9 },
+            {   0x2B,  7 }, {  0x137,  9 }, {   0xF5,  8 }, {   0x89,  8 },
+            {   0xC6,  8 }, {  0x262, 10 }, {   0x88,  8 }, {  0x3C8, 10 },
+            {  0x1F6,  9 }, {  0x3CA, 10 }, {   0x9E,  8 }, {  0x261, 10 },
+            {  0x136,  9 }, {  0x108,  9 }, {  0x133,  9 }, {  0x793, 11 },
+            {  0x180,  9 }, {  0x3DB, 10 }, {   0x45,  7 }
+        },
+        {
+            {    0x1,  6 }, {  0x1C7,  9 }, {   0x67,  8 }, {   0xB5,  9 },
+            {   0x66,  8 }, {  0x139,  9 }, {   0x99,  8 }, {   0xB4,  9 },
+            {   0xC3,  8 }, {  0x130,  9 }, {    0x0,  7 }, {  0x131,  9 },
+            {   0x9E,  8 }, {   0xB7,  9 }, {   0x2C,  7 }, {    0x1,  7 },
+            {   0x28,  7 }, {  0x138,  9 }, {   0x4B,  7 }, {   0x31,  8 },
+            {   0x60,  7 }, {   0x91,  8 }, {    0x3,  6 }, {   0x9D,  8 },
+            {   0x17,  6 }, {   0x4D,  7 }, {   0x31,  6 }, {   0x70,  7 },
+            {    0x7,  5 }, {   0x3A,  6 }, {    0x7,  4 }, {    0x2,  4 },
+            {    0xB,  4 }, {    0x1,  4 }, {    0xF,  4 }, {    0x8,  4 },
+            {    0xD,  4 }, {    0x4,  4 }, {    0xA,  4 }, {    0xD,  5 },
+            {   0x19,  5 }, {    0x2,  6 }, {   0x3B,  6 }, {   0x4A,  7 },
+            {   0x15,  6 }, {   0xC2,  8 }, {   0x18,  6 }, {   0x32,  7 },
+            {   0x72,  7 }, {  0x1C6,  9 }, {   0x29,  7 }, {  0x1C5,  9 },
+            {   0x49,  7 }, {  0x121,  9 }, {   0x1B,  7 }, {   0x30,  8 },
+            {   0x1A,  7 }, {  0x1C4,  9 }, {   0x9F,  8 }, {   0xB6,  9 },
+            {   0x19,  7 }, {  0x120,  9 }, {   0x73,  7 }
+        },
+        {
+            {   0x23,  6 }, {  0x1C8,  9 }, {   0x43,  8 }, {  0x110,  9 },
+            {    0xC,  7 }, {  0x153,  9 }, {   0x22,  7 }, {  0x111,  9 },
+            {    0xF,  7 }, {   0x42,  8 }, {   0x23,  7 }, {  0x1C9,  9 },
+            {   0x2A,  7 }, {   0x1B,  8 }, {   0x73,  7 }, {   0x45,  7 },
+            {   0x6E,  7 }, {   0x89,  8 }, {   0x6C,  7 }, {   0x1A,  8 },
+            {   0x6F,  7 }, {   0xB6,  8 }, {    0xB,  6 }, {   0xE5,  8 },
+            {   0x25,  6 }, {   0x20,  7 }, {   0x29,  6 }, {   0x4D,  7 },
+            {    0x2,  5 }, {   0x14,  6 }, {   0x1A,  5 }, {   0x17,  5 },
+            {   0x1E,  5 }, {   0x27,  6 }, {   0x18,  5 }, {   0x28,  6 },
+            {   0x1F,  5 }, {    0x0,  5 }, {    0x6,  4 }, {   0x10,  5 },
+            {    0x7,  4 }, {    0xB,  5 }, {    0x3,  4 }, {    0x4,  5 },
+            {   0x1D,  5 }, {   0x2C,  6 }, {   0x19,  5 }, {   0x2B,  6 },
+            {    0x9,  5 }, {   0x55,  7 }, {   0x38,  6 }, {    0xE,  7 },
+            {   0x24,  6 }, {   0xA8,  8 }, {    0xA,  6 }, {   0x99,  8 },
+            {   0x5A,  7 }, {   0x98,  8 }, {   0x6D,  7 }, {  0x152,  9 },
+            {   0x2B,  7 }, {   0xB7,  8 }, {    0x1,  5 }
+        },
+        {
+            {   0x3D,  6 }, {   0xB1,  8 }, {   0xDD,  8 }, {  0x1F6,  9 },
+            {   0xC5,  8 }, {  0x188,  9 }, {   0x37,  7 }, {   0x3F,  8 },
+            {   0x1E,  7 }, {  0x189,  9 }, {    0xF,  7 }, {   0x3E,  8 },
+            {   0x6A,  7 }, {  0x1F7,  9 }, {   0x61,  7 }, {   0x79,  7 },
+            {   0x18,  6 }, {   0xB0,  8 }, {    0xE,  6 }, {   0xB3,  8 },
+            {    0xC,  6 }, {   0xDF,  8 }, {    0x6,  6 }, {   0xDC,  8 },
+            {   0x19,  6 }, {   0xDE,  8 }, {   0x27,  6 }, {    0xE,  7 },
+            {   0x1A,  6 }, {   0x63,  7 }, {    0xF,  5 }, {    0xE,  5 },
+            {   0x14,  5 }, {   0x7C,  7 }, {   0x36,  6 }, {   0x6B,  7 },
+            {   0x3F,  6 }, {   0x60,  7 }, {    0x8,  5 }, {   0x74,  7 },
+            {    0x9,  5 }, {   0x78,  7 }, {   0x12,  5 }, {    0xD,  6 },
+            {   0x15,  5 }, {   0x2D,  6 }, {    0x2,  4 }, {   0x1C,  5 },
+            {    0x5,  4 }, {   0x3B,  6 }, {    0x0,  4 }, {   0x34,  6 },
+            {   0x19,  5 }, {   0x26,  6 }, {   0x10,  5 }, {   0x75,  7 },
+            {    0x2,  5 }, {   0x36,  7 }, {   0x23,  6 }, {   0xB2,  8 },
+            {   0x22,  6 }, {   0xFA,  8 }, {   0x17,  5 }
+        },
+        {
+            {   0x15,  5 }, {   0xDD,  8 }, {   0x3E,  7 }, {  0x16E,  9 },
+            {   0x4C,  7 }, {   0x12,  8 }, {   0x5D,  7 }, {   0xB6,  8 },
+            {   0x6F,  7 }, {  0x1F1,  9 }, {   0x69,  7 }, {  0x1F0,  9 },
+            {   0x1D,  7 }, {  0x16F,  9 }, {    0x2,  6 }, {   0x6B,  7 },
+            {    0xC,  6 }, {   0xDC,  8 }, {   0x68,  7 }, {   0x9B,  8 },
+            {   0x7D,  7 }, {   0x9A,  8 }, {    0xD,  6 }, {   0x13,  8 },
+            {    0x8,  6 }, {   0xF9,  8 }, {   0x2C,  6 }, {   0x12,  7 },
+            {   0x33,  6 }, {   0x4F,  7 }, {    0xD,  5 }, {    0x5,  5 },
+            {   0x12,  5 }, {   0x3F,  7 }, {   0x32,  6 }, {   0x13,  7 },
+            {   0x3B,  6 }, {    0x5,  6 }, {   0x2F,  6 }, {   0x5A,  7 },
+            {   0x3F,  6 }, {   0x1C,  7 }, {   0x3A,  6 }, {    0x8,  7 },
+            {   0x36,  6 }, {   0x5C,  7 }, {   0x10,  5 }, {    0x0,  5 },
+            {    0xC,  5 }, {   0x4E,  7 }, {    0x3,  5 }, {   0x6A,  7 },
+            {    0xE,  5 }, {    0x3,  6 }, {   0x14,  5 }, {   0x1E,  6 },
+            {   0x1C,  5 }, {    0xF,  6 }, {   0x18,  5 }, {   0x23,  6 },
+            {   0x1E,  5 }, {   0x22,  6 }, {    0x2,  3 }
+        }
+    },
+    { /* y-axis tables */
+        {
+            {   0x52,  7 }, {  0x14C,  9 }, {  0x1FA,  9 }, {  0x124,  9 },
+            {   0x82,  8 }, {  0x29E, 10 }, {   0x8E,  8 }, {  0x24B, 10 },
+            {   0x9C,  8 }, {  0x3F7, 10 }, {   0x86,  8 }, {  0x114,  9 },
+            {   0x83,  8 }, {  0x3A5, 10 }, {   0xFA,  8 }, {   0x4F,  7 },
+            {   0xFB,  8 }, {  0x13B,  9 }, {   0xFC,  8 }, {  0x172,  9 },
+            {   0x44,  7 }, {  0x173,  9 }, {   0x51,  7 }, {   0x87,  8 },
+            {   0x5F,  7 }, {   0xBA,  8 }, {   0x26,  6 }, {   0x5E,  7 },
+            {   0x16,  5 }, {   0x15,  5 }, {    0x6,  3 }, {    0x1,  2 },
+            {    0x0,  2 }, {   0x1C,  5 }, {   0x1E,  5 }, {   0x75,  7 },
+            {   0x3B,  6 }, {   0xFF,  8 }, {   0x25,  6 }, {   0xBB,  8 },
+            {   0x7C,  7 }, {   0x8B,  8 }, {   0x48,  7 }, {  0x171,  9 },
+            {   0x42,  7 }, {  0x14E,  9 }, {   0x46,  7 }, {   0xFE,  8 },
+            {   0x40,  7 }, {  0x13A,  9 }, {   0x93,  8 }, {  0x115,  9 },
+            {   0x8F,  8 }, {  0x3F6, 10 }, {  0x170,  9 }, {  0x29F, 10 },
+            {  0x1D1,  9 }, {  0x24A, 10 }, {  0x1D3,  9 }, {  0x3A4, 10 },
+            {  0x1D0,  9 }, {  0x14D,  9 }, {   0x50,  7 }
+        },
+        {
+            {   0xDE,  8 }, {  0x223, 10 }, {  0x136,  9 }, {  0x7C5, 11 },
+            {  0x12F,  9 }, {  0x4A1, 11 }, {  0x3D7, 10 }, {  0x7AC, 11 },
+            {  0x133,  9 }, {  0x7C4, 11 }, {  0x1B8,  9 }, {  0x222, 10 },
+            {   0x96,  8 }, {  0x251, 10 }, {   0x95,  8 }, {  0x1F0,  9 },
+            {   0xDA,  8 }, {  0x110,  9 }, {   0x9A,  8 }, {  0x360, 10 },
+            {   0xDD,  8 }, {  0x12E,  9 }, {   0x48,  7 }, {   0x92,  8 },
+            {   0x78,  7 }, {   0x98,  8 }, {   0x27,  6 }, {   0x45,  7 },
+            {   0x1A,  5 }, {   0x10,  5 }, {    0x5,  3 }, {    0x0,  2 },
+            {    0x1,  2 }, {    0xE,  4 }, {    0xC,  4 }, {   0x23,  6 },
+            {   0x3F,  6 }, {   0xF4,  8 }, {   0x7D,  7 }, {   0x89,  8 },
+            {   0x7B,  7 }, {  0x1BE,  9 }, {   0xF9,  8 }, {  0x3E3, 10 },
+            {   0xF3,  8 }, {  0x127,  9 }, {   0xDB,  8 }, {  0x1EA,  9 },
+            {   0xD9,  8 }, {  0x6E7, 11 }, {  0x1BF,  9 }, {  0x4A0, 11 },
+            {  0x1B1,  9 }, {  0x6E6, 11 }, {  0x137,  9 }, {  0x7AD, 11 },
+            {  0x126,  9 }, {  0x6C2, 11 }, {  0x132,  9 }, {  0x6C3, 11 },
+            {  0x129,  9 }, {  0x372, 10 }, {   0xF2,  8 }
+        },
+        {
+            {   0x16,  7 }, {   0x9C,  9 }, {  0x13C,  9 }, {   0x9E, 10 },
+            {  0x12B,  9 }, {   0xBA, 10 }, {  0x181,  9 }, {  0x317, 10 },
+            {   0x84,  8 }, {   0x4E,  9 }, {   0x26,  8 }, {  0x316, 10 },
+            {  0x180,  9 }, {   0x5C,  9 }, {   0xC1,  8 }, {   0x2F,  8 },
+            {   0x10,  7 }, {   0x45,  9 }, {   0x12,  7 }, {  0x189,  9 },
+            {   0x24,  7 }, {  0x13D,  9 }, {   0x66,  7 }, {   0x23,  8 },
+            {   0x67,  7 }, {   0xC6,  8 }, {   0x24,  6 }, {   0x4B,  7 },
+            {   0x11,  5 }, {   0x32,  6 }, {    0xD,  4 }, {    0x0,  3 },
+            {    0x7,  3 }, {    0x5,  3 }, {    0x3,  3 }, {    0x3,  4 },
+            {    0x5,  4 }, {   0x20,  6 }, {    0x8,  5 }, {   0x25,  7 },
+            {   0x26,  6 }, {   0x4F,  8 }, {   0x61,  7 }, {   0x2B,  8 },
+            {   0x4E,  7 }, {  0x18A,  9 }, {   0x43,  7 }, {   0x9F,  8 },
+            {   0x14,  7 }, {  0x254, 10 }, {   0x94,  8 }, {  0x310, 10 },
+            {   0x85,  8 }, {  0x311, 10 }, {   0x2A,  8 }, {   0xBB, 10 },
+            {  0x18F,  9 }, {  0x255, 10 }, {   0x9D,  9 }, {   0x9F, 10 },
+            {  0x18E,  9 }, {   0x44,  9 }, {   0x26,  7 }
+        },
+        {
+            {   0x61,  7 }, {  0x12A,  9 }, {    0xD,  8 }, {  0x3BD, 10 },
+            {   0x89,  8 }, {  0x109,  9 }, {  0x18E,  9 }, {  0x210, 10 },
+            {  0x1D3,  9 }, {  0x211, 10 }, {   0x88,  8 }, {   0x19,  9 },
+            {   0x85,  8 }, {   0x18,  9 }, {   0xE8,  8 }, {   0xCE,  8 },
+            {   0x40,  7 }, {  0x119,  9 }, {   0x45,  7 }, {  0x1D2,  9 },
+            {   0x4B,  7 }, {  0x1DD,  9 }, {   0x62,  7 }, {   0x94,  8 },
+            {   0x75,  7 }, {    0xC,  7 }, {   0x27,  6 }, {    0xD,  7 },
+            {    0x2,  5 }, {   0x26,  6 }, {    0x6,  4 }, {   0x1E,  5 },
+            {    0xD,  4 }, {   0x1F,  5 }, {    0x1,  3 }, {    0xA,  4 },
+            {    0x2,  3 }, {    0x7,  4 }, {    0xB,  4 }, {    0x0,  5 },
+            {   0x1C,  5 }, {   0x76,  7 }, {   0x32,  6 }, {    0x7,  7 },
+            {   0x24,  6 }, {   0xC0,  8 }, {    0x7,  6 }, {   0x41,  7 },
+            {    0x2,  6 }, {  0x18F,  9 }, {   0x47,  7 }, {  0x1DC,  9 },
+            {   0x43,  7 }, {  0x12B,  9 }, {   0xCF,  8 }, {  0x118,  9 },
+            {   0xC6,  8 }, {  0x3BC, 10 }, {   0x8D,  8 }, {  0x3BF, 10 },
+            {   0xC1,  8 }, {  0x3BE, 10 }, {   0x66,  7 }
+        },
+        {
+            {    0x7,  6 }, {  0x14D,  9 }, {   0xA0,  8 }, {   0x9E,  9 },
+            {   0xCF,  8 }, {  0x39C, 10 }, {   0xA1,  8 }, {  0x39D, 10 },
+            {   0xAB,  8 }, {  0x1C5,  9 }, {   0x26,  7 }, {  0x14C,  9 },
+            {   0x25,  7 }, {  0x19C,  9 }, {   0x3F,  7 }, {   0xE1,  8 },
+            {   0x66,  7 }, {  0x1CF,  9 }, {   0x3E,  7 }, {  0x1C4,  9 },
+            {   0x72,  7 }, {   0x4E,  8 }, {    0x6,  6 }, {   0xAA,  8 },
+            {   0x1C,  6 }, {   0xE6,  8 }, {   0x32,  6 }, {   0x51,  7 },
+            {   0x3B,  6 }, {    0x5,  6 }, {   0x1F,  5 }, {   0x18,  5 },
+            {    0x2,  4 }, {   0x3A,  6 }, {    0x0,  4 }, {   0x36,  6 },
+            {    0x5,  4 }, {    0x8,  5 }, {    0x8,  4 }, {   0x16,  5 },
+            {    0x9,  4 }, {    0xD,  5 }, {    0x3,  4 }, {   0x2F,  6 },
+            {   0x1E,  5 }, {   0x2E,  6 }, {   0x1A,  5 }, {   0x2B,  6 },
+            {    0xC,  5 }, {   0x24,  7 }, {   0x1E,  6 }, {   0xE0,  8 },
+            {    0x4,  6 }, {   0xA7,  8 }, {   0x54,  7 }, {  0x1C7,  9 },
+            {   0x52,  7 }, {  0x19D,  9 }, {   0x3A,  7 }, {   0x9F,  9 },
+            {   0x3B,  7 }, {  0x1C6,  9 }, {   0x37,  6 }
+        },
+        {
+            {   0x2A,  6 }, {   0x39,  8 }, {   0x25,  7 }, {  0x115,  9 },
+            {   0x24,  7 }, {  0x1FA,  9 }, {   0x2F,  7 }, {  0x114,  9 },
+            {   0x75,  7 }, {   0x38,  8 }, {   0xFC,  8 }, {   0x36,  8 },
+            {   0x1E,  7 }, {  0x1FB,  9 }, {   0x7F,  7 }, {   0x68,  7 },
+            {   0x16,  6 }, {   0x37,  8 }, {   0x1F,  7 }, {   0x5C,  8 },
+            {   0x13,  6 }, {   0x8B,  8 }, {    0x1,  6 }, {   0xFB,  8 },
+            {   0x21,  6 }, {   0x44,  7 }, {   0x2B,  6 }, {   0x6B,  7 },
+            {   0x3B,  6 }, {    0xC,  6 }, {   0x1C,  5 }, {   0x19,  5 },
+            {    0x1,  4 }, {   0x20,  6 }, {   0x16,  5 }, {   0x7C,  7 },
+            {    0xC,  5 }, {   0x74,  7 }, {    0xA,  5 }, {   0x1C,  6 },
+            {   0x12,  5 }, {   0x69,  7 }, {    0xF,  5 }, {   0x6A,  7 },
+            {   0x14,  5 }, {   0x11,  6 }, {   0x1E,  5 }, {   0x17,  5 },
+            {    0x2,  4 }, {   0x31,  6 }, {   0x1B,  5 }, {   0x30,  6 },
+            {    0xD,  5 }, {    0x0,  6 }, {    0x1,  5 }, {   0x1D,  7 },
+            {   0x23,  6 }, {   0x1A,  7 }, {   0x1D,  6 }, {   0x5D,  8 },
+            {   0x10,  6 }, {   0xFA,  8 }, {   0x13,  5 }
+        },
+        {
+            {   0x12,  5 }, {   0x26,  7 }, {   0x41,  7 }, {   0x22,  8 },
+            {   0x1A,  7 }, {   0xA9,  8 }, {   0x4C,  7 }, {  0x1B2,  9 },
+            {   0x5C,  7 }, {   0xA8,  8 }, {   0x58,  7 }, {  0x1B3,  9 },
+            {   0x40,  7 }, {   0x79,  8 }, {    0xC,  6 }, {   0x55,  7 },
+            {   0x1F,  6 }, {   0xD8,  8 }, {   0x76,  7 }, {   0x23,  8 },
+            {   0x5F,  7 }, {   0x78,  8 }, {    0xB,  6 }, {   0x1B,  7 },
+            {   0x2D,  6 }, {   0x10,  7 }, {   0x37,  6 }, {   0x6D,  7 },
+            {   0x32,  6 }, {    0xA,  6 }, {   0x1A,  5 }, {   0x1E,  5 },
+            {   0x1F,  5 }, {   0x2B,  6 }, {    0xD,  5 }, {   0x77,  7 },
+            {   0x31,  6 }, {   0x5D,  7 }, {   0x38,  6 }, {   0x27,  7 },
+            {    0xC,  5 }, {   0xE9,  8 }, {   0x33,  6 }, {   0x5E,  7 },
+            {   0x30,  6 }, {   0x4D,  7 }, {    0xA,  5 }, {   0x21,  6 },
+            {    0x7,  5 }, {   0x3D,  7 }, {   0x39,  6 }, {   0xE8,  8 },
+            {    0xB,  5 }, {   0x59,  7 }, {   0x14,  5 }, {   0x27,  6 },
+            {   0x11,  5 }, {   0x75,  7 }, {    0xE,  5 }, {    0x9,  6 },
+            {    0x8,  5 }, {   0x12,  6 }, {    0x0,  3 }
+        }
+    }
+};
+
+static const uint16_t vp4_dc_bias[16][32][2] = {
+    { /* DC bias table 0 */
+        {    0xC,  5 }, {   0x70,  7 }, {  0x1CA,  9 }, {  0x1CB,  9 },
+        {  0x391, 10 }, { 0x1C9B, 13 }, { 0x3935, 14 }, {   0x71,  7 },
+        { 0x3934, 14 }, {    0xB,  4 }, {    0xF,  4 }, {   0x19,  5 },
+        {    0x2,  4 }, {    0x9,  4 }, {    0x3,  4 }, {   0x1D,  5 },
+        {   0x18,  5 }, {    0x7,  4 }, {    0xD,  4 }, {    0x2,  3 },
+        {    0x0,  3 }, {    0xA,  4 }, {    0x8,  4 }, {   0x1A,  6 },
+        {   0x73,  7 }, {   0x6F,  8 }, {  0xE4C, 12 }, {  0x727, 11 },
+        {  0x392, 10 }, {  0x390, 10 }, {   0x36,  7 }, {   0x6E,  8 }
+    },
+    { /* DC bias table 1 */
+        {   0x11,  5 }, {   0x7A,  7 }, {   0x83,  8 }, {   0x40,  7 },
+        {  0x105,  9 }, {  0x413, 11 }, {  0x410, 11 }, {   0x7B,  7 },
+        {  0x822, 12 }, {    0xE,  4 }, {    0x2,  3 }, {    0x2,  4 },
+        {    0x6,  4 }, {    0xA,  4 }, {    0x7,  4 }, {   0x1F,  5 },
+        {   0x17,  5 }, {    0x9,  4 }, {    0xD,  4 }, {    0x0,  3 },
+        {    0xC,  4 }, {    0x3,  4 }, {   0x3C,  6 }, {   0x2C,  6 },
+        {   0x21,  6 }, {  0x169,  9 }, {  0x412, 11 }, {  0x2D0, 10 },
+        {  0x2D1, 10 }, {  0x823, 12 }, {   0x5B,  7 }, {   0xB5,  8 }
+    },
+    { /* DC bias table 2 */
+        {   0x17,  5 }, {   0x10,  6 }, {   0xB6,  8 }, {   0x22,  7 },
+        {  0x16A,  9 }, {  0x2D0, 10 }, {  0xB48, 12 }, {   0x77,  7 },
+        { 0x1692, 13 }, {    0x0,  3 }, {    0x3,  3 }, {    0x3,  4 },
+        {    0x9,  4 }, {    0xC,  4 }, {    0x5,  4 }, {    0x2,  4 },
+        {   0x1C,  5 }, {    0x8,  4 }, {    0xD,  4 }, {    0xF,  4 },
+        {    0xA,  4 }, {    0x9,  5 }, {   0x23,  7 }, {   0x3A,  6 },
+        {   0x2C,  6 }, {  0x16B,  9 }, {  0x5A5, 11 }, {  0x2D3, 10 },
+        {  0x2D1, 10 }, { 0x1693, 13 }, {   0x76,  7 }, {   0xB7,  8 }
+    },
+    { /* DC bias table 3 */
+        {   0x1E,  5 }, {   0x13,  6 }, {   0xFB,  8 }, {   0x7C,  7 },
+        {   0x46,  8 }, {  0x7D6, 11 }, {  0xFA9, 12 }, {   0x12,  6 },
+        { 0x1F50, 13 }, {    0x1,  3 }, {    0x4,  3 }, {    0x5,  4 },
+        {    0xA,  4 }, {    0xE,  4 }, {    0x7,  4 }, {    0x0,  4 },
+        {   0x17,  5 }, {    0x6,  4 }, {    0xD,  4 }, {    0xC,  4 },
+        {    0x1,  4 }, {   0x2C,  6 }, {   0x8F,  9 }, {   0x3F,  6 },
+        {   0x2D,  6 }, {  0x1F4,  9 }, {  0x7D5, 11 }, {   0x8E,  9 },
+        {  0x7D7, 11 }, { 0x1F51, 13 }, {   0x10,  6 }, {   0x22,  7 }
+    },
+    { /* DC bias table 4 */
+        {    0x1,  4 }, {   0x2B,  6 }, {   0x12,  7 }, {   0x55,  7 },
+        {   0x27,  8 }, {  0x3B0, 10 }, {  0x762, 11 }, {   0x77,  7 },
+        {  0x261, 12 }, {    0x2,  3 }, {    0x6,  3 }, {    0x7,  4 },
+        {    0xB,  4 }, {    0xF,  4 }, {    0x8,  4 }, {    0x0,  4 },
+        {   0x1C,  5 }, {    0x3,  4 }, {    0x9,  4 }, {    0x6,  4 },
+        {   0x14,  5 }, {   0x54,  7 }, {  0x131, 11 }, {    0x5,  5 },
+        {   0x3A,  6 }, {  0x1D9,  9 }, {   0x99, 10 }, {   0x4D,  9 },
+        {  0x763, 11 }, {  0x260, 12 }, {    0x8,  6 }, {   0xED,  8 }
+    },
+    { /* DC bias table 5 */
+        {    0x4,  4 }, {   0x33,  6 }, {   0x60,  7 }, {   0x65,  7 },
+        {   0xC2,  8 }, {  0x30D, 10 }, {  0x619, 11 }, {   0x64,  7 },
+        { 0x1862, 13 }, {    0x4,  3 }, {    0x7,  3 }, {    0xA,  4 },
+        {    0xB,  4 }, {    0xD,  4 }, {    0x6,  4 }, {    0x0,  4 },
+        {    0xF,  5 }, {    0x3,  4 }, {    0x5,  4 }, {    0x2,  4 },
+        {    0x2,  5 }, {   0x77,  8 }, {  0xC30, 12 }, {    0x3,  5 },
+        {   0x31,  6 }, {  0x187,  9 }, {  0x1D9, 10 }, {   0xED,  9 },
+        {  0x1D8, 10 }, { 0x1863, 13 }, {   0x1C,  6 }, {   0x3A,  7 }
+    },
+    { /* DC bias table 6 */
+        {    0x8,  4 }, {    0xA,  5 }, {   0x6A,  7 }, {   0x16,  6 },
+        {   0x1E,  7 }, {  0x34E, 10 }, {  0x69F, 11 }, {   0x68,  7 },
+        {  0xD28, 12 }, {    0x5,  3 }, {    0x7,  3 }, {    0x7,  4 },
+        {    0xC,  4 }, {    0x0,  3 }, {    0x6,  4 }, {   0x1B,  5 },
+        {   0x12,  5 }, {    0x2,  4 }, {    0x4,  4 }, {   0x13,  5 },
+        {    0xE,  6 }, {  0x34B, 10 }, { 0x1A53, 13 }, {    0x6,  5 },
+        {   0x17,  6 }, {  0x1A6,  9 }, {  0x69E, 11 }, {  0x1A4,  9 },
+        {  0x695, 11 }, { 0x1A52, 13 }, {   0x6B,  7 }, {   0x1F,  7 }
+    },
+    { /* DC bias table 7 */
+        {    0xE,  4 }, {    0xF,  5 }, {   0x17,  6 }, {   0x25,  6 },
+        {   0x9F,  8 }, {  0x138,  9 }, {  0x24B, 10 }, {   0x93,  8 },
+        {  0x92A, 12 }, {    0x5,  3 }, {    0x0,  2 }, {    0x8,  4 },
+        {    0xD,  4 }, {    0xF,  4 }, {    0x6,  4 }, {    0x4,  4 },
+        {    0xE,  5 }, {   0x19,  5 }, {   0x18,  5 }, {    0xA,  5 },
+        {   0x9E,  8 }, {  0x494, 11 }, { 0x1256, 13 }, {   0x26,  6 },
+        {   0x16,  6 }, {  0x124,  9 }, {  0x4E5, 11 }, {  0x273, 10 },
+        {  0x4E4, 11 }, { 0x1257, 13 }, {   0x48,  7 }, {   0x9D,  8 }
+    },
+    { /* DC bias table 8 */
+        {    0x4,  4 }, {   0x2C,  6 }, {   0x50,  7 }, {   0x1E,  7 },
+        {   0x71,  9 }, {   0xE1, 10 }, {   0xE0, 10 }, {   0x1D,  7 },
+        {    0x6,  6 }, {    0x7,  3 }, {    0x6,  3 }, {    0x7,  4 },
+        {    0x5,  4 }, {    0x6,  4 }, {   0x15,  5 }, {    0x0,  5 },
+        {   0x29,  6 }, {    0x2,  5 }, {    0x6,  5 }, {    0x1,  5 },
+        {   0x23,  6 }, {   0x1F,  7 }, {   0x39,  8 }, {    0x9,  4 },
+        {    0x2,  4 }, {   0x10,  5 }, {    0x7,  6 }, {   0x2D,  6 },
+        {   0x2F,  6 }, {   0x2E,  6 }, {   0x22,  6 }, {   0x51,  7 }
+    },
+    { /* DC bias table 9 */
+        {    0x8,  4 }, {   0x2F,  6 }, {   0x51,  7 }, {   0x50,  7 },
+        {  0x2ED, 10 }, {  0x5D9, 11 }, {  0x5D8, 11 }, {   0xBA,  8 },
+        {   0x5C,  7 }, {    0x7,  3 }, {    0x6,  3 }, {    0x9,  4 },
+        {    0x6,  4 }, {    0x7,  4 }, {   0x16,  5 }, {    0x5,  5 },
+        {   0x2B,  6 }, {    0x6,  5 }, {    0xA,  5 }, {    0x1,  5 },
+        {    0xF,  6 }, {   0x1D,  7 }, {  0x177,  9 }, {    0x4,  4 },
+        {    0x1,  4 }, {    0x4,  5 }, {    0x1,  6 }, {   0x2A,  6 },
+        {    0xB,  5 }, {   0x29,  6 }, {    0x0,  6 }, {   0x1C,  7 }
+    },
+    { /* DC bias table 10 */
+        {    0xA,  4 }, {   0x3C,  6 }, {   0x74,  7 }, {   0x4E,  7 },
+        {  0x26D, 10 }, {  0x4D9, 11 }, {  0x4D8, 11 }, {   0x9A,  8 },
+        {   0x4C,  7 }, {    0x0,  2 }, {    0x6,  3 }, {    0x8,  4 },
+        {    0x7,  4 }, {    0x6,  4 }, {   0x16,  5 }, {    0x8,  5 },
+        {   0x2E,  6 }, {    0xA,  5 }, {    0xB,  5 }, {   0x3D,  6 },
+        {   0x24,  6 }, {   0xEB,  8 }, {  0x137,  9 }, {   0x1F,  5 },
+        {   0x1C,  5 }, {   0x3B,  6 }, {   0x12,  6 }, {   0x25,  6 },
+        {   0x2F,  6 }, {   0x13,  6 }, {   0x4F,  7 }, {   0xEA,  8 }
+    },
+    { /* DC bias table 11 */
+        {    0xA,  4 }, {    0xA,  5 }, {    0x3,  6 }, {   0x16,  6 },
+        {    0x9,  8 }, {   0x21, 10 }, {   0x20, 10 }, {   0xB3,  8 },
+        {   0x58,  7 }, {    0x7,  3 }, {    0x6,  3 }, {    0x7,  4 },
+        {    0x6,  4 }, {    0x4,  4 }, {   0x13,  5 }, {    0x2,  5 },
+        {   0x25,  6 }, {    0x0,  5 }, {    0x3,  5 }, {   0x2D,  6 },
+        {   0x5D,  7 }, {   0xB2,  8 }, {   0x11,  9 }, {    0x8,  4 },
+        {    0x2,  4 }, {    0x6,  5 }, {   0x17,  6 }, {   0x2F,  6 },
+        {    0x7,  5 }, {   0x24,  6 }, {   0x5C,  7 }, {    0x5,  7 }
+    },
+    { /* DC bias table 12 */
+        {    0xB,  4 }, {   0x13,  5 }, {   0x1F,  6 }, {   0x31,  6 },
+        {   0x21,  7 }, {  0x295, 10 }, {  0x528, 11 }, {   0xA4,  8 },
+        {   0x3C,  7 }, {    0x0,  2 }, {    0x7,  3 }, {    0x6,  4 },
+        {    0x5,  4 }, {   0x1B,  5 }, {   0x12,  5 }, {   0x32,  6 },
+        {   0x1D,  6 }, {   0x2B,  6 }, {   0x30,  6 }, {   0x1C,  6 },
+        {   0x3D,  7 }, {  0x14B,  9 }, {  0x529, 11 }, {    0x8,  4 },
+        {   0x1A,  5 }, {   0x33,  6 }, {   0x11,  6 }, {   0x2A,  6 },
+        {    0x9,  5 }, {   0x28,  6 }, {   0x53,  7 }, {   0x20,  7 }
+    },
+    { /* DC bias table 13 */
+        {    0xE,  4 }, {   0x15,  5 }, {   0x29,  6 }, {   0x3F,  6 },
+        {   0x4D,  7 }, {  0x2F1, 10 }, {  0x5E0, 11 }, {   0x92,  8 },
+        {   0x48,  7 }, {    0x0,  2 }, {    0x6,  3 }, {    0x6,  4 },
+        {    0x5,  4 }, {    0x4,  4 }, {    0xF,  5 }, {   0x2E,  6 },
+        {   0x1D,  6 }, {   0x28,  6 }, {   0x27,  6 }, {   0x5F,  7 },
+        {   0xBD,  8 }, {  0x179,  9 }, {  0x5E1, 11 }, {    0x8,  4 },
+        {   0x1E,  5 }, {   0x2D,  6 }, {   0x1C,  6 }, {   0x2C,  6 },
+        {   0x3E,  6 }, {   0x25,  6 }, {   0x4C,  7 }, {   0x93,  8 }
+    },
+    { /* DC bias table 14 */
+        {    0xC,  4 }, {   0x17,  5 }, {   0x35,  6 }, {   0x13,  5 },
+        {   0x21,  6 }, {   0xAD,  8 }, {  0x6F1, 11 }, {  0x1BD,  9 },
+        {   0xD9,  8 }, {    0x0,  2 }, {    0x7,  3 }, {    0x7,  4 },
+        {    0x6,  4 }, {    0x4,  4 }, {   0x11,  5 }, {   0x2A,  6 },
+        {   0x6E,  7 }, {   0x25,  6 }, {   0x24,  6 }, {   0x57,  7 },
+        {   0xD8,  8 }, {  0x379, 10 }, {  0x6F0, 11 }, {    0x5,  4 },
+        {   0x16,  5 }, {   0x29,  6 }, {   0x6D,  7 }, {   0x28,  6 },
+        {   0x34,  6 }, {   0x20,  6 }, {   0xDF,  8 }, {   0xAC,  8 }
+    },
+    { /* DC bias table 15 */
+        {    0x0,  3 }, {   0x1A,  5 }, {    0x6,  5 }, {   0x19,  5 },
+        {   0x30,  6 }, {   0x5A,  7 }, {  0x18A,  9 }, {  0x2DD, 10 },
+        {  0x18B,  9 }, {    0x1,  2 }, {    0x7,  3 }, {    0xA,  4 },
+        {    0x9,  4 }, {    0x2,  4 }, {   0x10,  5 }, {   0x2E,  6 },
+        {   0x6E,  7 }, {   0x2C,  6 }, {    0xE,  6 }, {   0x5E,  7 },
+        {   0xC4,  8 }, {  0x5B9, 11 }, {  0x5B8, 11 }, {   0x11,  5 },
+        {   0x36,  6 }, {   0x5F,  7 }, {   0x1E,  7 }, {   0x63,  7 },
+        {   0x6F,  7 }, {   0x1F,  7 }, {   0xB6,  8 }, {  0x16F,  9 }
+    }
+};
+
+static const uint16_t vp4_ac_bias_0[16][32][2] = {
+    { /* AC bias group 1, table 0 */
+        {    0x6,  5 }, {   0x1E,  7 }, {  0x1CC,  9 }, {  0x1CE,  9 },
+        {  0x734, 11 }, { 0x1CD5, 13 }, { 0x1CD4, 13 }, {   0x18,  5 },
+        {  0xE6B, 12 }, {    0x0,  3 }, {    0xF,  4 }, {    0x6,  4 },
+        {    0x7,  4 }, {    0xD,  4 }, {    0x8,  4 }, {    0x2,  4 },
+        {   0x19,  5 }, {    0x5,  4 }, {    0xB,  4 }, {    0xA,  4 },
+        {   0x1D,  5 }, {   0x27,  6 }, {  0x1CF,  9 }, {    0x4,  4 },
+        {   0x38,  6 }, {    0xE,  6 }, {   0x4C,  7 }, {   0x1F,  7 },
+        {   0x4D,  7 }, {  0x39B, 10 }, {   0x12,  5 }, {   0x72,  7 }
+    },
+    { /* AC bias group 1, table 1 */
+        {    0x9,  5 }, {   0x4B,  7 }, {   0x90,  8 }, {   0x91,  8 },
+        {  0x745, 11 }, { 0x1D11, 13 }, { 0x1D10, 13 }, {   0x19,  5 },
+        {  0xE89, 12 }, {    0x0,  3 }, {    0xF,  4 }, {    0x8,  4 },
+        {    0x7,  4 }, {    0xD,  4 }, {    0xB,  4 }, {    0x2,  4 },
+        {   0x1C,  5 }, {    0x3,  4 }, {    0xA,  4 }, {    0x5,  4 },
+        {   0x18,  5 }, {   0x10,  6 }, {  0x1D0,  9 }, {    0x6,  4 },
+        {   0x3B,  6 }, {   0x11,  6 }, {   0x4A,  7 }, {   0x49,  7 },
+        {   0xE9,  8 }, {  0x3A3, 10 }, {   0x13,  5 }, {   0x75,  7 }
+    },
+    { /* AC bias group 1, table 2 */
+        {   0x19,  5 }, {   0x74,  7 }, {   0x1D,  8 }, {   0xEA,  8 },
+        {   0x73, 10 }, {  0x1CA, 12 }, {  0x396, 13 }, {   0x1C,  5 },
+        {   0xE4, 11 }, {    0x2,  3 }, {    0x1,  3 }, {    0x7,  4 },
+        {    0x8,  4 }, {    0xD,  4 }, {    0x9,  4 }, {   0x1F,  5 },
+        {   0x18,  5 }, {    0x0,  4 }, {    0x6,  4 }, {   0x1E,  5 },
+        {   0x3B,  6 }, {   0xEB,  8 }, {  0x397, 13 }, {    0xA,  4 },
+        {    0x2,  5 }, {   0x2C,  6 }, {   0x5B,  7 }, {   0x5A,  7 },
+        {    0xF,  7 }, {   0x38,  9 }, {   0x17,  5 }, {    0x6,  6 }
+    },
+    { /* AC bias group 1, table 3 */
+        {   0x1E,  5 }, {   0x6F,  7 }, {   0xAE,  8 }, {   0xAF,  8 },
+        {  0x187, 10 }, {  0x61B, 12 }, {  0xC35, 13 }, {   0x1A,  5 },
+        {  0x30C, 11 }, {    0x2,  3 }, {    0x1,  3 }, {    0x7,  4 },
+        {    0x8,  4 }, {    0xE,  4 }, {    0x9,  4 }, {   0x1F,  5 },
+        {   0x14,  5 }, {    0x0,  4 }, {    0x1,  4 }, {   0x19,  5 },
+        {   0x2A,  6 }, {   0x60,  8 }, {  0xC34, 13 }, {    0xB,  4 },
+        {    0xD,  5 }, {   0x36,  6 }, {   0x6E,  7 }, {   0x56,  7 },
+        {   0x31,  7 }, {   0xC2,  9 }, {   0x18,  5 }, {   0x19,  6 }
+    },
+    { /* AC bias group 1, table 4 */
+        {    0x1,  4 }, {   0x2C,  6 }, {    0x5,  7 }, {   0x15,  7 },
+        {    0x8,  8 }, {   0x97, 12 }, {  0x12D, 13 }, {   0x17,  5 },
+        {   0x4A, 11 }, {    0x3,  3 }, {    0x2,  3 }, {    0x9,  4 },
+        {    0xA,  4 }, {    0xE,  4 }, {    0x8,  4 }, {   0x1F,  5 },
+        {    0x7,  5 }, {   0x1E,  5 }, {   0x1B,  5 }, {    0x4,  5 },
+        {   0x5A,  7 }, {   0x24, 10 }, {  0x12C, 13 }, {    0xC,  4 },
+        {    0x6,  5 }, {    0x0,  5 }, {    0x3,  6 }, {   0x5B,  7 },
+        {   0x14,  7 }, {   0x13,  9 }, {   0x1A,  5 }, {    0xB,  6 }
+    },
+    { /* AC bias group 1, table 5 */
+        {    0x4,  4 }, {    0x0,  5 }, {   0x17,  7 }, {   0x63,  7 },
+        {  0x18B,  9 }, {  0x310, 10 }, {  0xC44, 12 }, {   0x19,  5 },
+        {  0x623, 11 }, {    0x4,  3 }, {    0x3,  3 }, {    0xA,  4 },
+        {    0xB,  4 }, {    0xD,  4 }, {    0x3,  4 }, {   0x1C,  5 },
+        {    0x3,  5 }, {    0xA,  5 }, {    0x4,  5 }, {    0x3,  6 },
+        {  0x18A,  9 }, { 0x188B, 13 }, { 0x188A, 13 }, {    0xF,  4 },
+        {    0xB,  5 }, {    0x2,  5 }, {    0xA,  6 }, {    0x2,  6 },
+        {   0x16,  7 }, {  0x189,  9 }, {   0x1D,  5 }, {   0x30,  6 }
+    },
+    { /* AC bias group 1, table 6 */
+        {    0xD,  4 }, {    0x3,  5 }, {   0x77,  7 }, {    0xD,  6 },
+        {   0x82,  8 }, {  0x20D, 10 }, {  0x830, 12 }, {   0x19,  5 },
+        {  0x419, 11 }, {    0x3,  3 }, {    0x2,  3 }, {    0xA,  4 },
+        {    0x9,  4 }, {    0xB,  4 }, {    0x2,  4 }, {   0x11,  5 },
+        {   0x39,  6 }, {    0x2,  5 }, {   0x21,  6 }, {   0x40,  7 },
+        { 0x1063, 13 }, { 0x20C5, 14 }, { 0x20C4, 14 }, {    0xF,  4 },
+        {   0x18,  5 }, {    0x7,  5 }, {   0x38,  6 }, {    0xC,  6 },
+        {   0x76,  7 }, {  0x107,  9 }, {    0x0,  4 }, {   0x3A,  6 }
+    },
+    { /* AC bias group 1, table 7 */
+        {    0xF,  4 }, {   0x1C,  5 }, {   0x36,  6 }, {    0x8,  5 },
+        {   0x61,  7 }, {   0x91,  8 }, {  0x243, 10 }, {    0x9,  5 },
+        {  0x120,  9 }, {    0x5,  3 }, {    0x3,  3 }, {    0x8,  4 },
+        {    0x5,  4 }, {    0x1,  4 }, {   0x13,  5 }, {   0x31,  6 },
+        {   0x76,  7 }, {   0x60,  7 }, {   0x93,  8 }, {  0x909, 12 },
+        {  0x908, 12 }, {  0x90B, 12 }, {  0x90A, 12 }, {    0x1,  3 },
+        {   0x1A,  5 }, {   0x19,  5 }, {   0x3A,  6 }, {   0x25,  6 },
+        {   0x77,  7 }, {   0x92,  8 }, {    0x0,  4 }, {   0x37,  6 }
+    },
+    { /* AC bias group 1, table 8 */
+        {   0x1F,  5 }, {   0x79,  7 }, {   0xF1,  8 }, {   0xF0,  8 },
+        {  0x11B, 10 }, {  0x469, 12 }, {  0x468, 12 }, {   0x3B,  6 },
+        {   0x22,  7 }, {    0x5,  3 }, {    0x4,  3 }, {    0x7,  4 },
+        {    0x5,  4 }, {    0x6,  4 }, {   0x1C,  5 }, {    0x1,  5 },
+        {   0x35,  6 }, {   0x3D,  6 }, {   0x3A,  6 }, {   0x10,  6 },
+        {   0x47,  8 }, {   0x8C,  9 }, {  0x235, 11 }, {    0x1,  3 },
+        {    0x1,  4 }, {   0x19,  5 }, {    0x0,  5 }, {   0x30,  6 },
+        {    0x9,  5 }, {   0x31,  6 }, {   0x1B,  5 }, {   0x34,  6 }
+    },
+    { /* AC bias group 1, table 9 */
+        {    0x3,  4 }, {   0x1B,  6 }, {   0xF3,  8 }, {   0xFD,  8 },
+        {  0x3C9, 10 }, {  0xF20, 12 }, { 0x1E42, 13 }, {   0x3D,  6 },
+        {   0xFC,  8 }, {    0x6,  3 }, {    0x4,  3 }, {    0x2,  4 },
+        {    0x0,  4 }, {    0x1,  4 }, {   0x17,  5 }, {   0x3E,  6 },
+        {   0x1A,  6 }, {   0x39,  6 }, {   0x2B,  6 }, {   0x78,  7 },
+        {  0x1E5,  9 }, {  0x791, 11 }, { 0x1E43, 13 }, {    0x2,  3 },
+        {    0x7,  4 }, {   0x1D,  5 }, {    0xC,  5 }, {   0x38,  6 },
+        {   0x14,  5 }, {   0x7F,  7 }, {   0x16,  5 }, {   0x2A,  6 }
+    },
+    { /* AC bias group 1, table 10 */
+        {    0x7,  4 }, {   0x39,  6 }, {   0x51,  7 }, {   0x78,  7 },
+        {  0x3CB, 10 }, {  0xF29, 12 }, { 0x1E51, 13 }, {   0x3D,  6 },
+        {   0xF3,  8 }, {    0x6,  3 }, {    0x4,  3 }, {    0x2,  4 },
+        {    0x0,  4 }, {    0x1,  4 }, {   0x17,  5 }, {   0x3E,  6 },
+        {   0x7F,  7 }, {   0x2B,  6 }, {   0x7E,  7 }, {   0x50,  7 },
+        {  0x1E4,  9 }, {  0x795, 11 }, { 0x1E50, 13 }, {    0x2,  3 },
+        {    0x6,  4 }, {   0x1D,  5 }, {    0x6,  5 }, {   0x38,  6 },
+        {    0x7,  5 }, {   0x29,  6 }, {   0x16,  5 }, {   0x2A,  6 }
+    },
+    { /* AC bias group 1, table 11 */
+        {    0x8,  4 }, {   0x3B,  6 }, {   0x1D,  7 }, {   0x72,  7 },
+        {  0x1CC,  9 }, {  0x734, 11 }, { 0x1CD5, 13 }, {   0x3A,  6 },
+        {   0x1C,  7 }, {    0x6,  3 }, {    0x5,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {    0x0,  4 }, {   0x12,  5 }, {   0x3E,  6 },
+        {   0x7F,  7 }, {   0x1E,  6 }, {   0x7E,  7 }, {   0xE7,  8 },
+        {  0x39B, 10 }, {  0xE6B, 12 }, { 0x1CD4, 13 }, {    0x2,  3 },
+        {    0x6,  4 }, {   0x1E,  5 }, {    0xE,  5 }, {   0x38,  6 },
+        {    0x6,  5 }, {    0xF,  6 }, {   0x13,  5 }, {   0x1F,  6 }
+    },
+    { /* AC bias group 1, table 12 */
+        {    0xD,  4 }, {   0x3F,  6 }, {   0x73,  7 }, {    0xC,  6 },
+        {   0xE4,  8 }, {  0x72B, 11 }, {  0xE54, 12 }, {   0x3A,  6 },
+        {   0x1A,  7 }, {    0x5,  3 }, {    0x4,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {    0x0,  4 }, {    0x7,  5 }, {   0x38,  6 },
+        {   0x76,  7 }, {   0x77,  7 }, {   0x1B,  7 }, {  0x1CB,  9 },
+        {  0x394, 10 }, { 0x1CAB, 13 }, { 0x1CAA, 13 }, {    0x2,  3 },
+        {    0x6,  4 }, {   0x1E,  5 }, {    0xE,  5 }, {   0x3E,  6 },
+        {   0x19,  5 }, {   0x1F,  6 }, {   0x18,  5 }, {   0x1E,  6 }
+    },
+    { /* AC bias group 1, table 13 */
+        {    0xE,  4 }, {    0x7,  5 }, {    0xC,  6 }, {   0x1C,  6 },
+        {   0xBD,  8 }, {  0x2F3, 10 }, {  0xBC9, 12 }, {   0x1F,  6 },
+        {   0xBF,  8 }, {    0x6,  3 }, {    0x4,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {   0x1E,  5 }, {    0x1,  5 }, {    0xD,  6 },
+        {   0x3A,  7 }, {   0x3B,  7 }, {   0xBE,  8 }, {  0x178,  9 },
+        {  0x5E5, 11 }, { 0x1791, 13 }, { 0x1790, 13 }, {    0x2,  3 },
+        {    0x6,  4 }, {   0x1F,  5 }, {   0x16,  5 }, {    0x0,  5 },
+        {   0x15,  5 }, {   0x2E,  6 }, {   0x14,  5 }, {   0x1E,  6 }
+    },
+    { /* AC bias group 1, table 14 */
+        {    0x0,  3 }, {   0x1B,  5 }, {   0x31,  6 }, {   0x3A,  6 },
+        {   0x60,  7 }, {   0x6F,  9 }, {  0x1B9, 11 }, {    0xE,  6 },
+        {   0x1A,  7 }, {    0x5,  3 }, {    0x3,  3 }, {    0x2,  4 },
+        {   0x1F,  5 }, {   0x1A,  5 }, {   0x39,  6 }, {    0xC,  6 },
+        {   0xC3,  8 }, {   0xC2,  8 }, {   0x36,  8 }, {   0xDD, 10 },
+        {  0x370, 12 }, {  0x6E3, 13 }, {  0x6E2, 13 }, {    0x2,  3 },
+        {    0x8,  4 }, {   0x1E,  5 }, {   0x19,  5 }, {   0x3B,  6 },
+        {   0x12,  5 }, {    0xF,  6 }, {   0x13,  5 }, {   0x38,  6 }
+    },
+    { /* AC bias group 1, table 15 */
+        {    0x2,  3 }, {    0x0,  4 }, {    0x3,  5 }, {   0x1C,  5 },
+        {   0x32,  6 }, {   0x1C,  7 }, {  0x199,  9 }, {    0x4,  6 },
+        {   0xCD,  8 }, {    0x4,  3 }, {    0x3,  3 }, {   0x1B,  5 },
+        {   0x1A,  5 }, {   0x3D,  6 }, {   0x67,  7 }, {   0x3B,  8 },
+        {  0x198,  9 }, {   0x75,  9 }, {   0xE9, 10 }, {  0x3A1, 12 },
+        {  0x3A0, 12 }, {  0x3A3, 12 }, {  0x3A2, 12 }, {    0x5,  3 },
+        {    0x2,  4 }, {   0x1F,  5 }, {   0x1D,  5 }, {   0x3C,  6 },
+        {   0x18,  5 }, {    0xF,  6 }, {    0x6,  5 }, {    0x5,  6 }
+    }
+};
+
+static const uint16_t vp4_ac_bias_1[16][32][2] = {
+    { /* AC bias group 2, table 0 */
+        {    0x4,  5 }, {   0xF5,  8 }, {  0x182,  9 }, {  0x60F, 11 },
+        { 0x1839, 13 }, { 0x1838, 13 }, { 0x183B, 13 }, {   0x13,  5 },
+        {   0xC0,  8 }, {    0x3,  3 }, {    0x2,  3 }, {    0xB,  4 },
+        {    0xA,  4 }, {    0xE,  4 }, {    0x8,  4 }, {    0x1,  4 },
+        {   0x12,  5 }, {   0x1F,  5 }, {    0x0,  4 }, {    0x6,  5 },
+        {   0x7B,  7 }, {  0x306, 10 }, { 0x183A, 13 }, {    0xD,  4 },
+        {    0x7,  5 }, {   0x31,  6 }, {    0xA,  6 }, {   0x61,  7 },
+        {   0x3C,  6 }, {   0xF4,  8 }, {   0x19,  5 }, {    0xB,  6 }
+    },
+    { /* AC bias group 2, table 1 */
+        {    0xA,  5 }, {   0x1A,  7 }, {  0x1D8,  9 }, {  0x3B3, 10 },
+        {  0xECA, 12 }, { 0x1D96, 13 }, { 0x3B2F, 14 }, {   0x14,  5 },
+        {   0x36,  8 }, {    0x4,  3 }, {    0x3,  3 }, {    0xC,  4 },
+        {    0xB,  4 }, {    0x0,  3 }, {    0x4,  4 }, {   0x1C,  5 },
+        {    0x5,  5 }, {   0x15,  5 }, {    0x7,  5 }, {   0x17,  6 },
+        {   0x37,  8 }, {  0x764, 11 }, { 0x3B2E, 14 }, {    0xF,  4 },
+        {   0x1A,  5 }, {   0x3A,  6 }, {    0xC,  6 }, {   0x77,  7 },
+        {    0x4,  5 }, {   0xED,  8 }, {   0x1B,  5 }, {   0x16,  6 }
+    },
+    { /* AC bias group 2, table 2 */
+        {   0x1A,  5 }, {   0x2D,  7 }, {   0x58,  8 }, {  0x1F4,  9 },
+        {  0x7D4, 11 }, { 0x1F55, 13 }, { 0x1F54, 13 }, {   0x14,  5 },
+        {   0x59,  8 }, {    0x4,  3 }, {    0x3,  3 }, {    0xB,  4 },
+        {    0xC,  4 }, {    0xE,  4 }, {    0x4,  4 }, {   0x15,  5 },
+        {    0x5,  5 }, {    0x7,  5 }, {    0x4,  5 }, {   0x7C,  7 },
+        {  0x3EB, 10 }, { 0x1F57, 13 }, { 0x1F56, 13 }, {    0x0,  3 },
+        {   0x1B,  5 }, {   0x3F,  6 }, {    0xD,  6 }, {    0xC,  6 },
+        {    0xA,  5 }, {   0xFB,  8 }, {   0x1E,  5 }, {   0x17,  6 }
+    },
+    { /* AC bias group 2, table 3 */
+        {    0x0,  4 }, {   0x75,  7 }, {   0x4A,  8 }, {   0x97,  9 },
+        {  0x25B, 11 }, {  0x969, 13 }, {  0x968, 13 }, {    0xB,  5 },
+        {   0xE8,  8 }, {    0x5,  3 }, {    0x4,  3 }, {    0x7,  4 },
+        {    0xC,  4 }, {    0xD,  4 }, {    0x1,  4 }, {    0xA,  5 },
+        {   0x39,  6 }, {   0x3B,  6 }, {   0x18,  6 }, {   0xE9,  8 },
+        {  0x12C, 10 }, {  0x96B, 13 }, {  0x96A, 13 }, {    0x1,  3 },
+        {   0x1F,  5 }, {    0x8,  5 }, {   0x19,  6 }, {   0x13,  6 },
+        {    0xD,  5 }, {   0x24,  7 }, {   0x1E,  5 }, {   0x38,  6 }
+    },
+    { /* AC bias group 2, table 4 */
+        {    0x4,  4 }, {   0x14,  6 }, {   0x6E,  8 }, {   0x57,  8 },
+        {  0x159, 10 }, {  0x562, 12 }, {  0xAC7, 13 }, {    0xB,  5 },
+        {   0x6F,  8 }, {    0x6,  3 }, {    0x5,  3 }, {    0x8,  4 },
+        {    0x9,  4 }, {    0x7,  4 }, {   0x1E,  5 }, {    0x2,  5 },
+        {    0x7,  6 }, {    0x6,  6 }, {   0x2A,  7 }, {   0xAD,  9 },
+        {  0xAC6, 13 }, {  0x561, 12 }, {  0x560, 12 }, {    0x1,  3 },
+        {   0x1F,  5 }, {    0xC,  5 }, {   0x39,  6 }, {   0x1A,  6 },
+        {    0x0,  4 }, {   0x36,  7 }, {   0x1D,  5 }, {   0x38,  6 }
+    },
+    { /* AC bias group 2, table 5 */
+        {    0x7,  4 }, {   0x1B,  6 }, {    0xE,  7 }, {    0xD,  7 },
+        {  0x3E1, 10 }, { 0x1F06, 13 }, { 0x3E0F, 14 }, {    0x2,  5 },
+        {   0xF9,  8 }, {    0x5,  3 }, {    0x6,  3 }, {    0x8,  4 },
+        {    0x9,  4 }, {    0x4,  4 }, {    0xC,  5 }, {   0x1A,  6 },
+        {    0xF,  7 }, {    0xC,  7 }, {  0x1F1,  9 }, {  0x7C0, 11 },
+        { 0x3E0E, 14 }, { 0x1F05, 13 }, { 0x1F04, 13 }, {    0x1,  3 },
+        {    0x0,  4 }, {   0x1C,  5 }, {   0x3F,  6 }, {   0x3D,  6 },
+        {    0x5,  4 }, {   0x7D,  7 }, {   0x1D,  5 }, {   0x3C,  6 }
+    },
+    { /* AC bias group 2, table 6 */
+        {    0xF,  4 }, {    0xA,  5 }, {   0x71,  7 }, {    0x6,  6 },
+        {  0x1C2,  9 }, {  0x702, 11 }, { 0x1C0E, 13 }, {    0x2,  5 },
+        {    0xE,  7 }, {    0x5,  3 }, {    0x4,  3 }, {    0x6,  4 },
+        {    0x7,  4 }, {   0x1D,  5 }, {   0x17,  6 }, {    0xF,  7 },
+        {  0x1C3,  9 }, {  0x1C1,  9 }, {  0x380, 10 }, { 0x381F, 14 },
+        { 0x381E, 14 }, { 0x1C0D, 13 }, { 0x1C0C, 13 }, {    0x1,  3 },
+        {    0x4,  4 }, {   0x18,  5 }, {    0x1,  5 }, {    0x0,  5 },
+        {    0xD,  4 }, {   0x16,  6 }, {   0x19,  5 }, {   0x39,  6 }
+    },
+    { /* AC bias group 2, table 7 */
+        {    0x2,  3 }, {   0x1E,  5 }, {   0x3B,  6 }, {    0xD,  5 },
+        {   0x61,  7 }, {  0x1FA,  9 }, { 0x1FB5, 13 }, {   0x31,  6 },
+        {   0xFC,  8 }, {    0x4,  3 }, {    0x5,  3 }, {    0x1,  4 },
+        {    0x7,  4 }, {   0x3A,  6 }, {   0x60,  7 }, {  0x3F7, 10 },
+        {  0x7EC, 11 }, { 0x1FB7, 13 }, { 0x3F6C, 14 }, { 0x7EDB, 15 },
+        { 0x7EDA, 15 }, { 0x3F69, 14 }, { 0x3F68, 14 }, {    0x1,  3 },
+        {    0x0,  4 }, {   0x19,  5 }, {   0x3E,  6 }, {   0x39,  6 },
+        {    0xD,  4 }, {   0x38,  6 }, {    0xC,  5 }, {   0x7F,  7 }
+    },
+    { /* AC bias group 2, table 8 */
+        {   0x1E,  5 }, {   0x70,  7 }, {  0x127,  9 }, {  0x126,  9 },
+        {  0x492, 11 }, { 0x124D, 13 }, { 0x124C, 13 }, {    0x1,  5 },
+        {   0x7F,  7 }, {    0x6,  3 }, {    0x5,  3 }, {    0x5,  4 },
+        {    0x4,  4 }, {    0x1,  4 }, {    0x7,  5 }, {   0x25,  6 },
+        {   0x71,  7 }, {   0x7E,  7 }, {   0x48,  7 }, {  0x125,  9 },
+        {  0x248, 10 }, { 0x124F, 13 }, { 0x124E, 13 }, {    0x3,  3 },
+        {    0x8,  4 }, {   0x1D,  5 }, {    0x6,  5 }, {   0x3E,  6 },
+        {    0x2,  4 }, {    0x0,  5 }, {   0x13,  5 }, {   0x39,  6 }
+    },
+    { /* AC bias group 2, table 9 */
+        {    0x1,  4 }, {    0x1,  6 }, {   0xE7,  8 }, {   0x91,  8 },
+        {  0x240, 10 }, { 0x120D, 13 }, { 0x120C, 13 }, {   0x3C,  6 },
+        {    0x0,  6 }, {    0x6,  3 }, {    0x5,  3 }, {    0x5,  4 },
+        {    0x4,  4 }, {   0x1F,  5 }, {    0x4,  5 }, {   0x25,  6 },
+        {   0x72,  7 }, {   0x49,  7 }, {   0xE6,  8 }, {  0x121,  9 },
+        {  0x482, 11 }, { 0x120F, 13 }, { 0x120E, 13 }, {    0x3,  3 },
+        {    0x8,  4 }, {   0x1D,  5 }, {    0x5,  5 }, {   0x3D,  6 },
+        {    0x3,  4 }, {    0x1,  5 }, {   0x13,  5 }, {   0x38,  6 }
+    },
+    { /* AC bias group 2, table 10 */
+        {    0x4,  4 }, {    0xF,  6 }, {   0xF4,  8 }, {   0x5B,  8 },
+        {  0x2D3, 11 }, {  0xB4A, 13 }, { 0x1697, 14 }, {   0x3C,  6 },
+        {    0xE,  6 }, {    0x6,  3 }, {    0x5,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {   0x1D,  5 }, {    0x0,  5 }, {   0x7B,  7 },
+        {   0x2C,  7 }, {   0xF5,  8 }, {   0xB5,  9 }, {  0x168, 10 },
+        { 0x1696, 14 }, {  0xB49, 13 }, {  0xB48, 13 }, {    0x3,  3 },
+        {    0x9,  4 }, {   0x1F,  5 }, {    0xA,  5 }, {    0x1,  5 },
+        {    0x8,  4 }, {    0x6,  5 }, {   0x1C,  5 }, {   0x17,  6 }
+    },
+    { /* AC bias group 2, table 11 */
+        {    0x8,  4 }, {   0x39,  6 }, {   0x1A,  7 }, {    0x3,  7 },
+        {   0xDB, 10 }, {  0x6D6, 13 }, {  0xDAF, 14 }, {   0x3C,  6 },
+        {    0xC,  6 }, {    0x6,  3 }, {    0x5,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {   0x1D,  5 }, {   0x3D,  6 }, {    0x0,  6 },
+        {    0x2,  7 }, {   0x37,  8 }, {   0x6C,  9 }, {  0x1B4, 11 },
+        {  0xDAE, 14 }, {  0x6D5, 13 }, {  0x6D4, 13 }, {    0x2,  3 },
+        {    0x7,  4 }, {   0x1F,  5 }, {    0x7,  5 }, {    0x1,  5 },
+        {    0x9,  4 }, {    0xD,  5 }, {    0xC,  5 }, {   0x38,  6 }
+    },
+    { /* AC bias group 2, table 12 */
+        {    0xF,  4 }, {    0x4,  5 }, {   0x2F,  7 }, {   0x2E,  7 },
+        {   0x54,  9 }, {  0x555, 13 }, {  0x554, 13 }, {   0x16,  6 },
+        {    0xE,  6 }, {    0x6,  3 }, {    0x5,  3 }, {    0x1,  4 },
+        {    0x0,  4 }, {    0x9,  5 }, {    0xB,  6 }, {   0x14,  7 },
+        {   0x57,  9 }, {   0x56,  9 }, {   0xAB, 10 }, {  0x557, 13 },
+        {  0x556, 13 }, {  0x2A9, 12 }, {  0x2A8, 12 }, {    0x3,  3 },
+        {    0x8,  4 }, {   0x13,  5 }, {    0xA,  5 }, {    0x8,  5 },
+        {    0xE,  4 }, {   0x12,  5 }, {    0x6,  5 }, {    0xF,  6 }
+    },
+    { /* AC bias group 2, table 13 */
+        {    0x1,  3 }, {    0xE,  5 }, {    0x6,  6 }, {    0x4,  6 },
+        {   0xDA,  9 }, {  0xDBE, 13 }, { 0x1B7E, 14 }, {    0x7,  6 },
+        {   0x1A,  6 }, {    0x5,  3 }, {    0x4,  3 }, {   0x1C,  5 },
+        {   0x1B,  5 }, {   0x3A,  6 }, {   0x37,  7 }, {   0x6C,  8 },
+        {  0x1B6, 10 }, {  0x36E, 11 }, {  0xDBD, 13 }, { 0x36FF, 15 },
+        { 0x36FE, 15 }, { 0x1B79, 14 }, { 0x1B78, 14 }, {    0x2,  3 },
+        {    0xC,  4 }, {    0x0,  4 }, {    0xF,  5 }, {    0xC,  5 },
+        {    0xF,  4 }, {   0x1A,  5 }, {   0x3B,  6 }, {    0x5,  6 }
+    },
+    { /* AC bias group 2, table 14 */
+        {    0x5,  3 }, {   0x1E,  5 }, {   0x3A,  6 }, {   0x3E,  6 },
+        {   0xFC,  8 }, {  0xFD7, 12 }, { 0x3F55, 14 }, {   0x77,  7 },
+        {   0x30,  6 }, {    0x3,  3 }, {    0x4,  3 }, {   0x1A,  5 },
+        {   0x19,  5 }, {   0x7F,  7 }, {  0x1FB,  9 }, {  0x3F4, 10 },
+        {  0xFD6, 12 }, { 0x1FA9, 13 }, { 0x3F54, 14 }, { 0x3F57, 14 },
+        { 0x3F56, 14 }, { 0x3F51, 14 }, { 0x3F50, 14 }, {    0x1,  3 },
+        {    0x4,  4 }, {   0x1C,  5 }, {    0xB,  5 }, {    0xA,  5 },
+        {    0x0,  3 }, {   0x1B,  5 }, {   0x31,  6 }, {   0x76,  7 }
+    },
+    { /* AC bias group 2, table 15 */
+        {    0x5,  3 }, {    0xC,  4 }, {   0x1B,  5 }, {    0x8,  4 },
+        {   0x38,  6 }, {   0x15,  8 }, {   0xA3, 11 }, {   0xE6,  8 },
+        {    0x4,  6 }, {    0x1,  3 }, {    0x2,  3 }, {   0x12,  5 },
+        {    0x3,  5 }, {    0xB,  7 }, {   0x29,  9 }, {   0xA0, 11 },
+        {  0x142, 12 }, {  0x287, 13 }, {  0x286, 13 }, {  0x289, 13 },
+        {  0x288, 13 }, {  0x28B, 13 }, {  0x28A, 13 }, {    0xF,  4 },
+        {   0x1D,  5 }, {   0x13,  5 }, {    0x1,  5 }, {    0x0,  5 },
+        {    0x3,  3 }, {   0x1A,  5 }, {   0x72,  7 }, {   0xE7,  8 }
+    }
+};
+
+static const uint16_t vp4_ac_bias_2[16][32][2] = {
+    { /* AC bias group 3, table 0 */
+        {    0x9,  5 }, {   0x15,  7 }, {   0x28,  8 }, {   0x52,  9 },
+        {  0x29A, 12 }, {  0x537, 13 }, {  0x536, 13 }, {    0xA,  5 },
+        {   0x54,  7 }, {    0x4,  3 }, {    0x3,  3 }, {    0xC,  4 },
+        {    0xB,  4 }, {    0xD,  4 }, {    0x3,  4 }, {   0x14,  5 },
+        {   0x3A,  6 }, {    0x4,  5 }, {   0x38,  6 }, {   0x55,  7 },
+        {   0xA7, 10 }, {  0x299, 12 }, {  0x298, 12 }, {    0x0,  3 },
+        {   0x1E,  5 }, {    0x8,  5 }, {   0x2B,  6 }, {    0xB,  6 },
+        {    0xB,  5 }, {   0x3B,  6 }, {   0x1F,  5 }, {   0x39,  6 }
+    },
+    { /* AC bias group 3, table 1 */
+        {   0x1D,  5 }, {   0x2F,  7 }, {    0x2,  8 }, {    0x7,  9 },
+        {   0x19, 11 }, {   0x35, 12 }, {   0x34, 12 }, {    0x9,  5 },
+        {   0x2E,  7 }, {    0x6,  3 }, {    0x5,  3 }, {    0x9,  4 },
+        {    0x8,  4 }, {    0x7,  4 }, {   0x1F,  5 }, {    0x8,  5 },
+        {   0x18,  6 }, {   0x19,  6 }, {    0x1,  6 }, {    0x0,  7 },
+        {   0x18, 11 }, {   0x37, 12 }, {   0x36, 12 }, {    0x1,  3 },
+        {    0x1,  4 }, {    0xA,  5 }, {   0x39,  6 }, {   0x16,  6 },
+        {    0xD,  5 }, {    0x1,  5 }, {   0x1E,  5 }, {   0x38,  6 }
+    },
+    { /* AC bias group 3, table 2 */
+        {    0x1,  4 }, {   0x71,  7 }, {   0xE0,  8 }, {  0x1C3,  9 },
+        {  0x708, 11 }, { 0x1C26, 13 }, { 0x384F, 14 }, {    0x1,  5 },
+        {   0x31,  7 }, {    0x6,  3 }, {    0x5,  3 }, {    0x9,  4 },
+        {    0x8,  4 }, {    0x5,  4 }, {    0xF,  5 }, {   0x39,  6 },
+        {   0x77,  7 }, {   0x76,  7 }, {   0x30,  7 }, {  0x385, 10 },
+        { 0x384E, 14 }, { 0x1C25, 13 }, { 0x1C24, 13 }, {    0x1,  3 },
+        {    0x4,  4 }, {    0xD,  5 }, {    0x0,  5 }, {   0x19,  6 },
+        {   0x1F,  5 }, {    0xE,  5 }, {   0x1E,  5 }, {   0x3A,  6 }
+    },
+    { /* AC bias group 3, table 3 */
+        {    0x6,  4 }, {    0xC,  6 }, {   0xD6,  8 }, {   0x7B,  8 },
+        {  0x1E8, 10 }, {  0x7A4, 12 }, {  0xF4B, 13 }, {   0x36,  6 },
+        {   0x6A,  7 }, {    0x7,  3 }, {    0x5,  3 }, {    0x8,  4 },
+        {    0x9,  4 }, {    0x1,  4 }, {    0x7,  5 }, {    0xD,  6 },
+        {   0x3C,  7 }, {   0xD7,  8 }, {   0xF5,  9 }, {  0x7A7, 12 },
+        {  0xF4A, 13 }, {  0xF4D, 13 }, {  0xF4C, 13 }, {    0x2,  3 },
+        {    0x2,  4 }, {    0xE,  5 }, {   0x37,  6 }, {   0x34,  6 },
+        {    0x0,  4 }, {   0x19,  5 }, {   0x18,  5 }, {   0x1F,  6 }
+    },
+    { /* AC bias group 3, table 4 */
+        {    0xA,  4 }, {   0x27,  6 }, {   0xBF,  8 }, {   0xBE,  8 },
+        {  0x224, 10 }, { 0x225D, 14 }, { 0x225C, 14 }, {   0x26,  6 },
+        {   0x5E,  7 }, {    0x7,  3 }, {    0x6,  3 }, {    0x6,  4 },
+        {    0x7,  4 }, {   0x16,  5 }, {   0x2E,  6 }, {   0x45,  7 },
+        {   0x88,  8 }, {  0x113,  9 }, {  0x44A, 11 }, { 0x225F, 14 },
+        { 0x225E, 14 }, { 0x112D, 13 }, { 0x112C, 13 }, {    0x2,  3 },
+        {    0x2,  4 }, {   0x12,  5 }, {    0x3,  5 }, {    0x2,  5 },
+        {    0x3,  4 }, {    0x0,  4 }, {   0x10,  5 }, {   0x23,  6 }
+    },
+    { /* AC bias group 3, table 5 */
+        {    0xF,  4 }, {    0x6,  5 }, {   0x75,  7 }, {   0x74,  7 },
+        {    0xA,  9 }, {   0xBF, 13 }, {   0xB9, 13 }, {   0x22,  6 },
+        {    0x3,  7 }, {    0x5,  3 }, {    0x6,  3 }, {    0x1,  4 },
+        {    0x2,  4 }, {    0x7,  5 }, {    0x0,  6 }, {    0x4,  8 },
+        {   0x16, 10 }, {   0x5E, 12 }, {   0xB8, 13 }, {   0xBB, 13 },
+        {   0xBA, 13 }, {  0x17D, 14 }, {  0x17C, 14 }, {    0x2,  3 },
+        {    0x6,  4 }, {   0x1C,  5 }, {   0x10,  5 }, {   0x3B,  6 },
+        {    0x9,  4 }, {    0x7,  4 }, {    0x1,  5 }, {   0x23,  6 }
+    },
+    { /* AC bias group 3, table 6 */
+        {    0x1,  3 }, {   0x1C,  5 }, {   0x36,  6 }, {   0x3B,  6 },
+        {   0xEA,  8 }, {  0x75B, 11 }, { 0x1D65, 13 }, {   0x19,  6 },
+        {   0x74,  7 }, {    0x4,  3 }, {    0x5,  3 }, {    0x0,  4 },
+        {    0x1,  4 }, {   0x37,  6 }, {  0x1D7,  9 }, {  0x75A, 11 },
+        { 0x1D64, 13 }, { 0x1D67, 13 }, { 0x1D66, 13 }, { 0x1D61, 13 },
+        { 0x1D60, 13 }, { 0x1D63, 13 }, { 0x1D62, 13 }, {    0x2,  3 },
+        {   0x1F,  5 }, {   0x1A,  5 }, {    0xD,  5 }, {   0x3D,  6 },
+        {    0xC,  4 }, {    0x7,  4 }, {   0x3C,  6 }, {   0x18,  6 }
+    },
+    { /* AC bias group 3, table 7 */
+        {    0x2,  3 }, {    0x1,  4 }, {   0x14,  5 }, {    0x0,  4 },
+        {   0x2F,  6 }, {   0xBB,  8 }, {  0x2E4, 10 }, {   0x7D,  7 },
+        {   0xBA,  8 }, {    0x3,  3 }, {    0x4,  3 }, {   0x16,  5 },
+        {   0x1A,  5 }, {   0xB8,  8 }, { 0x172E, 13 }, { 0x2E5F, 14 },
+        { 0x2E5E, 14 }, { 0x1729, 13 }, { 0x1728, 13 }, { 0x172B, 13 },
+        { 0x172A, 13 }, { 0x172D, 13 }, { 0x172C, 13 }, {    0x1,  3 },
+        {   0x1E,  5 }, {   0x15,  5 }, {   0x1B,  5 }, {   0x3F,  6 },
+        {    0xC,  4 }, {    0xE,  4 }, {   0x7C,  7 }, {  0x173,  9 }
+    },
+    { /* AC bias group 3, table 8 */
+        {    0x3,  4 }, {   0x7B,  7 }, {   0x58,  8 }, {  0x1EA,  9 },
+        { 0x1EB1, 13 }, { 0x1EB0, 13 }, { 0x1EB3, 13 }, {   0x13,  6 },
+        {   0x12,  6 }, {    0x5,  3 }, {    0x6,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {   0x13,  5 }, {   0x3C,  6 }, {   0x2D,  7 },
+        {   0xF4,  8 }, {   0x59,  8 }, {  0x3D7, 10 }, {  0xF5B, 12 },
+        { 0x1EB2, 13 }, { 0x1EB5, 13 }, { 0x1EB4, 13 }, {    0x3,  3 },
+        {    0xE,  4 }, {   0x1F,  5 }, {   0x12,  5 }, {    0x8,  5 },
+        {    0x8,  4 }, {    0x0,  4 }, {    0xA,  5 }, {   0x17,  6 }
+    },
+    { /* AC bias group 3, table 9 */
+        {    0x8,  4 }, {   0x3C,  6 }, {   0xF5,  8 }, {   0xF4,  8 },
+        { 0x1EF7, 13 }, { 0x3DE9, 14 }, { 0x3DE8, 14 }, {   0x1C,  6 },
+        {    0xD,  6 }, {    0x5,  3 }, {    0x6,  3 }, {    0x1,  4 },
+        {    0x0,  4 }, {    0x7,  5 }, {    0xC,  6 }, {   0xF6,  8 },
+        {  0x1EE,  9 }, {  0x3DF, 10 }, {  0x7BC, 11 }, { 0x3DEB, 14 },
+        { 0x3DEA, 14 }, { 0x3DED, 14 }, { 0x3DEC, 14 }, {    0x2,  3 },
+        {    0x9,  4 }, {   0x1F,  5 }, {    0xF,  5 }, {    0x5,  5 },
+        {    0xE,  4 }, {    0x6,  4 }, {    0x4,  5 }, {   0x1D,  6 }
+    },
+    { /* AC bias group 3, table 10 */
+        {    0x9,  4 }, {   0x39,  6 }, {   0x19,  7 }, {   0x18,  7 },
+        {  0x706, 11 }, { 0x383D, 14 }, { 0x383C, 14 }, {    0xD,  6 },
+        {    0xF,  6 }, {    0x5,  3 }, {    0x6,  3 }, {    0x0,  4 },
+        {   0x1D,  5 }, {    0x3,  5 }, {   0x71,  7 }, {   0xE1,  8 },
+        {  0x1C0,  9 }, {  0x382, 10 }, { 0x1C1D, 13 }, { 0x383F, 14 },
+        { 0x383E, 14 }, { 0x3839, 14 }, { 0x3838, 14 }, {    0x2,  3 },
+        {    0x8,  4 }, {    0x2,  4 }, {    0xD,  5 }, {    0xC,  5 },
+        {    0xF,  4 }, {    0x7,  4 }, {    0x2,  5 }, {    0xE,  6 }
+    },
+    { /* AC bias group 3, table 11 */
+        {    0x0,  3 }, {    0x6,  5 }, {   0x35,  7 }, {   0x34,  7 },
+        {  0x777, 11 }, { 0x1DD4, 13 }, { 0x3BAB, 14 }, {    0xE,  6 },
+        {    0xF,  6 }, {    0x5,  3 }, {    0x4,  3 }, {   0x1C,  5 },
+        {   0x19,  5 }, {   0x3A,  6 }, {   0xEF,  8 }, {  0x1DC,  9 },
+        {  0x776, 11 }, {  0x774, 11 }, { 0x3BAA, 14 }, { 0x3BAD, 14 },
+        { 0x3BAC, 14 }, { 0x3BAF, 14 }, { 0x3BAE, 14 }, {    0x2,  3 },
+        {    0x7,  4 }, {    0x2,  4 }, {   0x18,  5 }, {    0xC,  5 },
+        {    0xF,  4 }, {    0xD,  4 }, {   0x1B,  6 }, {   0x76,  7 }
+    },
+    { /* AC bias group 3, table 12 */
+        {    0x2,  3 }, {   0x11,  5 }, {    0x6,  6 }, {   0x4F,  7 },
+        {  0x130,  9 }, { 0x1319, 13 }, { 0x1318, 13 }, {   0x4E,  7 },
+        {    0x7,  6 }, {    0x6,  3 }, {    0x5,  3 }, {   0x10,  5 },
+        {    0xD,  5 }, {    0x5,  6 }, {   0x99,  8 }, {  0x262, 10 },
+        {  0x98E, 12 }, { 0x131B, 13 }, { 0x131A, 13 }, { 0x263D, 14 },
+        { 0x263C, 14 }, { 0x263F, 14 }, { 0x263E, 14 }, {    0x1,  3 },
+        {    0x7,  4 }, {    0x0,  4 }, {   0x12,  5 }, {    0xC,  5 },
+        {    0xE,  4 }, {    0xF,  4 }, {    0x4,  6 }, {   0x4D,  7 }
+    },
+    { /* AC bias group 3, table 13 */
+        {    0x3,  3 }, {    0x0,  4 }, {    0x2,  5 }, {   0x37,  6 },
+        {  0x1B7,  9 }, {  0xDB5, 12 }, { 0x36DD, 14 }, {   0x6C,  7 },
+        {   0x16,  6 }, {    0x5,  3 }, {    0x4,  3 }, {    0x3,  5 },
+        {    0xA,  5 }, {   0x2E,  7 }, {  0x36C, 10 }, {  0xDB4, 12 },
+        { 0x36DC, 14 }, { 0x36DF, 14 }, { 0x36DE, 14 }, { 0x36D9, 14 },
+        { 0x36D8, 14 }, { 0x36DB, 14 }, { 0x36DA, 14 }, {    0xE,  4 },
+        {    0x4,  4 }, {   0x1A,  5 }, {   0x19,  5 }, {   0x18,  5 },
+        {    0xF,  4 }, {    0x1,  3 }, {   0x2F,  7 }, {   0xDA,  8 }
+    },
+    { /* AC bias group 3, table 14 */
+        {    0x6,  3 }, {    0x6,  4 }, {    0xF,  5 }, {    0x0,  4 },
+        {   0x75,  7 }, {  0x3B8, 10 }, { 0x1DCA, 13 }, {   0x74,  7 },
+        {   0x76,  7 }, {    0x4,  3 }, {    0x5,  3 }, {    0x3,  5 },
+        {    0x2,  5 }, {  0x1DE,  9 }, {  0xEE6, 12 }, { 0x3B97, 14 },
+        { 0x3B96, 14 }, { 0x3B9D, 14 }, { 0x3B9C, 14 }, { 0x3B9F, 14 },
+        { 0x3B9E, 14 }, { 0x1DC9, 13 }, { 0x1DC8, 13 }, {    0x5,  4 },
+        {   0x1C,  5 }, {    0x9,  5 }, {    0xE,  5 }, {    0x8,  5 },
+        {    0xF,  4 }, {    0x1,  3 }, {  0x1DF,  9 }, {  0x1DD,  9 }
+    },
+    { /* AC bias group 3, table 15 */
+        {    0x4,  3 }, {    0xB,  4 }, {   0x1D,  5 }, {    0xC,  4 },
+        {   0x14,  5 }, {   0xE0,  8 }, { 0x3875, 14 }, {  0x386, 10 },
+        {  0x1C2,  9 }, {    0x0,  2 }, {    0x1,  2 }, {   0x71,  7 },
+        {   0x72,  7 }, { 0x1C3F, 13 }, { 0x3874, 14 }, { 0x3877, 14 },
+        { 0x3876, 14 }, { 0x3871, 14 }, { 0x3870, 14 }, { 0x3873, 14 },
+        { 0x3872, 14 }, { 0x3879, 14 }, { 0x3878, 14 }, {   0x3C,  6 },
+        {   0x73,  7 }, {   0x2A,  6 }, {   0x3D,  6 }, {   0x2B,  6 },
+        {   0x1F,  5 }, {    0xD,  4 }, { 0x1C3E, 13 }, { 0x1C3D, 13 }
+    }
+};
+
+static const uint16_t vp4_ac_bias_3[16][32][2] = {
+    { /* AC bias group 4, table 0 */
+        {    0x7,  4 }, {    0xF,  6 }, {   0xBB,  8 }, {   0xBA,  8 },
+        {  0x5CF, 11 }, { 0x173A, 13 }, { 0x2E77, 14 }, {   0x29,  6 },
+        {  0x172,  9 }, {    0x7,  3 }, {    0x6,  3 }, {    0x9,  4 },
+        {    0x8,  4 }, {    0x1,  4 }, {    0x5,  5 }, {    0xD,  6 },
+        {   0x1D,  7 }, {   0x1C,  7 }, {   0xB8,  8 }, {  0x2E6, 10 },
+        { 0x2E76, 14 }, { 0x1739, 13 }, { 0x1738, 13 }, {    0x2,  3 },
+        {    0x6,  4 }, {   0x16,  5 }, {    0x4,  5 }, {   0x28,  6 },
+        {   0x15,  5 }, {    0xC,  6 }, {    0x0,  4 }, {   0x2F,  6 }
+    },
+    { /* AC bias group 4, table 1 */
+        {    0xB,  4 }, {    0x2,  5 }, {   0x54,  7 }, {   0x2F,  7 },
+        {  0x2AC, 10 }, { 0x156B, 13 }, { 0x1568, 13 }, {   0x16,  6 },
+        {  0x154,  9 }, {    0x7,  3 }, {    0x6,  3 }, {    0x4,  4 },
+        {    0x3,  4 }, {   0x13,  5 }, {   0x28,  6 }, {   0x2E,  7 },
+        {  0x157,  9 }, {  0x155,  9 }, {  0x55B, 11 }, { 0x2AD3, 14 },
+        { 0x2AD2, 14 }, { 0x2AD5, 14 }, { 0x2AD4, 14 }, {    0x3,  3 },
+        {    0x8,  4 }, {    0x0,  4 }, {    0xA,  5 }, {    0x3,  5 },
+        {    0x2,  4 }, {   0x2B,  6 }, {   0x12,  5 }, {   0x29,  6 }
+    },
+    { /* AC bias group 4, table 2 */
+        {    0xF,  4 }, {    0x7,  5 }, {    0x1,  6 }, {    0x0,  6 },
+        {  0x1C4,  9 }, {  0x703, 11 }, {  0xE02, 12 }, {   0x11,  6 },
+        {   0xE1,  8 }, {    0x5,  3 }, {    0x6,  3 }, {    0x2,  4 },
+        {    0x1,  4 }, {    0x9,  5 }, {   0x10,  6 }, {   0xE3,  8 },
+        {  0x1C5,  9 }, {  0x1C1,  9 }, {  0x702, 11 }, { 0x1C07, 13 },
+        { 0x1C06, 13 }, {  0xE01, 12 }, {  0xE00, 12 }, {    0x4,  3 },
+        {    0x7,  4 }, {   0x1D,  5 }, {    0xD,  5 }, {    0x1,  5 },
+        {    0x5,  4 }, {    0x6,  5 }, {    0xC,  5 }, {   0x39,  6 }
+    },
+    { /* AC bias group 4, table 3 */
+        {    0x1,  3 }, {   0x1C,  5 }, {   0x11,  6 }, {   0x13,  6 },
+        {   0x42,  8 }, {  0x207, 11 }, {  0x815, 13 }, {   0x75,  7 },
+        {   0x41,  8 }, {    0x5,  3 }, {    0x6,  3 }, {    0x0,  4 },
+        {   0x1F,  5 }, {   0x3B,  6 }, {   0x74,  7 }, {   0x43,  8 },
+        {   0x80,  9 }, {  0x206, 11 }, {  0x814, 13 }, {  0x817, 13 },
+        {  0x816, 13 }, {  0x409, 12 }, {  0x408, 12 }, {    0x3,  3 },
+        {    0x9,  4 }, {   0x1E,  5 }, {   0x11,  5 }, {    0x3,  5 },
+        {    0x5,  4 }, {   0x10,  5 }, {    0x2,  5 }, {   0x12,  6 }
+    },
+    { /* AC bias group 4, table 4 */
+        {    0x1,  3 }, {   0x1F,  5 }, {   0x27,  6 }, {    0x1,  5 },
+        {   0x4B,  8 }, {  0x123, 10 }, {  0x915, 13 }, {    0x0,  6 },
+        {   0x49,  8 }, {    0x5,  3 }, {    0x6,  3 }, {   0x1D,  5 },
+        {   0x1C,  5 }, {   0x13,  6 }, {   0x4A,  8 }, {   0x90,  9 },
+        {  0x914, 13 }, {  0x917, 13 }, {  0x916, 13 }, {  0x911, 13 },
+        {  0x910, 13 }, {  0x913, 13 }, {  0x912, 13 }, {    0x3,  3 },
+        {    0x5,  4 }, {    0x1,  4 }, {   0x12,  5 }, {    0x8,  5 },
+        {    0x8,  4 }, {   0x1E,  5 }, {   0x26,  6 }, {    0x1,  6 }
+    },
+    { /* AC bias group 4, table 5 */
+        {    0x3,  3 }, {    0x1,  4 }, {   0x3F,  6 }, {    0xB,  5 },
+        {   0x4E,  7 }, {  0x132,  9 }, {  0x99A, 12 }, {   0x4F,  7 },
+        {   0x98,  8 }, {    0x6,  3 }, {    0x5,  3 }, {   0x1D,  5 },
+        {   0x1C,  5 }, {   0x7C,  7 }, {  0x267, 10 }, { 0x1331, 13 },
+        { 0x1330, 13 }, { 0x1333, 13 }, { 0x1332, 13 }, { 0x266D, 14 },
+        { 0x266C, 14 }, { 0x266F, 14 }, { 0x266E, 14 }, {    0x1,  3 },
+        {    0x4,  4 }, {   0x1E,  5 }, {   0x12,  5 }, {    0xA,  5 },
+        {    0x8,  4 }, {    0x0,  4 }, {   0x7D,  7 }, {   0x4D,  7 }
+    },
+    { /* AC bias group 4, table 6 */
+        {    0x2,  3 }, {    0x7,  4 }, {   0x15,  5 }, {    0x3,  4 },
+        {    0x4,  5 }, {   0xA7,  8 }, {  0x536, 11 }, {   0x28,  6 },
+        {  0x29A, 10 }, {    0x6,  3 }, {    0x4,  3 }, {   0x1C,  5 },
+        {   0x17,  5 }, {   0xA4,  8 }, { 0x29BE, 14 }, { 0x537F, 15 },
+        { 0x537E, 15 }, { 0x29B9, 14 }, { 0x29B8, 14 }, { 0x29BB, 14 },
+        { 0x29BA, 14 }, { 0x29BD, 14 }, { 0x29BC, 14 }, {    0xF,  4 },
+        {    0x0,  4 }, {    0x5,  5 }, {   0x16,  5 }, {   0x1D,  5 },
+        {    0x6,  4 }, {    0x1,  4 }, {   0xA5,  8 }, {  0x14C,  9 }
+    },
+    { /* AC bias group 4, table 7 */
+        {    0x4,  3 }, {    0x7,  4 }, {   0x1A,  5 }, {    0xC,  4 },
+        {    0x6,  4 }, {   0x29,  6 }, {  0x1BD,  9 }, { 0x1BE3, 13 },
+        { 0x1BE0, 13 }, {    0x0,  2 }, {    0x7,  3 }, {   0x6E,  7 },
+        {  0x1BC,  9 }, { 0x37C3, 14 }, { 0x37C2, 14 }, { 0x37CD, 14 },
+        { 0x37CC, 14 }, { 0x37CF, 14 }, { 0x37CE, 14 }, { 0x37C9, 14 },
+        { 0x37C8, 14 }, { 0x37CB, 14 }, { 0x37CA, 14 }, {   0x15,  5 },
+        {  0x1BF,  9 }, {  0x37D, 10 }, {   0x36,  6 }, {    0x2,  3 },
+        {    0xB,  4 }, {   0x28,  6 }, { 0x37C5, 14 }, { 0x37C4, 14 }
+    },
+    { /* AC bias group 4, table 8 */
+        {    0x1,  3 }, {    0x9,  5 }, {    0x3,  6 }, {    0x2,  6 },
+        {  0x11F, 10 }, {  0x8E9, 13 }, {  0x8E8, 13 }, {   0x2D,  7 },
+        {   0x22,  7 }, {    0x6,  3 }, {    0x7,  3 }, {   0x10,  5 },
+        {   0x11,  5 }, {   0x17,  6 }, {   0x2C,  7 }, {   0x46,  8 },
+        {  0x11E, 10 }, {  0x11C, 10 }, {  0x477, 12 }, {  0x8EB, 13 },
+        {  0x8EA, 13 }, {  0x8ED, 13 }, {  0x8EC, 13 }, {    0x3,  3 },
+        {    0xB,  4 }, {    0x1,  4 }, {   0x14,  5 }, {    0xA,  5 },
+        {    0x9,  4 }, {   0x15,  5 }, {    0x0,  5 }, {   0x10,  6 }
+    },
+    { /* AC bias group 4, table 9 */
+        {    0x1,  3 }, {   0x1D,  5 }, {   0x22,  6 }, {   0x13,  6 },
+        {  0x11E,  9 }, {  0x8FC, 12 }, { 0x23F5, 14 }, {   0x23,  7 },
+        {   0x22,  7 }, {    0x5,  3 }, {    0x6,  3 }, {   0x10,  5 },
+        {    0xB,  5 }, {   0x10,  6 }, {   0x8E,  8 }, {  0x23E, 10 },
+        {  0x8FF, 12 }, { 0x11FD, 13 }, { 0x23F4, 14 }, { 0x23F7, 14 },
+        { 0x23F6, 14 }, { 0x23F9, 14 }, { 0x23F8, 14 }, {    0x3,  3 },
+        {    0x9,  4 }, {    0x0,  4 }, {   0x1C,  5 }, {    0xA,  5 },
+        {    0xF,  4 }, {    0x1,  4 }, {   0x12,  6 }, {   0x46,  7 }
+    },
+    { /* AC bias group 4, table 10 */
+        {    0x3,  3 }, {   0x1F,  5 }, {   0x3C,  6 }, {   0x3D,  6 },
+        {   0x86,  8 }, {  0x877, 12 }, { 0x10E8, 13 }, {   0x41,  7 },
+        {   0x40,  7 }, {    0x5,  3 }, {    0x6,  3 }, {    0x7,  5 },
+        {    0x6,  5 }, {    0x4,  6 }, {  0x10F,  9 }, {  0x21C, 10 },
+        {  0x875, 12 }, { 0x21D3, 14 }, { 0x21D2, 14 }, { 0x21D9, 14 },
+        { 0x21D8, 14 }, { 0x21DB, 14 }, { 0x21DA, 14 }, {    0x2,  3 },
+        {    0x9,  4 }, {    0x0,  4 }, {   0x11,  5 }, {    0x3,  5 },
+        {    0xE,  4 }, {    0x2,  4 }, {    0x5,  6 }, {   0x42,  7 }
+    },
+    { /* AC bias group 4, table 11 */
+        {    0x4,  3 }, {    0x1,  4 }, {   0x3D,  6 }, {    0x9,  5 },
+        {   0xF3,  8 }, {  0x793, 11 }, { 0x1E45, 13 }, {    0x0,  7 },
+        {    0x2,  7 }, {    0x5,  3 }, {    0x6,  3 }, {    0x8,  5 },
+        {    0x1,  5 }, {    0x3,  7 }, {  0x1E5,  9 }, {  0x792, 11 },
+        { 0x1E44, 13 }, { 0x1E47, 13 }, { 0x1E46, 13 }, { 0x1E41, 13 },
+        { 0x1E40, 13 }, { 0x1E43, 13 }, { 0x1E42, 13 }, {    0x1,  3 },
+        {    0x6,  4 }, {   0x1F,  5 }, {    0xF,  5 }, {    0xE,  5 },
+        {    0xE,  4 }, {    0x5,  4 }, {   0x78,  7 }, {    0x1,  7 }
+    },
+    { /* AC bias group 4, table 12 */
+        {    0x4,  3 }, {    0x5,  4 }, {    0xE,  5 }, {   0x17,  5 },
+        {   0x3E,  7 }, {   0xF0,  9 }, {  0xF1E, 13 }, {   0x7A,  8 },
+        {   0x7F,  8 }, {    0x6,  3 }, {    0x7,  3 }, {    0x5,  5 },
+        {    0x4,  5 }, {   0x7B,  8 }, {  0x1E2, 10 }, { 0x1E3F, 14 },
+        { 0x1E3E, 14 }, {  0xF19, 13 }, {  0xF18, 13 }, {  0xF1B, 13 },
+        {  0xF1A, 13 }, {  0xF1D, 13 }, {  0xF1C, 13 }, {    0x0,  3 },
+        {    0x3,  4 }, {   0x16,  5 }, {    0x9,  5 }, {    0x8,  5 },
+        {    0xA,  4 }, {    0x6,  4 }, {   0x7E,  8 }, {   0x79,  8 }
+    },
+    { /* AC bias group 4, table 13 */
+        {    0x5,  3 }, {    0xC,  4 }, {   0x1A,  5 }, {    0x4,  4 },
+        {   0x1A,  6 }, {   0xDE,  9 }, {  0xDF4, 13 }, {   0xDD,  9 },
+        {   0x6D,  8 }, {    0x0,  2 }, {    0x7,  3 }, {   0x25,  6 },
+        {   0x24,  6 }, {   0xDC,  9 }, {  0xDF7, 13 }, { 0x1BEB, 14 },
+        { 0x1BEA, 14 }, {  0xDF1, 13 }, {  0xDF0, 13 }, {  0xDF3, 13 },
+        {  0xDF2, 13 }, { 0x1BED, 14 }, { 0x1BEC, 14 }, {    0x8,  4 },
+        {   0x13,  5 }, {    0xC,  5 }, {   0x37,  6 }, {   0x36,  6 },
+        {    0x5,  4 }, {    0x7,  4 }, {   0x6C,  8 }, {  0x1BF, 10 }
+    },
+    { /* AC bias group 4, table 14 */
+        {    0x5,  3 }, {    0xD,  4 }, {   0x1F,  5 }, {    0xC,  4 },
+        {   0x3B,  6 }, {   0x40,  7 }, {  0x41A, 11 }, {  0x104,  9 },
+        {  0x107,  9 }, {    0x1,  2 }, {    0x0,  2 }, {   0x24,  6 },
+        {   0x21,  6 }, {  0x20B, 10 }, { 0x106E, 13 }, { 0x20DF, 14 },
+        { 0x20DE, 14 }, { 0x1055, 13 }, { 0x1054, 13 }, { 0x1057, 13 },
+        { 0x1056, 13 }, { 0x106D, 13 }, { 0x106C, 13 }, {   0x11,  5 },
+        {   0x3A,  6 }, {   0x25,  6 }, {   0x38,  6 }, {   0x39,  6 },
+        {   0x13,  5 }, {   0x1E,  5 }, {  0x20C, 10 }, {  0x414, 11 }
+    },
+    { /* AC bias group 4, table 15 */
+        {    0x0,  2 }, {    0x7,  4 }, {    0xD,  5 }, {    0x5,  4 },
+        {    0x9,  5 }, {   0x22,  7 }, {  0xCD1, 13 }, {  0xCD0, 13 },
+        {  0xCD3, 13 }, {    0x3,  2 }, {    0x2,  2 }, {   0x8D,  9 },
+        {   0xCC,  9 }, {  0x66B, 12 }, {  0xCD2, 13 }, { 0x19B5, 14 },
+        { 0x19B4, 14 }, { 0x19B7, 14 }, { 0x19B6, 14 }, { 0x19B1, 14 },
+        { 0x19B0, 14 }, { 0x19B3, 14 }, { 0x19B2, 14 }, {   0x47,  8 },
+        {   0x8C,  9 }, {  0x337, 11 }, {   0x67,  8 }, {   0x18,  6 },
+        {   0x10,  6 }, {   0x32,  7 }, {  0xCD5, 13 }, {  0xCD4, 13 }
+    }
+};
+
+#endif /* AVCODEC_VP4DATA_H */