diff mbox

[FFmpeg-devel,2/2] avcodec: add bink2 video decoder

Message ID 20190327202147.25502-2-onemda@gmail.com
State New
Headers show

Commit Message

Paul B Mahol March 27, 2019, 8:21 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
Missing deblocking.
---
 configure               |    1 +
 libavcodec/Makefile     |    1 +
 libavcodec/allcodecs.c  |    1 +
 libavcodec/avcodec.h    |    1 +
 libavcodec/bink2.c      |  787 +++++++++++++++++++++++
 libavcodec/bink2f.c     | 1139 +++++++++++++++++++++++++++++++++
 libavcodec/bink2g.c     | 1342 +++++++++++++++++++++++++++++++++++++++
 libavcodec/codec_desc.c |    7 +
 libavformat/bink.c      |    3 +-
 9 files changed, 3280 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/bink2.c
 create mode 100644 libavcodec/bink2f.c
 create mode 100644 libavcodec/bink2g.c

Comments

Carl Eugen Hoyos March 27, 2019, 11:30 p.m. UTC | #1
2019-03-27 21:21 GMT+01:00, Paul B Mahol <onemda@gmail.com>:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
> Missing deblocking.

Patch contains an "if (0 && ..." somewhere, I assume this
is unintended.

Carl Eugen
Paul B Mahol March 28, 2019, 8:42 a.m. UTC | #2
On 3/28/19, Carl Eugen Hoyos <ceffmpeg@gmail.com> wrote:
> 2019-03-27 21:21 GMT+01:00, Paul B Mahol <onemda@gmail.com>:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>> Missing deblocking.
>
> Patch contains an "if (0 && ..." somewhere, I assume this
> is unintended.
>

Fixed locally.

> 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".
Peter Ross April 6, 2019, 11:15 p.m. UTC | #3
On Wed, Mar 27, 2019 at 09:21:47PM +0100, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
> Missing deblocking.
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  787 +++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1139 +++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1342 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-

my comments below.

this is a mammoth amount of work deserving of a better quality review.

> +++ b/libavcodec/bink2.c
> @@ -0,0 +1,787 @@
> +/*
> + * Bink video 2 decoder
> + * Copyright (c) 2014 Konstantin Shishkov
> + * Copyright (c) 2019 Paul B Mahol
> + *

> +static const uint8_t luma_repos[] = {
> +    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
> +};

identical to msvideo1enc.c remap
consider moving to libavcodec/mathops.h

> +static const int32_t bink2g_dc_pat[] = {
> +    1024, 1218, 1448, 1722, 2048,
> +    2435, 2896, 3444, 4096, 4871,
> +    5793, 6889, 8192, 9742, 11585, 13777, 16384,
> +    19484, 23170,  27555, 32768, 38968, 46341,
> +    55109, 65536, 77936, 92682, 110218, 131072,
> +    155872, 185364, 220436, 262144, 311744,
> +    370728, 440872, 524288,
> +};

this is so close to ff_dirac_qscale_tab it is not funny.

> +     3, 24, 11, 18, 25, 13, 14,  4,
> +    15,  5,  6,  7, 12, 19, 20, 21,
> +    22, 23, 26, 27, 28, 29, 30, 31,
> +    32, 33, 34, 35, 36, 37, 38, 39,
> +    40, 41, 42, 43, 44, 45, 46, 47,
> +    48, 49, 50, 51, 52, 53, 54, 55,
> +    56, 57, 58, 59, 60, 61, 62, 63
> +};
> +
> +static const uint8_t bink2g_scan[64] = {
> +     0,   8,   1,   2,  9,  16,  24,  17,
> +    10,   3,   4,  11, 18,  25,  32,  40,
> +    33,  26,  19,  12,  5,   6,  13,  20,
> +    27,  34,  41,  48, 56,  49,  42,  35,
> +    28,  21,  14,   7, 15,  22,  29,  36,
> +    43,  50,  57,  58, 51,  44,  37,  30,
> +    23,  31,  38,  45, 52,  59,  60,  53,
> +    46,  39,  47,  54, 61,  62,  55,  63,
> +};

this table has more white space than the other scan tables...

> +enum BlockTypes {
> +    INTRA_BLOCK = 0, ///< intra DCT block
> +    SKIP_BLOCK,      ///< skipped block
> +    MOTION_BLOCK,    ///< block is copied from previous frame with some offset
> +    RESIDUE_BLOCK,   ///< motion block with some difference added
> +};
> +
> +static const uint8_t ones_count[16] = {
> +    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
> +};

duplicate of libavcodec/vc1_mc.c popcount4

> +static int bink2_decode_frame(AVCodecContext *avctx, void *data,
> +                              int *got_frame, AVPacket *pkt)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +    GetBitContext *gb = &c->gb;
> +    AVFrame *frame = data;
> +    uint8_t *dst[4];
> +    uint8_t *src[4];
> +    int stride[4];
> +    int sstride[4];
> +    uint32_t off = 0;
> +    int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY);
> +    int ret, w, h;
> +    int height_a;
> +
> +    w = avctx->width;
> +    h = avctx->height;
> +    ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32));
> +    if (ret < 0)
> +        return ret;
> +    avctx->width  = w;
> +    avctx->height = h;
> +
> +    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
> +        return ret;

ret error handling style is inconsistent

> +static int bink2f_decode_inter_luma(Bink2Context *c,
> +                                    float block[4][64],
> +                                    unsigned *prev_cbp, int *prev_q,
> +                                    uint8_t *dst, int stride,
> +                                    int flags)
> +{
> +    GetBitContext *gb = &c->gb;
> +    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
> +    unsigned cbp;
> +    int q, dq;
> +
> +    *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp);
> +    dq = bink2f_decode_delta_q(gb);
> +    q = *prev_q + dq;
> +    if (q < 0 || q >= 16)
> +        return AVERROR_INVALIDDATA;
> +    *prev_q = q;
> +
> +    bink2f_decode_dc(c, gb, dc, 1, q, -1023, 1023, 0xA8);
> +
> +    for (int i = 0; i < 4; i++) {
> +        bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (i * 4),
> +                         bink2f_ac_quant[q], bink2f_luma_inter_qmat);

check error code?

> +        for (int j = 0; j < 4; j++) {
> +            block[j][0] = dc[i * 4 + j] * 0.125f;
> +            bink2f_idct_add(dst + (luma_repos[i*4+j]&3) * 8 +
> +                            (luma_repos[i*4+j]>>2) * 8 * stride, stride,
> +                            block[j]);
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int bink2f_decode_inter_chroma(Bink2Context *c,
> +                                      float block[4][64],
> +                                      unsigned *prev_cbp, int *prev_q,
> +                                      uint8_t *dst, int stride,
> +                                      int flags)
> +{
> +    GetBitContext *gb = &c->gb;
> +    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
> +    unsigned cbp;
> +    int q, dq;
> +
> +    *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp);
> +    dq = bink2f_decode_delta_q(gb);
> +    q = *prev_q + dq;
> +    if (q < 0 || q >= 16)
> +        return AVERROR_INVALIDDATA;
> +    *prev_q = q;
> +
> +    bink2f_decode_dc(c, gb, dc, 0, q, -1023, 1023, 0xA8);
> +
> +    bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp,
> +                     bink2f_ac_quant[q], bink2f_chroma_qmat);

ditto.

> +
> +    for (int i = 0; i < 4; i++) {
> +        block[i][0] = dc[i] * 0.125f;
> +        bink2f_idct_add(dst + (i & 1) * 8 + (i >> 1) * 8 * stride, stride,
> +                        block[i]);
> +    }
> +
> +    return 0;
> +}
> +

some of the bink2 f/g functions are identical except for the input/output type.
i guess not much can be done about that as macros will make it more ugly.

> +static float bink2f_average_block(uint8_t *src, int stride)
> +{
> +    int sum = 0;
> +
> +    for (int i = 0; i < 8; i++) {
> +        int avg_a = (src[i+0*stride] + src[i+1*stride] + 1) >> 1;
> +        int avg_b = (src[i+2*stride] + src[i+3*stride] + 1) >> 1;
> +        int avg_c = (src[i+4*stride] + src[i+5*stride] + 1) >> 1;
> +        int avg_d = (src[i+6*stride] + src[i+7*stride] + 1) >> 1;
> +        int avg_e = (avg_a + avg_b + 1) >> 1;
> +        int avg_f = (avg_c + avg_d + 1) >> 1;
> +        int avg_g = (avg_e + avg_f + 1) >> 1;
> +        sum += avg_g;
> +    }
> +
> +    return sum;
> +}
> +
> +static void bink2f_average_chroma(Bink2Context *c, int x, int y,
> +                                  uint8_t *src, int stride,
> +                                  float *dc)
> +{
> +    for (int i = 0; i < 4; i++) {
> +        int X = i & 1;
> +        int Y = i >> 1;

caps here makes actually it less readble.

> +        dc[i] = bink2f_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride);
> +    }
> +}

> +static int bink2g_get_type(GetBitContext *gb, int *lru)
> +{
> +    int val;
> +
> +    ff_dlog(NULL, " type show %X @ %d\n", show_bits(gb, 4), get_bits_count(gb));
> +    switch (get_unary(gb, 1, 3)) {
> +    case 0:
> +        val = lru[0];
> +        break;
> +    case 1:
> +        val = lru[1];
> +        FFSWAP(int, lru[0], lru[1]);
> +        break;
> +    case 2:
> +        val = lru[3];
> +        FFSWAP(int, lru[2], lru[3]);
> +        break;
> +    case 3:
> +        val = lru[2];
> +        FFSWAP(int, lru[1], lru[2]);
> +        break;
> +    }

cases 1-3 could be collapsed.

> +
> +    return val;
> +}
> +
> +static int bink2g_decode_dq(GetBitContext *gb)
> +{
> +    int dq = get_unary(gb, 1, 4);
> +
> +    if (dq == 3)
> +        dq += get_bits1(gb);
> +    else if (dq == 4)
> +        dq += get_bits(gb, 5) + 1;
> +    if (dq && get_bits1(gb))
> +        dq = -dq;
> +
> +    return dq;
> +}
> +
> +typedef uint8_t byte;
> +typedef int8_t sbyte;
> +typedef unsigned uint;

but why?

> +static void bink2g_get_cbp_flags(GetBitContext *gb, int offset, int size, uint8_t *dst)
> +{
> +    unsigned flag;
> +    int i, j;
> +    byte bVar4;
> +    sbyte sVar5;
> +    byte bVar6;
> +    int iVar7;
> +    int uVar8;
> +    int uVar9;
> +    int local_20;
> +    int local_1c;

those variable names are not meaningful enough. in fact they look computer generated.

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Michael Niedermayer April 7, 2019, 12:07 a.m. UTC | #4
On Sun, Apr 07, 2019 at 09:15:32AM +1000, Peter Ross wrote:
> On Wed, Mar 27, 2019 at 09:21:47PM +0100, Paul B Mahol wrote:
> > Signed-off-by: Paul B Mahol <onemda@gmail.com>
> > ---
> > Missing deblocking.
> > ---
> >  configure               |    1 +
> >  libavcodec/Makefile     |    1 +
> >  libavcodec/allcodecs.c  |    1 +
> >  libavcodec/avcodec.h    |    1 +
> >  libavcodec/bink2.c      |  787 +++++++++++++++++++++++
> >  libavcodec/bink2f.c     | 1139 +++++++++++++++++++++++++++++++++
> >  libavcodec/bink2g.c     | 1342 +++++++++++++++++++++++++++++++++++++++
> >  libavcodec/codec_desc.c |    7 +
> >  libavformat/bink.c      |    3 +-
> 
> my comments below.
> 
> this is a mammoth amount of work deserving of a better quality review.
> 
> > +++ b/libavcodec/bink2.c
> > @@ -0,0 +1,787 @@
> > +/*
> > + * Bink video 2 decoder
> > + * Copyright (c) 2014 Konstantin Shishkov
> > + * Copyright (c) 2019 Paul B Mahol
> > + *
> 
> > +static const uint8_t luma_repos[] = {
> > +    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
> > +};
> 
> identical to msvideo1enc.c remap
> consider moving to libavcodec/mathops.h
> 

> > +static const int32_t bink2g_dc_pat[] = {
> > +    1024, 1218, 1448, 1722, 2048,
> > +    2435, 2896, 3444, 4096, 4871,
> > +    5793, 6889, 8192, 9742, 11585, 13777, 16384,
> > +    19484, 23170,  27555, 32768, 38968, 46341,
> > +    55109, 65536, 77936, 92682, 110218, 131072,
> > +    155872, 185364, 220436, 262144, 311744,
> > +    370728, 440872, 524288,
> > +};
> 
> this is so close to ff_dirac_qscale_tab it is not funny.

This table can be generated this way:
    for (int i=0; i<37; i++) 
        printf("%d,\n", (int)lrint(1024 * pow(sqrt(sqrt(2)), i)));

        
[...]
James Almer April 7, 2019, 1:43 a.m. UTC | #5
On 3/27/2019 5:21 PM, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
> Missing deblocking.
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  787 +++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1139 +++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1342 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3280 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c
> 
> diff --git a/configure b/configure
> index 331393f8d5..2fdb7e589c 100755
> --- a/configure
> +++ b/configure
> @@ -2643,6 +2643,7 @@ atrac3p_decoder_select="mdct sinewin"
>  atrac9_decoder_select="mdct"
>  avrn_decoder_select="exif jpegtables"
>  bink_decoder_select="blockdsp hpeldsp"
> +bink2_decoder_select="blockdsp"
>  binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
>  binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
>  cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 15c43a8a6a..d02240febc 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -228,6 +228,7 @@ OBJS-$(CONFIG_AYUV_ENCODER)            += v408enc.o
>  OBJS-$(CONFIG_BETHSOFTVID_DECODER)     += bethsoftvideo.o
>  OBJS-$(CONFIG_BFI_DECODER)             += bfi.o
>  OBJS-$(CONFIG_BINK_DECODER)            += bink.o binkdsp.o
> +OBJS-$(CONFIG_BINK2_DECODER)           += bink2.o
>  OBJS-$(CONFIG_BINKAUDIO_DCT_DECODER)   += binkaudio.o
>  OBJS-$(CONFIG_BINKAUDIO_RDFT_DECODER)  += binkaudio.o
>  OBJS-$(CONFIG_BINTEXT_DECODER)         += bintext.o cga_data.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index b26aeca239..3a9ddb7b37 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -59,6 +59,7 @@ extern AVCodec ff_ayuv_decoder;
>  extern AVCodec ff_bethsoftvid_decoder;
>  extern AVCodec ff_bfi_decoder;
>  extern AVCodec ff_bink_decoder;
> +extern AVCodec ff_bink2_decoder;
>  extern AVCodec ff_bitpacked_decoder;
>  extern AVCodec ff_bmp_encoder;
>  extern AVCodec ff_bmp_decoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 0ce22ec4fa..6b881ac351 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -454,6 +454,7 @@ enum AVCodecID {
>      AV_CODEC_ID_RASC,
>      AV_CODEC_ID_HYMT,
>      AV_CODEC_ID_ARBC,
> +    AV_CODEC_ID_BINKVIDEO2,
>  
>      /* various PCM "codecs" */
>      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
> diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
> new file mode 100644
> index 0000000000..5513710bae
> --- /dev/null
> +++ b/libavcodec/bink2.c
> @@ -0,0 +1,787 @@
> +/*
> + * Bink video 2 decoder
> + * Copyright (c) 2014 Konstantin Shishkov
> + * Copyright (c) 2019 Paul B Mahol
> + *
> + * 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
> + */
> +
> +#define CACHED_BITSTREAM_READER 1
> +#define DEBUG 1
> +#define ASSERT_LEVEL 3
> +#include "libavutil/avassert.h"
> +#include "libavutil/attributes.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/internal.h"
> +#include "avcodec.h"
> +#include "blockdsp.h"
> +#include "copy_block.h"
> +#include "idctdsp.h"

Unused?

> +#include "internal.h"
> +#include "mathops.h"
> +
> +#define BITSTREAM_READER_LE
> +#include "get_bits.h"
> +#include "unary.h"
> +
> +#define BINK_FLAG_ALPHA 0x00100000
> +#define DC_MPRED(A, B, C) FFMIN(FFMAX((C) + (B) - (A), FFMIN3(A, B, C)), FFMAX3(A, B, C))
> +#define DC_MPRED2(A, B) FFMIN(FFMAX((A), (B)), FFMAX(FFMIN((A), (B)), 2 * (A) - (B)))
> +
> +static VLC bink2f_quant_vlc;
> +static VLC bink2f_ac_val0_vlc;
> +static VLC bink2f_ac_val1_vlc;
> +static VLC bink2f_ac_skip0_vlc;
> +static VLC bink2f_ac_skip1_vlc;
> +static VLC bink2g_ac_skip0_vlc;
> +static VLC bink2g_ac_skip1_vlc;
> +static VLC bink2g_mv_vlc;
> +
> +static const uint8_t kb2h_num_slices[] = {
> +    2, 3, 4, 8,
> +};
> +
> +static const uint8_t luma_repos[] = {
> +    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
> +};
> +
> +static const uint16_t bink2g_luma_intra_qmat[4][64] = {
> +    {
> +     1024,   1432,   1506,   1181,
> +     1843,   2025,   5271,   8592,
> +     1313,   1669,   1630,   1672,
> +     2625,   3442,   8023,  12794,
> +     1076,   1755,   1808,   1950,
> +     3980,   4875,   8813,  11909,
> +     1350,   1868,   2127,   2016,
> +     4725,   4450,   7712,   9637,
> +     2458,   3103,   4303,   4303,
> +     6963,   6835,  11079,  13365,
> +     3375,   5704,   5052,   6049,
> +     9198,   7232,  10725,   9834,
> +     5486,   7521,   7797,   7091,
> +    11079,  10016,  13559,  12912,
> +     7279,   7649,   7020,   6097,
> +     9189,   9047,  12661,  13768,
> +    },
> +    {
> +     1218,   1703,   1791,   1405,
> +     2192,   2408,   6268,  10218,
> +     1561,   1985,   1938,   1988,
> +     3122,   4093,   9541,  15215,
> +     1279,   2087,   2150,   2319,
> +     4733,   5798,  10481,  14162,
> +     1606,   2222,   2530,   2398,
> +     5619,   5292,   9171,  11460,
> +     2923,   3690,   5117,   5118,
> +     8281,   8128,  13176,  15894,
> +     4014,   6783,   6008,   7194,
> +    10938,   8600,  12755,  11694,
> +     6524,   8944,   9272,   8433,
> +    13176,  11911,  16125,  15354,
> +     8657,   9096,   8348,   7250,
> +    10927,  10759,  15056,  16373,
> +    },
> +    {
> +     1448,   2025,   2130,   1671,
> +     2607,   2864,   7454,  12151,
> +     1856,   2360,   2305,   2364,
> +     3713,   4867,  11346,  18094,
> +     1521,   2482,   2557,   2758,
> +     5628,   6894,  12464,  16841,
> +     1909,   2642,   3008,   2852,
> +     6683,   6293,  10906,  13629,
> +     3476,   4388,   6085,   6086,
> +     9847,   9666,  15668,  18901,
> +     4773,   8066,   7145,   8555,
> +    13007,  10227,  15168,  13907,
> +     7758,  10637,  11026,  10028,
> +    15668,  14165,  19175,  18259,
> +    10294,  10817,   9927,   8622,
> +    12995,  12794,  17905,  19470,
> +    },
> +    {
> +     1722,   2408,   2533,   1987,
> +     3100,   3406,   8864,  14450,
> +     2208,   2807,   2741,   2811,
> +     4415,   5788,  13493,  21517,
> +     1809,   2951,   3041,   3280,
> +     6693,   8199,  14822,  20028,
> +     2271,   3142,   3578,   3391,
> +     7947,   7484,  12969,  16207,
> +     4133,   5218,   7236,   7238,
> +    11711,  11495,  18633,  22478,
> +     5677,   9592,   8497,  10174,
> +    15469,  12162,  18038,  16538,
> +     9226,  12649,  13112,  11926,
> +    18633,  16845,  22804,  21715,
> +    12242,  12864,  11806,  10254,
> +    15454,  15215,  21293,  23155,
> +    },
> +};
> +
> +static const uint16_t bink2g_chroma_intra_qmat[4][64] = {
> +    {
> +     1024,   1193,   1434,   2203,
> +     5632,   4641,   5916,   6563,
> +     1193,   1622,   1811,   3606,
> +     6563,   5408,   6894,   7649,
> +     1434,   1811,   3515,   4875,
> +     5916,   4875,   6215,   6894,
> +     2203,   3606,   4875,   3824,
> +     4641,   3824,   4875,   5408,
> +     5632,   6563,   5916,   4641,
> +     5632,   4641,   5916,   6563,
> +     4641,   5408,   4875,   3824,
> +     4641,   3824,   4875,   5408,
> +     5916,   6894,   6215,   4875,
> +     5916,   4875,   6215,   6894,
> +     6563,   7649,   6894,   5408,
> +     6563,   5408,   6894,   7649,
> +    },
> +    {
> +     1218,   1419,   1706,   2620,
> +     6698,   5519,   7035,   7805,
> +     1419,   1929,   2153,   4288,
> +     7805,   6432,   8199,   9096,
> +     1706,   2153,   4180,   5798,
> +     7035,   5798,   7390,   8199,
> +     2620,   4288,   5798,   4548,
> +     5519,   4548,   5798,   6432,
> +     6698,   7805,   7035,   5519,
> +     6698,   5519,   7035,   7805,
> +     5519,   6432,   5798,   4548,
> +     5519,   4548,   5798,   6432,
> +     7035,   8199,   7390,   5798,
> +     7035,   5798,   7390,   8199,
> +     7805,   9096,   8199,   6432,
> +     7805,   6432,   8199,   9096,
> +    },
> +    {
> +     1448,   1688,   2028,   3116,
> +     7965,   6563,   8367,   9282,
> +     1688,   2294,   2561,   5099,
> +     9282,   7649,   9750,  10817,
> +     2028,   2561,   4971,   6894,
> +     8367,   6894,   8789,   9750,
> +     3116,   5099,   6894,   5408,
> +     6563,   5408,   6894,   7649,
> +     7965,   9282,   8367,   6563,
> +     7965,   6563,   8367,   9282,
> +     6563,   7649,   6894,   5408,
> +     6563,   5408,   6894,   7649,
> +     8367,   9750,   8789,   6894,
> +     8367,   6894,   8789,   9750,
> +     9282,  10817,   9750,   7649,
> +     9282,   7649,   9750,  10817,
> +    },
> +    {
> +     1722,   2007,   2412,   3706,
> +     9472,   7805,   9950,  11038,
> +     2007,   2729,   3045,   6064,
> +    11038,   9096,  11595,  12864,
> +     2412,   3045,   5912,   8199,
> +     9950,   8199,  10452,  11595,
> +     3706,   6064,   8199,   6432,
> +     7805,   6432,   8199,   9096,
> +     9472,  11038,   9950,   7805,
> +     9472,   7805,   9950,  11038,
> +     7805,   9096,   8199,   6432,
> +     7805,   6432,   8199,   9096,
> +     9950,  11595,  10452,   8199,
> +     9950,   8199,  10452,  11595,
> +    11038,  12864,  11595,   9096,
> +    11038,   9096,  11595,  12864,
> +    },
> +};
> +
> +
> +static const uint16_t bink2g_inter_qmat[4][64] = {
> +    {
> +     1024,   1193,   1076,    844,
> +     1052,    914,   1225,   1492,
> +     1193,   1391,   1254,    983,
> +     1227,   1065,   1463,   1816,
> +     1076,   1254,   1161,    936,
> +     1195,   1034,   1444,   1741,
> +      844,    983,    936,    811,
> +     1055,    927,   1305,   1584,
> +     1052,   1227,   1195,   1055,
> +     1451,   1336,   1912,   2354,
> +      914,   1065,   1034,    927,
> +     1336,   1313,   1945,   2486,
> +     1225,   1463,   1444,   1305,
> +     1912,   1945,   3044,   4039,
> +     1492,   1816,   1741,   1584,
> +     2354,   2486,   4039,   5679,
> +    },
> +    {
> +     1218,   1419,   1279,   1003,
> +     1252,   1087,   1457,   1774,
> +     1419,   1654,   1491,   1169,
> +     1459,   1267,   1739,   2159,
> +     1279,   1491,   1381,   1113,
> +     1421,   1230,   1717,   2070,
> +     1003,   1169,   1113,    965,
> +     1254,   1103,   1552,   1884,
> +     1252,   1459,   1421,   1254,
> +     1725,   1589,   2274,   2799,
> +     1087,   1267,   1230,   1103,
> +     1589,   1562,   2313,   2956,
> +     1457,   1739,   1717,   1552,
> +     2274,   2313,   3620,   4803,
> +     1774,   2159,   2070,   1884,
> +     2799,   2956,   4803,   6753,
> +    },
> +    {
> +     1448,   1688,   1521,   1193,
> +     1488,   1293,   1732,   2110,
> +     1688,   1967,   1773,   1391,
> +     1735,   1507,   2068,   2568,
> +     1521,   1773,   1642,   1323,
> +     1690,   1462,   2042,   2462,
> +     1193,   1391,   1323,   1147,
> +     1492,   1311,   1845,   2241,
> +     1488,   1735,   1690,   1492,
> +     2052,   1889,   2704,   3328,
> +     1293,   1507,   1462,   1311,
> +     1889,   1857,   2751,   3515,
> +     1732,   2068,   2042,   1845,
> +     2704,   2751,   4306,   5712,
> +     2110,   2568,   2462,   2241,
> +     3328,   3515,   5712,   8031,
> +    },
> +    {
> +     1722,   2007,   1809,   1419,
> +     1770,   1537,   2060,   2509,
> +     2007,   2339,   2108,   1654,
> +     2063,   1792,   2460,   3054,
> +     1809,   2108,   1953,   1574,
> +     2010,   1739,   2428,   2928,
> +     1419,   1654,   1574,   1364,
> +     1774,   1559,   2195,   2664,
> +     1770,   2063,   2010,   1774,
> +     2440,   2247,   3216,   3958,
> +     1537,   1792,   1739,   1559,
> +     2247,   2209,   3271,   4181,
> +     2060,   2460,   2428,   2195,
> +     3216,   3271,   5120,   6793,
> +     2509,   3054,   2928,   2664,
> +     3958,   4181,   6793,   9550,
> +    },
> +};
> +
> +static uint8_t bink2g_chroma_cbp_pat[16] = {
> +    0x00, 0x00, 0x00, 0x0F,
> +    0x00, 0x0F, 0x0F, 0x0F,
> +    0x00, 0x0F, 0x0F, 0x0F,
> +    0x0F, 0x0F, 0x0F, 0x0F,
> +};
> +
> +static const int32_t bink2g_dc_pat[] = {
> +    1024, 1218, 1448, 1722, 2048,
> +    2435, 2896, 3444, 4096, 4871,
> +    5793, 6889, 8192, 9742, 11585, 13777, 16384,
> +    19484, 23170,  27555, 32768, 38968, 46341,
> +    55109, 65536, 77936, 92682, 110218, 131072,
> +    155872, 185364, 220436, 262144, 311744,
> +    370728, 440872, 524288,
> +};
> +
> +static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };
> +
> +static const uint8_t bink2f_quant_codes[16] = {
> +    0x01, 0x02, 0x04, 0x08, 0x10, 0x30, 0x50, 0x70,
> +    0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0,
> +};
> +
> +static const uint8_t bink2f_quant_bits[16] = {
> +    1, 2, 3, 4, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
> +};
> +
> +static const uint16_t bink2f_ac_val_codes[2][13] = {
> +    {
> +        0x04, 0x01, 0x02, 0x00, 0x08, 0x18, 0xF8, 0x178, 0x138,
> +        0x38, 0x1B8, 0x78, 0xB8
> +    },
> +    {
> +        0x0A, 0x01, 0x04, 0x08, 0x06, 0x00, 0x02, 0x1A, 0x2A,
> +        0x16A, 0x1EA, 0x6A, 0xEA
> +    },
> +};
> +
> +static const uint8_t bink2f_ac_val_bits[2][13] = {
> +    { 3, 1, 2, 4, 5, 6, 8, 9, 9, 9, 9, 9, 9 },
> +    { 6, 1, 3, 4, 3, 4, 4, 5, 7, 9, 9, 9, 9 },
> +};
> +
> +#define NUM_AC_SKIPS 14
> +static const uint16_t bink2f_ac_skip_codes[2][NUM_AC_SKIPS] = {
> +    {
> +        0x00, 0x01, 0x0D, 0x15, 0x45, 0x85, 0xA5, 0x165,
> +        0x65, 0x1E5, 0xE5, 0x25, 0x03, 0x05
> +    },
> +    {
> +        0x00, 0x01, 0x03, 0x07, 0x1F, 0x1B, 0x0F, 0x2F,
> +        0x5B, 0xDB, 0x1DB, 0x3B, 0x05, 0x0B
> +    }
> +};
> +
> +static const uint8_t bink2f_ac_skip_bits[2][NUM_AC_SKIPS] = {
> +    { 1, 3, 4, 5, 7, 8, 8, 9, 9, 9, 9, 8, 2, 8 },
> +    { 1, 3, 4, 4, 5, 7, 6, 6, 8, 9, 9, 6, 3, 5 }
> +};
> +
> +static const uint8_t bink2f_skips[] = {
> +    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 62, 0, 0, 0,
> +};
> +
> +static const uint8_t bink2g_skips[] = {
> +    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0,
> +};
> +
> +static const uint8_t bink2f_next_skips[] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
> +};
> +
> +static const uint8_t bink2_next_skips[] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
> +};
> +
> +static const uint16_t bink2g_ac_skip_codes[2][NUM_AC_SKIPS] = {
> +    {
> +        0x01, 0x00, 0x004, 0x02C, 0x06C, 0x0C, 0x4C,
> +        0xAC, 0xEC, 0x12C, 0x16C, 0x1AC, 0x02, 0x1C,
> +    },
> +    {
> +        0x01, 0x04, 0x00, 0x08, 0x02, 0x32, 0x0A,
> +        0x12, 0x3A, 0x7A, 0xFA, 0x72, 0x06, 0x1A,
> +    },
> +};
> +
> +static const uint8_t bink2g_ac_skip_bits[2][NUM_AC_SKIPS] = {
> +    { 1, 3, 4, 9, 9, 7, 7, 9, 8, 9, 9, 9, 2, 5 },
> +    { 1, 3, 4, 4, 5, 7, 5, 6, 7, 8, 8, 7, 3, 6 },
> +};
> +
> +static const uint8_t bink2g_mv_codes[] = {
> +    0x01, 0x06, 0x0C, 0x1C, 0x18, 0x38, 0x58, 0x78,
> +    0x68, 0x48, 0x28, 0x08, 0x14, 0x04, 0x02, 0x00,
> +};
> +
> +static const uint8_t bink2g_mv_bits[] = {
> +    1, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 3, 4,
> +};
> +
> +static const float bink2f_dc_quant[16] = {
> +    4, 4, 4, 4, 4, 6, 7, 8, 10, 12, 16, 24, 32, 48, 64, 128
> +};
> +
> +static const float bink2f_ac_quant[16] = {
> +    1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 6.0, 7.0, 8.0, 12.0, 16.0, 24.0, 32.0, 48.0, 64.0, 128.0
> +};
> +
> +static const float bink2f_luma_intra_qmat[64] = {
> +    0.125,    0.190718, 0.16332,  0.235175, 0.3,      0.392847, 0.345013, 0.210373,
> +    0.208056, 0.288582, 0.317145, 0.387359, 0.450788, 0.790098, 0.562995, 0.263095,
> +    0.228649, 0.294491, 0.341421, 0.460907, 0.653281, 0.731424, 0.60988,  0.252336,
> +    0.205778, 0.346585, 0.422498, 0.501223, 0.749621, 1.004719, 0.636379, 0.251428,
> +    0.225,    0.381436, 0.604285, 0.823113, 0.85,     1.070509, 0.69679,  0.265553,
> +    0.235708, 0.476783, 0.70576,  0.739104, 0.795516, 0.802512, 0.600616, 0.249289,
> +    0.331483, 0.600528, 0.689429, 0.692062, 0.69679,  0.643138, 0.43934,  0.188511,
> +    0.248309, 0.440086, 0.42807,  0.397419, 0.386259, 0.270966, 0.192244, 0.094199,
> +};
> +
> +static const float bink2f_luma_inter_qmat[64] = {
> +    0.125,    0.17338,  0.16332,  0.146984, 0.128475, 0.106393, 0.077046, 0.043109,
> +    0.17338,  0.240485, 0.226532, 0.203873, 0.1782,   0.147571, 0.109474, 0.062454,
> +    0.16332,  0.226532, 0.219321, 0.202722, 0.181465, 0.149711, 0.112943, 0.062584,
> +    0.146984, 0.203873, 0.202722, 0.201647, 0.183731, 0.153976, 0.11711,  0.065335,
> +    0.128475, 0.1782,   0.181465, 0.183731, 0.177088, 0.155499, 0.120267, 0.068016,
> +    0.106393, 0.147571, 0.149711, 0.153976, 0.155499, 0.145756, 0.116636, 0.068495,
> +    0.077046, 0.109474, 0.112943, 0.11711,  0.120267, 0.116636, 0.098646, 0.060141,
> +    0.043109, 0.062454, 0.062584, 0.065335, 0.068016, 0.068495, 0.060141, 0.038853,
> +};
> +
> +static const float bink2f_chroma_qmat[64] = {
> +    0.125,      0.17338,    0.217761,   0.383793,   0.6875,     0.54016501, 0.37207201, 0.18968099,
> +    0.17338,    0.28056601, 0.32721299, 0.74753499, 0.95358998, 0.74923098, 0.51607901, 0.26309499,
> +    0.217761,   0.32721299, 0.66387498, 1.056244,   0.89826202, 0.70576,    0.48613599, 0.24783,
> +    0.383793,   0.74753499, 1.056244,   0.95059502, 0.80841398, 0.635167,   0.437511,   0.223041,
> +    0.6875,     0.95358998, 0.89826202, 0.80841398, 0.6875,     0.54016501, 0.37207201, 0.18968099,
> +    0.54016501, 0.74923098, 0.70576,    0.635167,   0.54016501, 0.42440501, 0.292335,   0.149031,
> +    0.37207201, 0.51607901, 0.48613599, 0.437511,   0.37207201, 0.292335,   0.201364,   0.102655,
> +    0.18968099, 0.26309499, 0.24783,    0.223041,   0.18968099, 0.149031,   0.102655,   0.052333001
> +};
> +
> +static const uint8_t bink2f_luma_scan[64] = {
> +     0,  2,  1,  8,  9, 17, 10, 16,
> +    24,  3, 18, 25, 32, 11, 33, 26,
> +     4, 40, 19, 12, 27, 41, 34,  5,
> +    20, 48,  6, 28, 15, 42, 23, 35,
> +    21, 13, 14,  7, 31, 43, 49, 36,
> +    22, 56, 39, 50, 30, 44, 29, 51,
> +    57, 47, 58, 59, 63, 61, 55, 38,
> +    52, 62, 45, 37, 60, 46, 54, 53
> +};
> +
> +static const uint8_t bink2f_chroma_scan[64] = {
> +     0,  1,  8,  2,  9, 16, 10, 17,
> +     3, 24, 11, 18, 25, 13, 14,  4,
> +    15,  5,  6,  7, 12, 19, 20, 21,
> +    22, 23, 26, 27, 28, 29, 30, 31,
> +    32, 33, 34, 35, 36, 37, 38, 39,
> +    40, 41, 42, 43, 44, 45, 46, 47,
> +    48, 49, 50, 51, 52, 53, 54, 55,
> +    56, 57, 58, 59, 60, 61, 62, 63
> +};
> +
> +static const uint8_t bink2g_scan[64] = {
> +     0,   8,   1,   2,  9,  16,  24,  17,
> +    10,   3,   4,  11, 18,  25,  32,  40,
> +    33,  26,  19,  12,  5,   6,  13,  20,
> +    27,  34,  41,  48, 56,  49,  42,  35,
> +    28,  21,  14,   7, 15,  22,  29,  36,
> +    43,  50,  57,  58, 51,  44,  37,  30,
> +    23,  31,  38,  45, 52,  59,  60,  53,
> +    46,  39,  47,  54, 61,  62,  55,  63,
> +};

All these tables could be in a separate file.

> +
> +typedef struct QuantPredict {
> +    int8_t intra_q;
> +    int8_t inter_q;
> +} QuantPredict;
> +
> +typedef struct DCPredict {
> +    float dc[4][16];
> +    int   block_type;
> +} DCPredict;
> +
> +typedef struct DCIPredict {
> +    int dc[4][16];
> +    int block_type;
> +} DCIPredict;
> +
> +typedef struct MVectors {
> +    int v[4][2];
> +    int nb_vectors;
> +} MVectors;
> +
> +typedef struct MVPredict {
> +    MVectors mv;
> +} MVPredict;
> +
> +/*
> + * Decoder context
> + */
> +typedef struct Bink2Context {
> +    AVCodecContext  *avctx;
> +    GetBitContext   gb;
> +    BlockDSPContext dsp;
> +    AVFrame         *last;
> +    int             version;              ///< internal Bink file version
> +    int             has_alpha;
> +
> +    DECLARE_ALIGNED(16, float, block[4][64]);
> +    DECLARE_ALIGNED(16, int16_t, iblock[4][64]);
> +
> +    QuantPredict    *current_q;
> +    QuantPredict    *prev_q;
> +
> +    DCPredict       *current_dc;
> +    DCPredict       *prev_dc;
> +
> +    DCIPredict      *current_idc;
> +    DCIPredict      *prev_idc;
> +
> +    MVPredict       *current_mv;
> +    MVPredict       *prev_mv;
> +
> +    uint8_t         *col_cbp;
> +    uint8_t         *row_cbp;
> +
> +    int             num_slices;
> +    int             slice_height[4];
> +
> +    int             comp;
> +    int             mb_pos;
> +    unsigned        flags;
> +    unsigned        frame_flags;
> +} Bink2Context;
> +
> +/**
> + * Bink2 video block types
> + */
> +enum BlockTypes {
> +    INTRA_BLOCK = 0, ///< intra DCT block
> +    SKIP_BLOCK,      ///< skipped block
> +    MOTION_BLOCK,    ///< block is copied from previous frame with some offset
> +    RESIDUE_BLOCK,   ///< motion block with some difference added
> +};
> +
> +static const uint8_t ones_count[16] = {
> +    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
> +};
> +
> +#include "bink2f.c"
> +#include "bink2g.c"
> +
> +static int bink2_decode_frame(AVCodecContext *avctx, void *data,
> +                              int *got_frame, AVPacket *pkt)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +    GetBitContext *gb = &c->gb;
> +    AVFrame *frame = data;
> +    uint8_t *dst[4];
> +    uint8_t *src[4];
> +    int stride[4];
> +    int sstride[4];
> +    uint32_t off = 0;
> +    int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY);
> +    int ret, w, h;
> +    int height_a;
> +
> +    w = avctx->width;
> +    h = avctx->height;
> +    ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32));
> +    if (ret < 0)
> +        return ret;
> +    avctx->width  = w;
> +    avctx->height = h;

Why doing this on every frame? The result will always be the same.

> +
> +    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
> +        return ret;
> +
> +    for (int i = 0; i < 4; i++) {
> +        src[i]     = c->last->data[i];
> +        dst[i]     = frame->data[i];
> +        stride[i]  = frame->linesize[i];
> +        sstride[i] = c->last->linesize[i];
> +    }
> +
> +    c->frame_flags = AV_RL32(pkt->data);
> +    ff_dlog(NULL, "frame flags %X\n", c->frame_flags);
> +
> +    if ((ret = init_get_bits8(gb, pkt->data, pkt->size)) < 0)
> +        return ret;
> +
> +    height_a = (avctx->height + 31) & 0xFFFFFFE0;
> +    if (c->version <= 'f') {
> +        c->num_slices = 2;
> +        c->slice_height[0] = (avctx->height / 2 + 16) & 0xFFFFFFE0;
> +    } else if (c->version == 'g') {
> +        if (height_a < 128) {
> +            c->num_slices = 1;
> +        } else {
> +            c->num_slices = 2;
> +            c->slice_height[0] = (avctx->height / 2 + 16) & 0xFFFFFFE0;
> +        }
> +    } else {
> +        int start, end;
> +
> +        c->num_slices = kb2h_num_slices[c->flags & 3];
> +        start = 0;
> +        end = height_a + 32 * c->num_slices - 1;
> +        for (int i = 0; i < c->num_slices - 1; i++) {
> +            start += ((end - start) / (c->num_slices - i)) & 0xFFFFFFE0;
> +            end -= 32;
> +            c->slice_height[i] = start;
> +        }
> +    }
> +    c->slice_height[c->num_slices - 1] = height_a;
> +
> +    skip_bits_long(gb, 32 + 32 * (c->num_slices - 1));
> +
> +    if (c->frame_flags & 0x10000) {
> +        if (!(c->frame_flags & 0x8000))
> +            bink2g_get_cbp_flags(gb, 1, (((avctx->height + 15) & ~15) >> 3) - 1, c->row_cbp);
> +        if (!(c->frame_flags & 0x4000))
> +            bink2g_get_cbp_flags(gb, 1, (((avctx->width + 15) & ~15) >> 3) - 1, c->col_cbp);
> +    }
> +
> +    for (int i = 0; i < c->num_slices; i++) {
> +        if (i == c->num_slices - 1)
> +            off = pkt->size;
> +        else
> +            off = AV_RL32(pkt->data + 4 + i * 4);
> +
> +        if (c->version <= 'f')
> +            ret = bink2f_decode_slice(c, dst, stride, src, sstride, is_kf, i ? c->slice_height[i-1] : 0, c->slice_height[i]);
> +        else
> +            ret = bink2g_decode_slice(c, dst, stride, src, sstride, is_kf, i ? c->slice_height[i-1] : 0, c->slice_height[i]);
> +        if (0 && ret < 0)
> +            return ret;
> +
> +        align_get_bits(gb);
> +        if (get_bits_left(gb) < 0)
> +            av_log(avctx, AV_LOG_WARNING, "slice %d: overread\n", i);
> +        if (8 * (off - (get_bits_count(gb) >> 3)) > 24)
> +            av_log(avctx, AV_LOG_WARNING, "slice %d: underread %d\n", i, 8 * (off - (get_bits_count(gb) >> 3)));
> +        skip_bits_long(gb, 8 * (off - (get_bits_count(gb) >> 3)));
> +
> +        dst[0] = frame->data[0] + c->slice_height[i]   * stride[0];
> +        dst[1] = frame->data[1] + c->slice_height[i]/2 * stride[1];
> +        dst[2] = frame->data[2] + c->slice_height[i]/2 * stride[2];
> +        dst[3] = frame->data[3] + c->slice_height[i]   * stride[3];
> +    }
> +
> +    frame->key_frame = is_kf;
> +    frame->pict_type = is_kf ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
> +
> +    av_frame_unref(c->last);
> +    if ((ret = av_frame_ref(c->last, frame)) < 0)
> +        return ret;
> +
> +    *got_frame = 1;
> +
> +    /* always report that the buffer was completely consumed */
> +    return pkt->size;
> +}
> +
> +#define INIT_VLC_STATIC_LE(vlc, nb_bits, nb_codes,                 \
> +                           bits, bits_wrap, bits_size,             \
> +                           codes, codes_wrap, codes_size,          \
> +                           symbols, symbols_wrap, symbols_size,    \
> +                           static_size)                            \
> +    do {                                                           \
> +        static VLC_TYPE table[static_size][2];                     \
> +        (vlc)->table           = table;                            \
> +        (vlc)->table_allocated = static_size;                      \
> +        ff_init_vlc_sparse(vlc, nb_bits, nb_codes,                 \
> +                           bits, bits_wrap, bits_size,             \
> +                           codes, codes_wrap, codes_size,          \
> +                           symbols, symbols_wrap, symbols_size,    \
> +                           INIT_VLC_LE | INIT_VLC_USE_NEW_STATIC); \
> +    } while (0)
> +
> +static av_cold int bink2_decode_init(AVCodecContext *avctx)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +    int ret;
> +
> +    c->version = avctx->codec_tag >> 24;
> +    if (avctx->extradata_size < 4) {
> +        av_log(avctx, AV_LOG_ERROR, "Extradata missing or too short\n");
> +        return AVERROR_INVALIDDATA;
> +    }
> +    c->flags = AV_RL32(avctx->extradata);
> +    av_log(avctx, AV_LOG_DEBUG, "flags: 0x%X\n", c->flags);
> +    c->has_alpha = c->flags & BINK_FLAG_ALPHA;
> +    c->avctx = avctx;
> +
> +    c->last = av_frame_alloc();
> +    if (!c->last)
> +        return AVERROR(ENOMEM);
> +
> +    if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
> +        return ret;
> +
> +    avctx->pix_fmt = c->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
> +
> +    ff_blockdsp_init(&c->dsp, avctx);
> +
> +    INIT_VLC_STATIC_LE(&bink2f_quant_vlc, 9, FF_ARRAY_ELEMS(bink2f_quant_codes),
> +                       bink2f_quant_bits, 1, 1, bink2f_quant_codes, 1, 1, NULL, 0, 0, 512);
> +    INIT_VLC_STATIC_LE(&bink2f_ac_val0_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_val_bits[0]),
> +                       bink2f_ac_val_bits[0], 1, 1, bink2f_ac_val_codes[0], 2, 2, NULL, 0, 0, 512);
> +    INIT_VLC_STATIC_LE(&bink2f_ac_val1_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_val_bits[1]),
> +                       bink2f_ac_val_bits[1], 1, 1, bink2f_ac_val_codes[1], 2, 2, NULL, 0, 0, 512);
> +    INIT_VLC_STATIC_LE(&bink2f_ac_skip0_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_skip_bits[0]),
> +                       bink2f_ac_skip_bits[0], 1, 1, bink2f_ac_skip_codes[0], 2, 2, NULL, 0, 0, 512);
> +    INIT_VLC_STATIC_LE(&bink2f_ac_skip1_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_skip_bits[1]),
> +                       bink2f_ac_skip_bits[1], 1, 1, bink2f_ac_skip_codes[1], 2, 2, NULL, 0, 0, 512);
> +
> +    INIT_VLC_STATIC_LE(&bink2g_ac_skip0_vlc, 9, FF_ARRAY_ELEMS(bink2g_ac_skip_bits[0]),
> +                       bink2g_ac_skip_bits[0], 1, 1, bink2g_ac_skip_codes[0], 2, 2, NULL, 0, 0, 512);
> +    INIT_VLC_STATIC_LE(&bink2g_ac_skip1_vlc, 9, FF_ARRAY_ELEMS(bink2g_ac_skip_bits[1]),
> +                       bink2g_ac_skip_bits[1], 1, 1, bink2g_ac_skip_codes[1], 2, 2, NULL, 0, 0, 512);
> +    INIT_VLC_STATIC_LE(&bink2g_mv_vlc, 9, FF_ARRAY_ELEMS(bink2g_mv_bits),
> +                       bink2g_mv_bits, 1, 1, bink2g_mv_codes, 1, 1, NULL, 0, 0, 512);
> +
> +    c->current_q = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_q));
> +    if (!c->current_q)
> +        return AVERROR(ENOMEM);
> +
> +    c->prev_q = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_q));
> +    if (!c->prev_q)
> +        return AVERROR(ENOMEM);
> +
> +    c->current_dc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_dc));
> +    if (!c->current_dc)
> +        return AVERROR(ENOMEM);
> +
> +    c->prev_dc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_dc));
> +    if (!c->prev_dc)
> +        return AVERROR(ENOMEM);
> +
> +    c->current_idc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_idc));
> +    if (!c->current_idc)
> +        return AVERROR(ENOMEM);
> +
> +    c->prev_idc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_idc));
> +    if (!c->prev_q)
> +        return AVERROR(ENOMEM);
> +
> +    c->current_mv = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_mv));
> +    if (!c->current_mv)
> +        return AVERROR(ENOMEM);
> +
> +    c->prev_mv = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_mv));
> +    if (!c->prev_mv)
> +        return AVERROR(ENOMEM);
> +
> +    c->col_cbp = av_calloc((((avctx->width + 31) >> 3) + 7) >> 3, sizeof(*c->col_cbp));
> +    if (!c->col_cbp)
> +        return AVERROR(ENOMEM);
> +
> +    c->row_cbp = av_calloc((((avctx->height + 31) >> 3) + 7) >> 3, sizeof(*c->row_cbp));
> +    if (!c->row_cbp)
> +        return AVERROR(ENOMEM);
> +
> +    return 0;
> +}
> +
> +static av_cold int bink2_decode_end(AVCodecContext *avctx)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +
> +    av_frame_free(&c->last);
> +    av_freep(&c->current_q);
> +    av_freep(&c->prev_q);
> +    av_freep(&c->current_dc);
> +    av_freep(&c->prev_dc);
> +    av_freep(&c->current_idc);
> +    av_freep(&c->prev_idc);
> +    av_freep(&c->current_mv);
> +    av_freep(&c->prev_mv);
> +    av_freep(&c->col_cbp);
> +    av_freep(&c->row_cbp);
> +
> +    return 0;
> +}
> +
> +AVCodec ff_bink2_decoder = {
> +    .name           = "binkvideo2",
> +    .long_name      = NULL_IF_CONFIG_SMALL("Bink video 2"),
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_BINKVIDEO2,
> +    .priv_data_size = sizeof(Bink2Context),
> +    .init           = bink2_decode_init,
> +    .close          = bink2_decode_end,
> +    .decode         = bink2_decode_frame,
> +    .capabilities   = AV_CODEC_CAP_DR1,

Missing FF_CODEC_CAP_INIT_CLEANUP, and a flush function to unref c->last
and do any other potentially required cleaning.
Paul B Mahol April 7, 2019, 8 a.m. UTC | #6
On 4/7/19, Peter Ross <pross@xvid.org> wrote:
> On Wed, Mar 27, 2019 at 09:21:47PM +0100, Paul B Mahol wrote:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>> Missing deblocking.
>> ---
>>  configure               |    1 +
>>  libavcodec/Makefile     |    1 +
>>  libavcodec/allcodecs.c  |    1 +
>>  libavcodec/avcodec.h    |    1 +
>>  libavcodec/bink2.c      |  787 +++++++++++++++++++++++
>>  libavcodec/bink2f.c     | 1139 +++++++++++++++++++++++++++++++++
>>  libavcodec/bink2g.c     | 1342 +++++++++++++++++++++++++++++++++++++++
>>  libavcodec/codec_desc.c |    7 +
>>  libavformat/bink.c      |    3 +-
>
> my comments below.
>
> this is a mammoth amount of work deserving of a better quality review.
>
>> +++ b/libavcodec/bink2.c
>> @@ -0,0 +1,787 @@
>> +/*
>> + * Bink video 2 decoder
>> + * Copyright (c) 2014 Konstantin Shishkov
>> + * Copyright (c) 2019 Paul B Mahol
>> + *
>
>> +static const uint8_t luma_repos[] = {
>> +    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
>> +};
>
> identical to msvideo1enc.c remap
> consider moving to libavcodec/mathops.h
>
>> +static const int32_t bink2g_dc_pat[] = {
>> +    1024, 1218, 1448, 1722, 2048,
>> +    2435, 2896, 3444, 4096, 4871,
>> +    5793, 6889, 8192, 9742, 11585, 13777, 16384,
>> +    19484, 23170,  27555, 32768, 38968, 46341,
>> +    55109, 65536, 77936, 92682, 110218, 131072,
>> +    155872, 185364, 220436, 262144, 311744,
>> +    370728, 440872, 524288,
>> +};
>
> this is so close to ff_dirac_qscale_tab it is not funny.
>
>> +     3, 24, 11, 18, 25, 13, 14,  4,
>> +    15,  5,  6,  7, 12, 19, 20, 21,
>> +    22, 23, 26, 27, 28, 29, 30, 31,
>> +    32, 33, 34, 35, 36, 37, 38, 39,
>> +    40, 41, 42, 43, 44, 45, 46, 47,
>> +    48, 49, 50, 51, 52, 53, 54, 55,
>> +    56, 57, 58, 59, 60, 61, 62, 63
>> +};
>> +
>> +static const uint8_t bink2g_scan[64] = {
>> +     0,   8,   1,   2,  9,  16,  24,  17,
>> +    10,   3,   4,  11, 18,  25,  32,  40,
>> +    33,  26,  19,  12,  5,   6,  13,  20,
>> +    27,  34,  41,  48, 56,  49,  42,  35,
>> +    28,  21,  14,   7, 15,  22,  29,  36,
>> +    43,  50,  57,  58, 51,  44,  37,  30,
>> +    23,  31,  38,  45, 52,  59,  60,  53,
>> +    46,  39,  47,  54, 61,  62,  55,  63,
>> +};
>
> this table has more white space than the other scan tables...
>
>> +enum BlockTypes {
>> +    INTRA_BLOCK = 0, ///< intra DCT block
>> +    SKIP_BLOCK,      ///< skipped block
>> +    MOTION_BLOCK,    ///< block is copied from previous frame with some
>> offset
>> +    RESIDUE_BLOCK,   ///< motion block with some difference added
>> +};
>> +
>> +static const uint8_t ones_count[16] = {
>> +    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
>> +};
>
> duplicate of libavcodec/vc1_mc.c popcount4
>
>> +static int bink2_decode_frame(AVCodecContext *avctx, void *data,
>> +                              int *got_frame, AVPacket *pkt)
>> +{
>> +    Bink2Context * const c = avctx->priv_data;
>> +    GetBitContext *gb = &c->gb;
>> +    AVFrame *frame = data;
>> +    uint8_t *dst[4];
>> +    uint8_t *src[4];
>> +    int stride[4];
>> +    int sstride[4];
>> +    uint32_t off = 0;
>> +    int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY);
>> +    int ret, w, h;
>> +    int height_a;
>> +
>> +    w = avctx->width;
>> +    h = avctx->height;
>> +    ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32));
>> +    if (ret < 0)
>> +        return ret;
>> +    avctx->width  = w;
>> +    avctx->height = h;
>> +
>> +    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
>> +        return ret;
>
> ret error handling style is inconsistent
>
>> +static int bink2f_decode_inter_luma(Bink2Context *c,
>> +                                    float block[4][64],
>> +                                    unsigned *prev_cbp, int *prev_q,
>> +                                    uint8_t *dst, int stride,
>> +                                    int flags)
>> +{
>> +    GetBitContext *gb = &c->gb;
>> +    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
>> +    unsigned cbp;
>> +    int q, dq;
>> +
>> +    *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp);
>> +    dq = bink2f_decode_delta_q(gb);
>> +    q = *prev_q + dq;
>> +    if (q < 0 || q >= 16)
>> +        return AVERROR_INVALIDDATA;
>> +    *prev_q = q;
>> +
>> +    bink2f_decode_dc(c, gb, dc, 1, q, -1023, 1023, 0xA8);
>> +
>> +    for (int i = 0; i < 4; i++) {
>> +        bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (i * 4),
>> +                         bink2f_ac_quant[q], bink2f_luma_inter_qmat);
>
> check error code?
>
>> +        for (int j = 0; j < 4; j++) {
>> +            block[j][0] = dc[i * 4 + j] * 0.125f;
>> +            bink2f_idct_add(dst + (luma_repos[i*4+j]&3) * 8 +
>> +                            (luma_repos[i*4+j]>>2) * 8 * stride, stride,
>> +                            block[j]);
>> +        }
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +static int bink2f_decode_inter_chroma(Bink2Context *c,
>> +                                      float block[4][64],
>> +                                      unsigned *prev_cbp, int *prev_q,
>> +                                      uint8_t *dst, int stride,
>> +                                      int flags)
>> +{
>> +    GetBitContext *gb = &c->gb;
>> +    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
>> +    unsigned cbp;
>> +    int q, dq;
>> +
>> +    *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp);
>> +    dq = bink2f_decode_delta_q(gb);
>> +    q = *prev_q + dq;
>> +    if (q < 0 || q >= 16)
>> +        return AVERROR_INVALIDDATA;
>> +    *prev_q = q;
>> +
>> +    bink2f_decode_dc(c, gb, dc, 0, q, -1023, 1023, 0xA8);
>> +
>> +    bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp,
>> +                     bink2f_ac_quant[q], bink2f_chroma_qmat);
>
> ditto.
>
>> +
>> +    for (int i = 0; i < 4; i++) {
>> +        block[i][0] = dc[i] * 0.125f;
>> +        bink2f_idct_add(dst + (i & 1) * 8 + (i >> 1) * 8 * stride,
>> stride,
>> +                        block[i]);
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>
> some of the bink2 f/g functions are identical except for the input/output
> type.
> i guess not much can be done about that as macros will make it more ugly.
>
>> +static float bink2f_average_block(uint8_t *src, int stride)
>> +{
>> +    int sum = 0;
>> +
>> +    for (int i = 0; i < 8; i++) {
>> +        int avg_a = (src[i+0*stride] + src[i+1*stride] + 1) >> 1;
>> +        int avg_b = (src[i+2*stride] + src[i+3*stride] + 1) >> 1;
>> +        int avg_c = (src[i+4*stride] + src[i+5*stride] + 1) >> 1;
>> +        int avg_d = (src[i+6*stride] + src[i+7*stride] + 1) >> 1;
>> +        int avg_e = (avg_a + avg_b + 1) >> 1;
>> +        int avg_f = (avg_c + avg_d + 1) >> 1;
>> +        int avg_g = (avg_e + avg_f + 1) >> 1;
>> +        sum += avg_g;
>> +    }
>> +
>> +    return sum;
>> +}
>> +
>> +static void bink2f_average_chroma(Bink2Context *c, int x, int y,
>> +                                  uint8_t *src, int stride,
>> +                                  float *dc)
>> +{
>> +    for (int i = 0; i < 4; i++) {
>> +        int X = i & 1;
>> +        int Y = i >> 1;
>
> caps here makes actually it less readble.
>
>> +        dc[i] = bink2f_average_block(src + x + X * 8 + (y + Y * 8) *
>> stride, stride);
>> +    }
>> +}
>
>> +static int bink2g_get_type(GetBitContext *gb, int *lru)
>> +{
>> +    int val;
>> +
>> +    ff_dlog(NULL, " type show %X @ %d\n", show_bits(gb, 4),
>> get_bits_count(gb));
>> +    switch (get_unary(gb, 1, 3)) {
>> +    case 0:
>> +        val = lru[0];
>> +        break;
>> +    case 1:
>> +        val = lru[1];
>> +        FFSWAP(int, lru[0], lru[1]);
>> +        break;
>> +    case 2:
>> +        val = lru[3];
>> +        FFSWAP(int, lru[2], lru[3]);
>> +        break;
>> +    case 3:
>> +        val = lru[2];
>> +        FFSWAP(int, lru[1], lru[2]);
>> +        break;
>> +    }
>
> cases 1-3 could be collapsed.

I do not see how.

>> +
>> +    return val;
>> +}
>> +
>> +static int bink2g_decode_dq(GetBitContext *gb)
>> +{
>> +    int dq = get_unary(gb, 1, 4);
>> +
>> +    if (dq == 3)
>> +        dq += get_bits1(gb);
>> +    else if (dq == 4)
>> +        dq += get_bits(gb, 5) + 1;
>> +    if (dq && get_bits1(gb))
>> +        dq = -dq;
>> +
>> +    return dq;
>> +}
>> +
>> +typedef uint8_t byte;
>> +typedef int8_t sbyte;
>> +typedef unsigned uint;
>
> but why?
>
>> +static void bink2g_get_cbp_flags(GetBitContext *gb, int offset, int size,
>> uint8_t *dst)
>> +{
>> +    unsigned flag;
>> +    int i, j;
>> +    byte bVar4;
>> +    sbyte sVar5;
>> +    byte bVar6;
>> +    int iVar7;
>> +    int uVar8;
>> +    int uVar9;
>> +    int local_20;
>> +    int local_1c;
>
> those variable names are not meaningful enough. in fact they look computer
> generated.

Yes, that code needs some refactoring.

>
> -- Peter
> (A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
>
Peter Ross April 7, 2019, 10:47 a.m. UTC | #7
On Sun, Apr 07, 2019 at 10:00:09AM +0200, Paul B Mahol wrote:
> On 4/7/19, Peter Ross <pross@xvid.org> wrote:
> > On Wed, Mar 27, 2019 at 09:21:47PM +0100, Paul B Mahol wrote:
> >> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> >> ---
> >> Missing deblocking.
> >> ---
> >>  configure               |    1 +
> >>  libavcodec/Makefile     |    1 +
> >>  libavcodec/allcodecs.c  |    1 +
> >>  libavcodec/avcodec.h    |    1 +
> >>  libavcodec/bink2.c      |  787 +++++++++++++++++++++++
> >>  libavcodec/bink2f.c     | 1139 +++++++++++++++++++++++++++++++++
> >>  libavcodec/bink2g.c     | 1342 +++++++++++++++++++++++++++++++++++++++

> >> +static int bink2g_get_type(GetBitContext *gb, int *lru)
> >> +{
> >> +    int val;
> >> +
> >> +    ff_dlog(NULL, " type show %X @ %d\n", show_bits(gb, 4),
> >> get_bits_count(gb));
> >> +    switch (get_unary(gb, 1, 3)) {
> >> +    case 0:
> >> +        val = lru[0];
> >> +        break;
> >> +    case 1:
> >> +        val = lru[1];
> >> +        FFSWAP(int, lru[0], lru[1]);
> >> +        break;
> >> +    case 2:
> >> +        val = lru[3];
> >> +        FFSWAP(int, lru[2], lru[3]);
> >> +        break;
> >> +    case 3:
> >> +        val = lru[2];
> >> +        FFSWAP(int, lru[1], lru[2]);
> >> +        break;
> >> +    }
> >
> > cases 1-3 could be collapsed.
> 
> I do not see how.

reorder the second and third elements in bink2g_decode_slice types_lru[].
that at least removes the val = lru[x] statement from each switch case.

as for the swaps, there is some (probably unintentional) symetry going on there.

the result could be:

int n = get_unary(gb, 1, 3)
int v = lru[n];
if (n) {
    int n2 = n == 1 ? 1 : 3;
    FFSWAP(int, lru[n - 1], lru[n2]);
}
return v;

this is a minor cleanup and in the scheme of things, may not even be worth it.

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

Patch

diff --git a/configure b/configure
index 331393f8d5..2fdb7e589c 100755
--- a/configure
+++ b/configure
@@ -2643,6 +2643,7 @@  atrac3p_decoder_select="mdct sinewin"
 atrac9_decoder_select="mdct"
 avrn_decoder_select="exif jpegtables"
 bink_decoder_select="blockdsp hpeldsp"
+bink2_decoder_select="blockdsp"
 binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
 binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
 cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 15c43a8a6a..d02240febc 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -228,6 +228,7 @@  OBJS-$(CONFIG_AYUV_ENCODER)            += v408enc.o
 OBJS-$(CONFIG_BETHSOFTVID_DECODER)     += bethsoftvideo.o
 OBJS-$(CONFIG_BFI_DECODER)             += bfi.o
 OBJS-$(CONFIG_BINK_DECODER)            += bink.o binkdsp.o
+OBJS-$(CONFIG_BINK2_DECODER)           += bink2.o
 OBJS-$(CONFIG_BINKAUDIO_DCT_DECODER)   += binkaudio.o
 OBJS-$(CONFIG_BINKAUDIO_RDFT_DECODER)  += binkaudio.o
 OBJS-$(CONFIG_BINTEXT_DECODER)         += bintext.o cga_data.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index b26aeca239..3a9ddb7b37 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -59,6 +59,7 @@  extern AVCodec ff_ayuv_decoder;
 extern AVCodec ff_bethsoftvid_decoder;
 extern AVCodec ff_bfi_decoder;
 extern AVCodec ff_bink_decoder;
+extern AVCodec ff_bink2_decoder;
 extern AVCodec ff_bitpacked_decoder;
 extern AVCodec ff_bmp_encoder;
 extern AVCodec ff_bmp_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 0ce22ec4fa..6b881ac351 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -454,6 +454,7 @@  enum AVCodecID {
     AV_CODEC_ID_RASC,
     AV_CODEC_ID_HYMT,
     AV_CODEC_ID_ARBC,
+    AV_CODEC_ID_BINKVIDEO2,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
new file mode 100644
index 0000000000..5513710bae
--- /dev/null
+++ b/libavcodec/bink2.c
@@ -0,0 +1,787 @@ 
+/*
+ * Bink video 2 decoder
+ * Copyright (c) 2014 Konstantin Shishkov
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * 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
+ */
+
+#define CACHED_BITSTREAM_READER 1
+#define DEBUG 1
+#define ASSERT_LEVEL 3
+#include "libavutil/avassert.h"
+#include "libavutil/attributes.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
+#include "avcodec.h"
+#include "blockdsp.h"
+#include "copy_block.h"
+#include "idctdsp.h"
+#include "internal.h"
+#include "mathops.h"
+
+#define BITSTREAM_READER_LE
+#include "get_bits.h"
+#include "unary.h"
+
+#define BINK_FLAG_ALPHA 0x00100000
+#define DC_MPRED(A, B, C) FFMIN(FFMAX((C) + (B) - (A), FFMIN3(A, B, C)), FFMAX3(A, B, C))
+#define DC_MPRED2(A, B) FFMIN(FFMAX((A), (B)), FFMAX(FFMIN((A), (B)), 2 * (A) - (B)))
+
+static VLC bink2f_quant_vlc;
+static VLC bink2f_ac_val0_vlc;
+static VLC bink2f_ac_val1_vlc;
+static VLC bink2f_ac_skip0_vlc;
+static VLC bink2f_ac_skip1_vlc;
+static VLC bink2g_ac_skip0_vlc;
+static VLC bink2g_ac_skip1_vlc;
+static VLC bink2g_mv_vlc;
+
+static const uint8_t kb2h_num_slices[] = {
+    2, 3, 4, 8,
+};
+
+static const uint8_t luma_repos[] = {
+    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
+};
+
+static const uint16_t bink2g_luma_intra_qmat[4][64] = {
+    {
+     1024,   1432,   1506,   1181,
+     1843,   2025,   5271,   8592,
+     1313,   1669,   1630,   1672,
+     2625,   3442,   8023,  12794,
+     1076,   1755,   1808,   1950,
+     3980,   4875,   8813,  11909,
+     1350,   1868,   2127,   2016,
+     4725,   4450,   7712,   9637,
+     2458,   3103,   4303,   4303,
+     6963,   6835,  11079,  13365,
+     3375,   5704,   5052,   6049,
+     9198,   7232,  10725,   9834,
+     5486,   7521,   7797,   7091,
+    11079,  10016,  13559,  12912,
+     7279,   7649,   7020,   6097,
+     9189,   9047,  12661,  13768,
+    },
+    {
+     1218,   1703,   1791,   1405,
+     2192,   2408,   6268,  10218,
+     1561,   1985,   1938,   1988,
+     3122,   4093,   9541,  15215,
+     1279,   2087,   2150,   2319,
+     4733,   5798,  10481,  14162,
+     1606,   2222,   2530,   2398,
+     5619,   5292,   9171,  11460,
+     2923,   3690,   5117,   5118,
+     8281,   8128,  13176,  15894,
+     4014,   6783,   6008,   7194,
+    10938,   8600,  12755,  11694,
+     6524,   8944,   9272,   8433,
+    13176,  11911,  16125,  15354,
+     8657,   9096,   8348,   7250,
+    10927,  10759,  15056,  16373,
+    },
+    {
+     1448,   2025,   2130,   1671,
+     2607,   2864,   7454,  12151,
+     1856,   2360,   2305,   2364,
+     3713,   4867,  11346,  18094,
+     1521,   2482,   2557,   2758,
+     5628,   6894,  12464,  16841,
+     1909,   2642,   3008,   2852,
+     6683,   6293,  10906,  13629,
+     3476,   4388,   6085,   6086,
+     9847,   9666,  15668,  18901,
+     4773,   8066,   7145,   8555,
+    13007,  10227,  15168,  13907,
+     7758,  10637,  11026,  10028,
+    15668,  14165,  19175,  18259,
+    10294,  10817,   9927,   8622,
+    12995,  12794,  17905,  19470,
+    },
+    {
+     1722,   2408,   2533,   1987,
+     3100,   3406,   8864,  14450,
+     2208,   2807,   2741,   2811,
+     4415,   5788,  13493,  21517,
+     1809,   2951,   3041,   3280,
+     6693,   8199,  14822,  20028,
+     2271,   3142,   3578,   3391,
+     7947,   7484,  12969,  16207,
+     4133,   5218,   7236,   7238,
+    11711,  11495,  18633,  22478,
+     5677,   9592,   8497,  10174,
+    15469,  12162,  18038,  16538,
+     9226,  12649,  13112,  11926,
+    18633,  16845,  22804,  21715,
+    12242,  12864,  11806,  10254,
+    15454,  15215,  21293,  23155,
+    },
+};
+
+static const uint16_t bink2g_chroma_intra_qmat[4][64] = {
+    {
+     1024,   1193,   1434,   2203,
+     5632,   4641,   5916,   6563,
+     1193,   1622,   1811,   3606,
+     6563,   5408,   6894,   7649,
+     1434,   1811,   3515,   4875,
+     5916,   4875,   6215,   6894,
+     2203,   3606,   4875,   3824,
+     4641,   3824,   4875,   5408,
+     5632,   6563,   5916,   4641,
+     5632,   4641,   5916,   6563,
+     4641,   5408,   4875,   3824,
+     4641,   3824,   4875,   5408,
+     5916,   6894,   6215,   4875,
+     5916,   4875,   6215,   6894,
+     6563,   7649,   6894,   5408,
+     6563,   5408,   6894,   7649,
+    },
+    {
+     1218,   1419,   1706,   2620,
+     6698,   5519,   7035,   7805,
+     1419,   1929,   2153,   4288,
+     7805,   6432,   8199,   9096,
+     1706,   2153,   4180,   5798,
+     7035,   5798,   7390,   8199,
+     2620,   4288,   5798,   4548,
+     5519,   4548,   5798,   6432,
+     6698,   7805,   7035,   5519,
+     6698,   5519,   7035,   7805,
+     5519,   6432,   5798,   4548,
+     5519,   4548,   5798,   6432,
+     7035,   8199,   7390,   5798,
+     7035,   5798,   7390,   8199,
+     7805,   9096,   8199,   6432,
+     7805,   6432,   8199,   9096,
+    },
+    {
+     1448,   1688,   2028,   3116,
+     7965,   6563,   8367,   9282,
+     1688,   2294,   2561,   5099,
+     9282,   7649,   9750,  10817,
+     2028,   2561,   4971,   6894,
+     8367,   6894,   8789,   9750,
+     3116,   5099,   6894,   5408,
+     6563,   5408,   6894,   7649,
+     7965,   9282,   8367,   6563,
+     7965,   6563,   8367,   9282,
+     6563,   7649,   6894,   5408,
+     6563,   5408,   6894,   7649,
+     8367,   9750,   8789,   6894,
+     8367,   6894,   8789,   9750,
+     9282,  10817,   9750,   7649,
+     9282,   7649,   9750,  10817,
+    },
+    {
+     1722,   2007,   2412,   3706,
+     9472,   7805,   9950,  11038,
+     2007,   2729,   3045,   6064,
+    11038,   9096,  11595,  12864,
+     2412,   3045,   5912,   8199,
+     9950,   8199,  10452,  11595,
+     3706,   6064,   8199,   6432,
+     7805,   6432,   8199,   9096,
+     9472,  11038,   9950,   7805,
+     9472,   7805,   9950,  11038,
+     7805,   9096,   8199,   6432,
+     7805,   6432,   8199,   9096,
+     9950,  11595,  10452,   8199,
+     9950,   8199,  10452,  11595,
+    11038,  12864,  11595,   9096,
+    11038,   9096,  11595,  12864,
+    },
+};
+
+
+static const uint16_t bink2g_inter_qmat[4][64] = {
+    {
+     1024,   1193,   1076,    844,
+     1052,    914,   1225,   1492,
+     1193,   1391,   1254,    983,
+     1227,   1065,   1463,   1816,
+     1076,   1254,   1161,    936,
+     1195,   1034,   1444,   1741,
+      844,    983,    936,    811,
+     1055,    927,   1305,   1584,
+     1052,   1227,   1195,   1055,
+     1451,   1336,   1912,   2354,
+      914,   1065,   1034,    927,
+     1336,   1313,   1945,   2486,
+     1225,   1463,   1444,   1305,
+     1912,   1945,   3044,   4039,
+     1492,   1816,   1741,   1584,
+     2354,   2486,   4039,   5679,
+    },
+    {
+     1218,   1419,   1279,   1003,
+     1252,   1087,   1457,   1774,
+     1419,   1654,   1491,   1169,
+     1459,   1267,   1739,   2159,
+     1279,   1491,   1381,   1113,
+     1421,   1230,   1717,   2070,
+     1003,   1169,   1113,    965,
+     1254,   1103,   1552,   1884,
+     1252,   1459,   1421,   1254,
+     1725,   1589,   2274,   2799,
+     1087,   1267,   1230,   1103,
+     1589,   1562,   2313,   2956,
+     1457,   1739,   1717,   1552,
+     2274,   2313,   3620,   4803,
+     1774,   2159,   2070,   1884,
+     2799,   2956,   4803,   6753,
+    },
+    {
+     1448,   1688,   1521,   1193,
+     1488,   1293,   1732,   2110,
+     1688,   1967,   1773,   1391,
+     1735,   1507,   2068,   2568,
+     1521,   1773,   1642,   1323,
+     1690,   1462,   2042,   2462,
+     1193,   1391,   1323,   1147,
+     1492,   1311,   1845,   2241,
+     1488,   1735,   1690,   1492,
+     2052,   1889,   2704,   3328,
+     1293,   1507,   1462,   1311,
+     1889,   1857,   2751,   3515,
+     1732,   2068,   2042,   1845,
+     2704,   2751,   4306,   5712,
+     2110,   2568,   2462,   2241,
+     3328,   3515,   5712,   8031,
+    },
+    {
+     1722,   2007,   1809,   1419,
+     1770,   1537,   2060,   2509,
+     2007,   2339,   2108,   1654,
+     2063,   1792,   2460,   3054,
+     1809,   2108,   1953,   1574,
+     2010,   1739,   2428,   2928,
+     1419,   1654,   1574,   1364,
+     1774,   1559,   2195,   2664,
+     1770,   2063,   2010,   1774,
+     2440,   2247,   3216,   3958,
+     1537,   1792,   1739,   1559,
+     2247,   2209,   3271,   4181,
+     2060,   2460,   2428,   2195,
+     3216,   3271,   5120,   6793,
+     2509,   3054,   2928,   2664,
+     3958,   4181,   6793,   9550,
+    },
+};
+
+static uint8_t bink2g_chroma_cbp_pat[16] = {
+    0x00, 0x00, 0x00, 0x0F,
+    0x00, 0x0F, 0x0F, 0x0F,
+    0x00, 0x0F, 0x0F, 0x0F,
+    0x0F, 0x0F, 0x0F, 0x0F,
+};
+
+static const int32_t bink2g_dc_pat[] = {
+    1024, 1218, 1448, 1722, 2048,
+    2435, 2896, 3444, 4096, 4871,
+    5793, 6889, 8192, 9742, 11585, 13777, 16384,
+    19484, 23170,  27555, 32768, 38968, 46341,
+    55109, 65536, 77936, 92682, 110218, 131072,
+    155872, 185364, 220436, 262144, 311744,
+    370728, 440872, 524288,
+};
+
+static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };
+
+static const uint8_t bink2f_quant_codes[16] = {
+    0x01, 0x02, 0x04, 0x08, 0x10, 0x30, 0x50, 0x70,
+    0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0,
+};
+
+static const uint8_t bink2f_quant_bits[16] = {
+    1, 2, 3, 4, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const uint16_t bink2f_ac_val_codes[2][13] = {
+    {
+        0x04, 0x01, 0x02, 0x00, 0x08, 0x18, 0xF8, 0x178, 0x138,
+        0x38, 0x1B8, 0x78, 0xB8
+    },
+    {
+        0x0A, 0x01, 0x04, 0x08, 0x06, 0x00, 0x02, 0x1A, 0x2A,
+        0x16A, 0x1EA, 0x6A, 0xEA
+    },
+};
+
+static const uint8_t bink2f_ac_val_bits[2][13] = {
+    { 3, 1, 2, 4, 5, 6, 8, 9, 9, 9, 9, 9, 9 },
+    { 6, 1, 3, 4, 3, 4, 4, 5, 7, 9, 9, 9, 9 },
+};
+
+#define NUM_AC_SKIPS 14
+static const uint16_t bink2f_ac_skip_codes[2][NUM_AC_SKIPS] = {
+    {
+        0x00, 0x01, 0x0D, 0x15, 0x45, 0x85, 0xA5, 0x165,
+        0x65, 0x1E5, 0xE5, 0x25, 0x03, 0x05
+    },
+    {
+        0x00, 0x01, 0x03, 0x07, 0x1F, 0x1B, 0x0F, 0x2F,
+        0x5B, 0xDB, 0x1DB, 0x3B, 0x05, 0x0B
+    }
+};
+
+static const uint8_t bink2f_ac_skip_bits[2][NUM_AC_SKIPS] = {
+    { 1, 3, 4, 5, 7, 8, 8, 9, 9, 9, 9, 8, 2, 8 },
+    { 1, 3, 4, 4, 5, 7, 6, 6, 8, 9, 9, 6, 3, 5 }
+};
+
+static const uint8_t bink2f_skips[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 62, 0, 0, 0,
+};
+
+static const uint8_t bink2g_skips[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0,
+};
+
+static const uint8_t bink2f_next_skips[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
+};
+
+static const uint8_t bink2_next_skips[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
+};
+
+static const uint16_t bink2g_ac_skip_codes[2][NUM_AC_SKIPS] = {
+    {
+        0x01, 0x00, 0x004, 0x02C, 0x06C, 0x0C, 0x4C,
+        0xAC, 0xEC, 0x12C, 0x16C, 0x1AC, 0x02, 0x1C,
+    },
+    {
+        0x01, 0x04, 0x00, 0x08, 0x02, 0x32, 0x0A,
+        0x12, 0x3A, 0x7A, 0xFA, 0x72, 0x06, 0x1A,
+    },
+};
+
+static const uint8_t bink2g_ac_skip_bits[2][NUM_AC_SKIPS] = {
+    { 1, 3, 4, 9, 9, 7, 7, 9, 8, 9, 9, 9, 2, 5 },
+    { 1, 3, 4, 4, 5, 7, 5, 6, 7, 8, 8, 7, 3, 6 },
+};
+
+static const uint8_t bink2g_mv_codes[] = {
+    0x01, 0x06, 0x0C, 0x1C, 0x18, 0x38, 0x58, 0x78,
+    0x68, 0x48, 0x28, 0x08, 0x14, 0x04, 0x02, 0x00,
+};
+
+static const uint8_t bink2g_mv_bits[] = {
+    1, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 3, 4,
+};
+
+static const float bink2f_dc_quant[16] = {
+    4, 4, 4, 4, 4, 6, 7, 8, 10, 12, 16, 24, 32, 48, 64, 128
+};
+
+static const float bink2f_ac_quant[16] = {
+    1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 6.0, 7.0, 8.0, 12.0, 16.0, 24.0, 32.0, 48.0, 64.0, 128.0
+};
+
+static const float bink2f_luma_intra_qmat[64] = {
+    0.125,    0.190718, 0.16332,  0.235175, 0.3,      0.392847, 0.345013, 0.210373,
+    0.208056, 0.288582, 0.317145, 0.387359, 0.450788, 0.790098, 0.562995, 0.263095,
+    0.228649, 0.294491, 0.341421, 0.460907, 0.653281, 0.731424, 0.60988,  0.252336,
+    0.205778, 0.346585, 0.422498, 0.501223, 0.749621, 1.004719, 0.636379, 0.251428,
+    0.225,    0.381436, 0.604285, 0.823113, 0.85,     1.070509, 0.69679,  0.265553,
+    0.235708, 0.476783, 0.70576,  0.739104, 0.795516, 0.802512, 0.600616, 0.249289,
+    0.331483, 0.600528, 0.689429, 0.692062, 0.69679,  0.643138, 0.43934,  0.188511,
+    0.248309, 0.440086, 0.42807,  0.397419, 0.386259, 0.270966, 0.192244, 0.094199,
+};
+
+static const float bink2f_luma_inter_qmat[64] = {
+    0.125,    0.17338,  0.16332,  0.146984, 0.128475, 0.106393, 0.077046, 0.043109,
+    0.17338,  0.240485, 0.226532, 0.203873, 0.1782,   0.147571, 0.109474, 0.062454,
+    0.16332,  0.226532, 0.219321, 0.202722, 0.181465, 0.149711, 0.112943, 0.062584,
+    0.146984, 0.203873, 0.202722, 0.201647, 0.183731, 0.153976, 0.11711,  0.065335,
+    0.128475, 0.1782,   0.181465, 0.183731, 0.177088, 0.155499, 0.120267, 0.068016,
+    0.106393, 0.147571, 0.149711, 0.153976, 0.155499, 0.145756, 0.116636, 0.068495,
+    0.077046, 0.109474, 0.112943, 0.11711,  0.120267, 0.116636, 0.098646, 0.060141,
+    0.043109, 0.062454, 0.062584, 0.065335, 0.068016, 0.068495, 0.060141, 0.038853,
+};
+
+static const float bink2f_chroma_qmat[64] = {
+    0.125,      0.17338,    0.217761,   0.383793,   0.6875,     0.54016501, 0.37207201, 0.18968099,
+    0.17338,    0.28056601, 0.32721299, 0.74753499, 0.95358998, 0.74923098, 0.51607901, 0.26309499,
+    0.217761,   0.32721299, 0.66387498, 1.056244,   0.89826202, 0.70576,    0.48613599, 0.24783,
+    0.383793,   0.74753499, 1.056244,   0.95059502, 0.80841398, 0.635167,   0.437511,   0.223041,
+    0.6875,     0.95358998, 0.89826202, 0.80841398, 0.6875,     0.54016501, 0.37207201, 0.18968099,
+    0.54016501, 0.74923098, 0.70576,    0.635167,   0.54016501, 0.42440501, 0.292335,   0.149031,
+    0.37207201, 0.51607901, 0.48613599, 0.437511,   0.37207201, 0.292335,   0.201364,   0.102655,
+    0.18968099, 0.26309499, 0.24783,    0.223041,   0.18968099, 0.149031,   0.102655,   0.052333001
+};
+
+static const uint8_t bink2f_luma_scan[64] = {
+     0,  2,  1,  8,  9, 17, 10, 16,
+    24,  3, 18, 25, 32, 11, 33, 26,
+     4, 40, 19, 12, 27, 41, 34,  5,
+    20, 48,  6, 28, 15, 42, 23, 35,
+    21, 13, 14,  7, 31, 43, 49, 36,
+    22, 56, 39, 50, 30, 44, 29, 51,
+    57, 47, 58, 59, 63, 61, 55, 38,
+    52, 62, 45, 37, 60, 46, 54, 53
+};
+
+static const uint8_t bink2f_chroma_scan[64] = {
+     0,  1,  8,  2,  9, 16, 10, 17,
+     3, 24, 11, 18, 25, 13, 14,  4,
+    15,  5,  6,  7, 12, 19, 20, 21,
+    22, 23, 26, 27, 28, 29, 30, 31,
+    32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47,
+    48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 58, 59, 60, 61, 62, 63
+};
+
+static const uint8_t bink2g_scan[64] = {
+     0,   8,   1,   2,  9,  16,  24,  17,
+    10,   3,   4,  11, 18,  25,  32,  40,
+    33,  26,  19,  12,  5,   6,  13,  20,
+    27,  34,  41,  48, 56,  49,  42,  35,
+    28,  21,  14,   7, 15,  22,  29,  36,
+    43,  50,  57,  58, 51,  44,  37,  30,
+    23,  31,  38,  45, 52,  59,  60,  53,
+    46,  39,  47,  54, 61,  62,  55,  63,
+};
+
+typedef struct QuantPredict {
+    int8_t intra_q;
+    int8_t inter_q;
+} QuantPredict;
+
+typedef struct DCPredict {
+    float dc[4][16];
+    int   block_type;
+} DCPredict;
+
+typedef struct DCIPredict {
+    int dc[4][16];
+    int block_type;
+} DCIPredict;
+
+typedef struct MVectors {
+    int v[4][2];
+    int nb_vectors;
+} MVectors;
+
+typedef struct MVPredict {
+    MVectors mv;
+} MVPredict;
+
+/*
+ * Decoder context
+ */
+typedef struct Bink2Context {
+    AVCodecContext  *avctx;
+    GetBitContext   gb;
+    BlockDSPContext dsp;
+    AVFrame         *last;
+    int             version;              ///< internal Bink file version
+    int             has_alpha;
+
+    DECLARE_ALIGNED(16, float, block[4][64]);
+    DECLARE_ALIGNED(16, int16_t, iblock[4][64]);
+
+    QuantPredict    *current_q;
+    QuantPredict    *prev_q;
+
+    DCPredict       *current_dc;
+    DCPredict       *prev_dc;
+
+    DCIPredict      *current_idc;
+    DCIPredict      *prev_idc;
+
+    MVPredict       *current_mv;
+    MVPredict       *prev_mv;
+
+    uint8_t         *col_cbp;
+    uint8_t         *row_cbp;
+
+    int             num_slices;
+    int             slice_height[4];
+
+    int             comp;
+    int             mb_pos;
+    unsigned        flags;
+    unsigned        frame_flags;
+} Bink2Context;
+
+/**
+ * Bink2 video block types
+ */
+enum BlockTypes {
+    INTRA_BLOCK = 0, ///< intra DCT block
+    SKIP_BLOCK,      ///< skipped block
+    MOTION_BLOCK,    ///< block is copied from previous frame with some offset
+    RESIDUE_BLOCK,   ///< motion block with some difference added
+};
+
+static const uint8_t ones_count[16] = {
+    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+
+#include "bink2f.c"
+#include "bink2g.c"
+
+static int bink2_decode_frame(AVCodecContext *avctx, void *data,
+                              int *got_frame, AVPacket *pkt)
+{
+    Bink2Context * const c = avctx->priv_data;
+    GetBitContext *gb = &c->gb;
+    AVFrame *frame = data;
+    uint8_t *dst[4];
+    uint8_t *src[4];
+    int stride[4];
+    int sstride[4];
+    uint32_t off = 0;
+    int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY);
+    int ret, w, h;
+    int height_a;
+
+    w = avctx->width;
+    h = avctx->height;
+    ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32));
+    if (ret < 0)
+        return ret;
+    avctx->width  = w;
+    avctx->height = h;
+
+    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
+        return ret;
+
+    for (int i = 0; i < 4; i++) {
+        src[i]     = c->last->data[i];
+        dst[i]     = frame->data[i];
+        stride[i]  = frame->linesize[i];
+        sstride[i] = c->last->linesize[i];
+    }
+
+    c->frame_flags = AV_RL32(pkt->data);
+    ff_dlog(NULL, "frame flags %X\n", c->frame_flags);
+
+    if ((ret = init_get_bits8(gb, pkt->data, pkt->size)) < 0)
+        return ret;
+
+    height_a = (avctx->height + 31) & 0xFFFFFFE0;
+    if (c->version <= 'f') {
+        c->num_slices = 2;
+        c->slice_height[0] = (avctx->height / 2 + 16) & 0xFFFFFFE0;
+    } else if (c->version == 'g') {
+        if (height_a < 128) {
+            c->num_slices = 1;
+        } else {
+            c->num_slices = 2;
+            c->slice_height[0] = (avctx->height / 2 + 16) & 0xFFFFFFE0;
+        }
+    } else {
+        int start, end;
+
+        c->num_slices = kb2h_num_slices[c->flags & 3];
+        start = 0;
+        end = height_a + 32 * c->num_slices - 1;
+        for (int i = 0; i < c->num_slices - 1; i++) {
+            start += ((end - start) / (c->num_slices - i)) & 0xFFFFFFE0;
+            end -= 32;
+            c->slice_height[i] = start;
+        }
+    }
+    c->slice_height[c->num_slices - 1] = height_a;
+
+    skip_bits_long(gb, 32 + 32 * (c->num_slices - 1));
+
+    if (c->frame_flags & 0x10000) {
+        if (!(c->frame_flags & 0x8000))
+            bink2g_get_cbp_flags(gb, 1, (((avctx->height + 15) & ~15) >> 3) - 1, c->row_cbp);
+        if (!(c->frame_flags & 0x4000))
+            bink2g_get_cbp_flags(gb, 1, (((avctx->width + 15) & ~15) >> 3) - 1, c->col_cbp);
+    }
+
+    for (int i = 0; i < c->num_slices; i++) {
+        if (i == c->num_slices - 1)
+            off = pkt->size;
+        else
+            off = AV_RL32(pkt->data + 4 + i * 4);
+
+        if (c->version <= 'f')
+            ret = bink2f_decode_slice(c, dst, stride, src, sstride, is_kf, i ? c->slice_height[i-1] : 0, c->slice_height[i]);
+        else
+            ret = bink2g_decode_slice(c, dst, stride, src, sstride, is_kf, i ? c->slice_height[i-1] : 0, c->slice_height[i]);
+        if (0 && ret < 0)
+            return ret;
+
+        align_get_bits(gb);
+        if (get_bits_left(gb) < 0)
+            av_log(avctx, AV_LOG_WARNING, "slice %d: overread\n", i);
+        if (8 * (off - (get_bits_count(gb) >> 3)) > 24)
+            av_log(avctx, AV_LOG_WARNING, "slice %d: underread %d\n", i, 8 * (off - (get_bits_count(gb) >> 3)));
+        skip_bits_long(gb, 8 * (off - (get_bits_count(gb) >> 3)));
+
+        dst[0] = frame->data[0] + c->slice_height[i]   * stride[0];
+        dst[1] = frame->data[1] + c->slice_height[i]/2 * stride[1];
+        dst[2] = frame->data[2] + c->slice_height[i]/2 * stride[2];
+        dst[3] = frame->data[3] + c->slice_height[i]   * stride[3];
+    }
+
+    frame->key_frame = is_kf;
+    frame->pict_type = is_kf ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P;
+
+    av_frame_unref(c->last);
+    if ((ret = av_frame_ref(c->last, frame)) < 0)
+        return ret;
+
+    *got_frame = 1;
+
+    /* always report that the buffer was completely consumed */
+    return pkt->size;
+}
+
+#define INIT_VLC_STATIC_LE(vlc, nb_bits, nb_codes,                 \
+                           bits, bits_wrap, bits_size,             \
+                           codes, codes_wrap, codes_size,          \
+                           symbols, symbols_wrap, symbols_size,    \
+                           static_size)                            \
+    do {                                                           \
+        static VLC_TYPE table[static_size][2];                     \
+        (vlc)->table           = table;                            \
+        (vlc)->table_allocated = static_size;                      \
+        ff_init_vlc_sparse(vlc, nb_bits, nb_codes,                 \
+                           bits, bits_wrap, bits_size,             \
+                           codes, codes_wrap, codes_size,          \
+                           symbols, symbols_wrap, symbols_size,    \
+                           INIT_VLC_LE | INIT_VLC_USE_NEW_STATIC); \
+    } while (0)
+
+static av_cold int bink2_decode_init(AVCodecContext *avctx)
+{
+    Bink2Context * const c = avctx->priv_data;
+    int ret;
+
+    c->version = avctx->codec_tag >> 24;
+    if (avctx->extradata_size < 4) {
+        av_log(avctx, AV_LOG_ERROR, "Extradata missing or too short\n");
+        return AVERROR_INVALIDDATA;
+    }
+    c->flags = AV_RL32(avctx->extradata);
+    av_log(avctx, AV_LOG_DEBUG, "flags: 0x%X\n", c->flags);
+    c->has_alpha = c->flags & BINK_FLAG_ALPHA;
+    c->avctx = avctx;
+
+    c->last = av_frame_alloc();
+    if (!c->last)
+        return AVERROR(ENOMEM);
+
+    if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0)
+        return ret;
+
+    avctx->pix_fmt = c->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P;
+
+    ff_blockdsp_init(&c->dsp, avctx);
+
+    INIT_VLC_STATIC_LE(&bink2f_quant_vlc, 9, FF_ARRAY_ELEMS(bink2f_quant_codes),
+                       bink2f_quant_bits, 1, 1, bink2f_quant_codes, 1, 1, NULL, 0, 0, 512);
+    INIT_VLC_STATIC_LE(&bink2f_ac_val0_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_val_bits[0]),
+                       bink2f_ac_val_bits[0], 1, 1, bink2f_ac_val_codes[0], 2, 2, NULL, 0, 0, 512);
+    INIT_VLC_STATIC_LE(&bink2f_ac_val1_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_val_bits[1]),
+                       bink2f_ac_val_bits[1], 1, 1, bink2f_ac_val_codes[1], 2, 2, NULL, 0, 0, 512);
+    INIT_VLC_STATIC_LE(&bink2f_ac_skip0_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_skip_bits[0]),
+                       bink2f_ac_skip_bits[0], 1, 1, bink2f_ac_skip_codes[0], 2, 2, NULL, 0, 0, 512);
+    INIT_VLC_STATIC_LE(&bink2f_ac_skip1_vlc, 9, FF_ARRAY_ELEMS(bink2f_ac_skip_bits[1]),
+                       bink2f_ac_skip_bits[1], 1, 1, bink2f_ac_skip_codes[1], 2, 2, NULL, 0, 0, 512);
+
+    INIT_VLC_STATIC_LE(&bink2g_ac_skip0_vlc, 9, FF_ARRAY_ELEMS(bink2g_ac_skip_bits[0]),
+                       bink2g_ac_skip_bits[0], 1, 1, bink2g_ac_skip_codes[0], 2, 2, NULL, 0, 0, 512);
+    INIT_VLC_STATIC_LE(&bink2g_ac_skip1_vlc, 9, FF_ARRAY_ELEMS(bink2g_ac_skip_bits[1]),
+                       bink2g_ac_skip_bits[1], 1, 1, bink2g_ac_skip_codes[1], 2, 2, NULL, 0, 0, 512);
+    INIT_VLC_STATIC_LE(&bink2g_mv_vlc, 9, FF_ARRAY_ELEMS(bink2g_mv_bits),
+                       bink2g_mv_bits, 1, 1, bink2g_mv_codes, 1, 1, NULL, 0, 0, 512);
+
+    c->current_q = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_q));
+    if (!c->current_q)
+        return AVERROR(ENOMEM);
+
+    c->prev_q = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_q));
+    if (!c->prev_q)
+        return AVERROR(ENOMEM);
+
+    c->current_dc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_dc));
+    if (!c->current_dc)
+        return AVERROR(ENOMEM);
+
+    c->prev_dc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_dc));
+    if (!c->prev_dc)
+        return AVERROR(ENOMEM);
+
+    c->current_idc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_idc));
+    if (!c->current_idc)
+        return AVERROR(ENOMEM);
+
+    c->prev_idc = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_idc));
+    if (!c->prev_q)
+        return AVERROR(ENOMEM);
+
+    c->current_mv = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->current_mv));
+    if (!c->current_mv)
+        return AVERROR(ENOMEM);
+
+    c->prev_mv = av_malloc_array((avctx->width + 31) / 32, sizeof(*c->prev_mv));
+    if (!c->prev_mv)
+        return AVERROR(ENOMEM);
+
+    c->col_cbp = av_calloc((((avctx->width + 31) >> 3) + 7) >> 3, sizeof(*c->col_cbp));
+    if (!c->col_cbp)
+        return AVERROR(ENOMEM);
+
+    c->row_cbp = av_calloc((((avctx->height + 31) >> 3) + 7) >> 3, sizeof(*c->row_cbp));
+    if (!c->row_cbp)
+        return AVERROR(ENOMEM);
+
+    return 0;
+}
+
+static av_cold int bink2_decode_end(AVCodecContext *avctx)
+{
+    Bink2Context * const c = avctx->priv_data;
+
+    av_frame_free(&c->last);
+    av_freep(&c->current_q);
+    av_freep(&c->prev_q);
+    av_freep(&c->current_dc);
+    av_freep(&c->prev_dc);
+    av_freep(&c->current_idc);
+    av_freep(&c->prev_idc);
+    av_freep(&c->current_mv);
+    av_freep(&c->prev_mv);
+    av_freep(&c->col_cbp);
+    av_freep(&c->row_cbp);
+
+    return 0;
+}
+
+AVCodec ff_bink2_decoder = {
+    .name           = "binkvideo2",
+    .long_name      = NULL_IF_CONFIG_SMALL("Bink video 2"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_BINKVIDEO2,
+    .priv_data_size = sizeof(Bink2Context),
+    .init           = bink2_decode_init,
+    .close          = bink2_decode_end,
+    .decode         = bink2_decode_frame,
+    .capabilities   = AV_CODEC_CAP_DR1,
+};
diff --git a/libavcodec/bink2f.c b/libavcodec/bink2f.c
new file mode 100644
index 0000000000..487c53038d
--- /dev/null
+++ b/libavcodec/bink2f.c
@@ -0,0 +1,1139 @@ 
+/*
+ * Bink video 2 decoder
+ * Copyright (c) 2014 Konstantin Shishkov
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * 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
+ */
+
+static inline void bink2f_idct_1d(float *blk, int step)
+{
+    float t00 =  blk[2 * step] + blk[6 * step];
+    float t01 = (blk[2 * step] - blk[6 * step]) * 1.4142135f - t00;
+    float t02 =  blk[0 * step] + blk[4 * step];
+    float t03 =  blk[0 * step] - blk[4 * step];
+    float t04 =  blk[3 * step] + blk[5 * step];
+    float t05 =  blk[3 * step] - blk[5 * step];
+    float t06 =  blk[1 * step] + blk[7 * step];
+    float t07 =  blk[1 * step] - blk[7 * step];
+    float t08 = t02 + t00;
+    float t09 = t02 - t00;
+    float t10 = t03 + t01;
+    float t11 = t03 - t01;
+    float t12 = t06 + t04;
+    float t13 = (t06 - t04) * 1.4142135f;
+    float t14 = (t07 - t05) * 1.847759f;
+    float t15 = t05 * 2.613126f + t14 - t12;
+    float t16 = t13 - t15;
+    float t17 = t07 * 1.0823922f - t14 + t16;
+
+    blk[0*step] = t08 + t12;
+    blk[1*step] = t10 + t15;
+    blk[2*step] = t11 + t16;
+    blk[3*step] = t09 - t17;
+    blk[4*step] = t09 + t17;
+    blk[5*step] = t11 - t16;
+    blk[6*step] = t10 - t15;
+    blk[7*step] = t08 - t12;
+}
+
+static void bink2f_idct_put(uint8_t *dst, int stride, float *block)
+{
+    block[0] += 512.5f;
+
+    for (int i = 0; i < 8; i++)
+        bink2f_idct_1d(block + i, 8);
+    for (int i = 0; i < 8; i++) {
+        bink2f_idct_1d(block, 1);
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(block[j] - 512.0f);
+        block += 8;
+        dst += stride;
+    }
+}
+
+static void bink2f_idct_add(uint8_t *dst, int stride,
+                            float *block)
+{
+    block[0] += 512.5f;
+
+    for (int i = 0; i < 8; i++)
+        bink2f_idct_1d(block + i, 8);
+    for (int i = 0; i < 8; i++) {
+        bink2f_idct_1d(block, 1);
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(dst[j] + block[j] - 512.0f);
+        block += 8;
+        dst += stride;
+    }
+}
+
+static int bink2f_decode_delta_q(GetBitContext *gb)
+{
+    int dq = get_vlc2(gb, bink2f_quant_vlc.table, bink2f_quant_vlc.bits, 1);
+
+    if (dq < 0)
+        return AVERROR_INVALIDDATA;
+    if (dq && get_bits1(gb))
+        dq = -dq;
+
+    return dq;
+}
+
+static unsigned bink2f_decode_cbp_luma(GetBitContext *gb, unsigned prev_cbp)
+{
+    unsigned cbp, cbp4, cbplo, cbphi;
+
+    if (get_bits1(gb)) {
+        if (get_bits1(gb))
+            return prev_cbp;
+        cbplo = prev_cbp & 0xFFFF;
+    } else {
+        cbplo = 0;
+        cbp4 = (prev_cbp >> 4) & 0xF;
+        for (int i = 0; i < 4; i++) {
+            if (!get_bits1(gb))
+                cbp4 = get_bits(gb, 4);
+            cbplo |= cbp4 << (i * 4);
+        }
+    }
+    cbphi = 0;
+    cbp = cbplo;
+    cbp4 = prev_cbp >> 20 & 0xF;
+    for (int i = 0; i < 4; i++) {
+        if (ones_count[cbp & 0xF]) {
+            if (ones_count[cbp & 0xF] == 1) {
+                cbp4 = 0;
+                for (int j = 1; j < 16; j <<= 1) {
+                    if ((j & cbp) && get_bits1(gb))
+                        cbp4 |= j;
+                }
+            } else if (!get_bits1(gb)) {
+                cbp4 = 0;
+                for (int j = 1; j < 16; j <<= 1) {
+                    if ((j & cbp) && get_bits1(gb))
+                        cbp4 |= j;
+                }
+            }
+        } else {
+            cbp4 = 0;
+        }
+        cbp4 &= cbp;
+        cbphi = (cbphi >> 4) | (cbp4 << 0x1c);
+        cbp >>= 4;
+    }
+    return cbphi | cbplo;
+}
+
+static unsigned bink2f_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp)
+{
+    unsigned cbplo, cbphi;
+
+    if (get_bits1(gb)) {
+        if (get_bits1(gb))
+            return prev_cbp;
+        cbplo = prev_cbp & 0xF;
+    } else {
+        cbplo = get_bits(gb, 4);
+    }
+
+    cbphi = 0;
+    if (ones_count[cbplo & 0xF]) {
+        if (ones_count[cbplo & 0xF] != 1) {
+            cbphi = (prev_cbp >> 16) & cbplo;
+            if (get_bits1(gb))
+                return cbplo | (cbphi << 16);
+        }
+        cbphi = 0;
+        for (int j = 1; j < 16; j <<= 1) {
+            if ((j & cbplo) && get_bits1(gb))
+                cbphi |= j;
+        }
+    }
+    return cbplo | (cbphi << 16);
+}
+
+static const uint8_t q_dc_bits[16] = {
+    2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7
+};
+
+static void bink2f_predict_dc(Bink2Context *c,
+                              int is_luma, float mindc, float maxdc,
+                              int flags, float tdc[16])
+{
+    float *LTdc = c->prev_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
+    float *Tdc = c->prev_dc[c->mb_pos].dc[c->comp];
+    float *Ldc = c->current_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
+    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
+
+    if (is_luma && (flags & 0x20) && (flags & 0x80)) {
+        dc[0]  = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(dc[4] + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma && (flags & 0x80)) {
+        dc[0]  = av_clipf(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(dc[4] + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma && (flags & 0x20)) {
+        dc[0]  = av_clipf(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma) {
+        dc[0]  = av_clipf(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) {
+        dc[0] = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x80)) {
+        dc[0] = av_clipf(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x20)) {
+        dc[0] = av_clipf(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma) {
+        dc[0] = av_clipf(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    }
+}
+
+static void bink2f_decode_dc(Bink2Context *c, GetBitContext *gb, float *dc,
+                             int is_luma, int q, int mindc, int maxdc,
+                             int flags)
+{
+    const int num_dc = is_luma ? 16 : 4;
+    float tdc[16] = { 0 };
+    int dc_bits;
+
+    dc_bits = get_bits(gb, 3);
+    if (dc_bits == 7)
+        dc_bits += get_bits(gb, 2);
+    //ff_dlog(NULL, "   DC bits %d @ %d\n", dc_bits, get_bits_count(gb));
+    if (!dc_bits) {
+        memset(dc, 0, sizeof(*dc) * num_dc);
+    } else {
+        for (int j = 0; j < num_dc; j += 4) {
+            for (int i = 0; i < 4; i++)
+                tdc[i + j] = get_bits(gb, dc_bits);
+
+            for (int i = 0; i < 4; i++)
+                if (tdc[i + j] && get_bits1(gb))
+                    tdc[i + j] = -tdc[i + j];
+        }
+    }
+
+    if ((flags & 0x20) && (flags & 0x80) && mindc >= 0) {
+        int bits = (q_dc_bits[q] - 1) + dc_bits;
+
+        if (bits < 10) {
+            int dc_val = get_bits(gb, 10 - bits);
+
+            if (dc_val) {
+               dc_val <<= dc_bits;
+               if (get_bits1(gb))
+                   dc_val = -dc_val;
+            }
+            //ff_dlog(NULL, "   start DC %d (%d bits) @ %d\n", dc_val, dc_bits, get_bits_count(gb));
+            tdc[0] += dc_val;
+        }
+    }
+
+    for (int i = 0; i < num_dc; i++)
+        tdc[i] *= bink2f_dc_quant[q];
+
+    bink2f_predict_dc(c, is_luma, mindc, maxdc, flags, tdc);
+}
+
+static int bink2f_decode_ac(GetBitContext *gb, const uint8_t *scan,
+                            float block[4][64], unsigned cbp,
+                            float q, const float qmat[64])
+{
+    int idx, next, val, skip;
+    VLC *val_vlc, *skip_vlc;
+
+    for (int i = 0; i < 4; i++, cbp >>= 1) {
+        memset(block[i], 0, sizeof(**block) * 64);
+
+        if (!(cbp & 1))
+            continue;
+
+        //ff_dlog(NULL, "   blk %d\n", i);
+        if (cbp & 0x10000) {
+            val_vlc = &bink2f_ac_val1_vlc;
+            skip_vlc = &bink2f_ac_skip1_vlc;
+        } else {
+            val_vlc = &bink2f_ac_val0_vlc;
+            skip_vlc = &bink2f_ac_skip0_vlc;
+        }
+
+        next = 0;
+        idx  = 1;
+        while (idx < 64) {
+            val = get_vlc2(gb, val_vlc->table, val_vlc->bits, 1);
+            if (val < 0)
+                return AVERROR_INVALIDDATA;
+            if (val) {
+                if (val >= 4) {
+                    val -= 3;
+                    val = get_bits(gb, val) + (1 << val) + 2;
+                }
+                if (get_bits1(gb))
+                    val = -val;
+            }
+
+            ff_dlog(NULL, "    AC level = %d @ %d\n", val, get_bits_count(gb));
+            block[i][scan[idx]] = val * q * qmat[scan[idx]];
+            if (idx > 62)
+                break;
+            idx++;
+            next--;
+            if (next < 1) {
+                skip = get_vlc2(gb, skip_vlc->table, skip_vlc->bits, 1);
+                if (skip < 0)
+                    return AVERROR_INVALIDDATA;
+                next = bink2f_next_skips[skip];
+                skip = bink2f_skips[skip];
+                if (skip == 11)
+                    skip = get_bits(gb, 6);
+                ff_dlog(NULL, "    AC skip = %d @ %d\n", skip, get_bits_count(gb));
+                idx += skip;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static int bink2f_decode_intra_luma(Bink2Context *c,
+                                    float block[4][64],
+                                    unsigned *prev_cbp, int *prev_q,
+                                    uint8_t *dst, int stride,
+                                    int flags)
+{
+    GetBitContext *gb = &c->gb;
+    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
+    int q, dq, ret;
+    unsigned cbp;
+
+    *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp);
+    //ff_dlog(NULL, "  Y CBP %X @ %d\n", cbp, get_bits_count(gb));
+    dq = bink2f_decode_delta_q(gb);
+    q = *prev_q + dq;
+    //ff_dlog(NULL, "  Y q %d @ %d\n", q, get_bits_count(gb));
+    if (q < 0 || q >= 16)
+        return AVERROR_INVALIDDATA;
+    *prev_q = q;
+
+    bink2f_decode_dc(c, gb, dc, 1, q, 0, 2047, flags);
+
+    for (int i = 0; i < 4; i++) {
+        ret = bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (4 * i),
+                               bink2f_ac_quant[q], bink2f_luma_intra_qmat);
+        if (ret < 0)
+            return ret;
+
+        for (int j = 0; j < 4; j++) {
+            block[j][0] = dc[i * 4 + j] * 0.125f;
+            bink2f_idct_put(dst + (luma_repos[i*4+j]&3) * 8 +
+                            (luma_repos[i*4+j]>>2) * 8 * stride, stride, block[j]);
+        }
+    }
+
+    return 0;
+}
+
+static int bink2f_decode_intra_chroma(Bink2Context *c,
+                                      float block[4][64],
+                                      unsigned *prev_cbp, int *prev_q,
+                                      uint8_t *dst, int stride,
+                                      int flags)
+{
+    GetBitContext *gb = &c->gb;
+    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
+    int q, dq, ret;
+    unsigned cbp;
+
+    *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp);
+    //ff_dlog(NULL, "  C CBP %X @ %d\n", cbp, get_bits_count(gb));
+    dq = bink2f_decode_delta_q(gb);
+    q = *prev_q + dq;
+    //ff_dlog(NULL, "  C q %d @ %d\n", q, get_bits_count(gb));
+    if (q < 0 || q >= 16)
+        return AVERROR_INVALIDDATA;
+    *prev_q = q;
+
+    bink2f_decode_dc(c, gb, dc, 0, q, 0, 2047, flags);
+
+    ret = bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp,
+                           bink2f_ac_quant[q], bink2f_chroma_qmat);
+    if (ret < 0)
+        return ret;
+
+    for (int j = 0; j < 4; j++) {
+        block[j][0] = dc[j] * 0.125f;
+        bink2f_idct_put(dst + (j & 1) * 8 + (j >> 1) * 8 * stride, stride, block[j]);
+    }
+
+    return 0;
+}
+
+static int bink2f_decode_inter_luma(Bink2Context *c,
+                                    float block[4][64],
+                                    unsigned *prev_cbp, int *prev_q,
+                                    uint8_t *dst, int stride,
+                                    int flags)
+{
+    GetBitContext *gb = &c->gb;
+    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
+    unsigned cbp;
+    int q, dq;
+
+    *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp);
+    dq = bink2f_decode_delta_q(gb);
+    q = *prev_q + dq;
+    if (q < 0 || q >= 16)
+        return AVERROR_INVALIDDATA;
+    *prev_q = q;
+
+    bink2f_decode_dc(c, gb, dc, 1, q, -1023, 1023, 0xA8);
+
+    for (int i = 0; i < 4; i++) {
+        bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (i * 4),
+                         bink2f_ac_quant[q], bink2f_luma_inter_qmat);
+        for (int j = 0; j < 4; j++) {
+            block[j][0] = dc[i * 4 + j] * 0.125f;
+            bink2f_idct_add(dst + (luma_repos[i*4+j]&3) * 8 +
+                            (luma_repos[i*4+j]>>2) * 8 * stride, stride,
+                            block[j]);
+        }
+    }
+
+    return 0;
+}
+
+static int bink2f_decode_inter_chroma(Bink2Context *c,
+                                      float block[4][64],
+                                      unsigned *prev_cbp, int *prev_q,
+                                      uint8_t *dst, int stride,
+                                      int flags)
+{
+    GetBitContext *gb = &c->gb;
+    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
+    unsigned cbp;
+    int q, dq;
+
+    *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp);
+    dq = bink2f_decode_delta_q(gb);
+    q = *prev_q + dq;
+    if (q < 0 || q >= 16)
+        return AVERROR_INVALIDDATA;
+    *prev_q = q;
+
+    bink2f_decode_dc(c, gb, dc, 0, q, -1023, 1023, 0xA8);
+
+    bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp,
+                     bink2f_ac_quant[q], bink2f_chroma_qmat);
+
+    for (int i = 0; i < 4; i++) {
+        block[i][0] = dc[i] * 0.125f;
+        bink2f_idct_add(dst + (i & 1) * 8 + (i >> 1) * 8 * stride, stride,
+                        block[i]);
+    }
+
+    return 0;
+}
+
+static void bink2f_predict_mv(Bink2Context *c, int x, int y, int flags, MVectors mv)
+{
+    MVectors *c_mv = &c->current_mv[c->mb_pos].mv;
+    MVectors *l_mv = &c->current_mv[FFMAX(c->mb_pos - 1, 0)].mv;
+    MVectors *lt_mv = &c->prev_mv[FFMAX(c->mb_pos - 1, 0)].mv;
+    MVectors *t_mv = &c->prev_mv[c->mb_pos].mv;
+
+    if (!(flags & 0x80)) {
+        if (flags & 0x20) {
+            c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]);
+            c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]);
+            c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]);
+            c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]);
+            c_mv->v[2][0] = mv.v[2][0] + mid_pred(t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]);
+            c_mv->v[2][1] = mv.v[2][1] + mid_pred(t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]);
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]);
+        } else {
+            c_mv->v[0][0] = mv.v[0][0] + mid_pred(lt_mv->v[3][0], t_mv->v[2][0], l_mv->v[1][0]);
+            c_mv->v[0][1] = mv.v[0][1] + mid_pred(lt_mv->v[3][1], t_mv->v[2][1], l_mv->v[1][1]);
+            c_mv->v[1][0] = mv.v[1][0] + mid_pred( t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]);
+            c_mv->v[1][1] = mv.v[1][1] + mid_pred( t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]);
+            c_mv->v[2][0] = mv.v[2][0] + mid_pred( t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]);
+            c_mv->v[2][1] = mv.v[2][1] + mid_pred( t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]);
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred( c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred( c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]);
+        }
+    } else {
+        if (flags & 0x20) {
+            c_mv->v[0][0] = mv.v[0][0];
+            c_mv->v[0][1] = mv.v[0][1];
+            c_mv->v[1][0] = mv.v[1][0];
+            c_mv->v[1][1] = mv.v[1][1];
+            c_mv->v[2][0] = mv.v[2][0];
+            c_mv->v[2][1] = mv.v[2][1];
+            c_mv->v[3][0] = mv.v[3][0];
+            c_mv->v[3][1] = mv.v[3][1];
+        } else {
+            c_mv->v[0][0] = mv.v[0][0] + mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]);
+            c_mv->v[0][1] = mv.v[0][1] + mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]);
+            c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0], c_mv->v[0][0]);
+            c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1], c_mv->v[0][1]);
+            c_mv->v[1][0] = mv.v[1][0] + mid_pred(l_mv->v[1][0], c_mv->v[0][0], c_mv->v[2][0]);
+            c_mv->v[1][1] = mv.v[1][1] + mid_pred(l_mv->v[1][1], c_mv->v[0][1], c_mv->v[2][1]);
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]);
+        }
+    }
+
+    for (int i = 0; i < 4; i++)
+        ff_dlog(NULL, "pred MV %dx%d %d: %dx%d\n", x, y, i, c_mv->v[i][0], c_mv->v[i][1]);
+}
+
+#define CH1FILTER(src)    ((6*(src)[0] + 2*(src)[1] + 4) >> 3)
+#define CH2FILTER(src)    ((  (src)[0] +   (src)[1] + 1) >> 1)
+#define CH3FILTER(src)    ((2*(src)[0] + 6*(src)[1] + 4) >> 3)
+
+#define CV1FILTER(src, i)    ((6*(src)[0] + 2*(src)[i] + 4) >> 3)
+#define CV2FILTER(src, i)    ((  (src)[0] +   (src)[i] + 1) >> 1)
+#define CV3FILTER(src, i)    ((2*(src)[0] + 6*(src)[i] + 4) >> 3)
+
+static void bink2f_c_mc(Bink2Context *c, int x, int y,
+                        uint8_t *dst, int stride,
+                        uint8_t *src, int sstride,
+                        int width, int height,
+                        int mv_x, int mv_y,
+                        int mode)
+{
+    uint8_t *msrc;
+    uint8_t temp[8*9];
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    //ff_dlog(NULL, "CHROMA %d: %dx%d | %dx%d\n", mode, x, y, mv_x, mv_y);
+    switch (mode) {
+    case 0:
+        copy_block8(dst, msrc, stride, sstride, 8);
+        break;
+    case 1:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CH1FILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+        break;
+    case 2:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CH2FILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+        break;
+    case 3:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CH3FILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+        break;
+    case 4:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i*stride] = av_clip_uint8(CV1FILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+        break;
+    case 5:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 6:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 7:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 8:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i*stride] = av_clip_uint8(CV2FILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+        break;
+    case 9:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 10:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 11:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 12:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i*stride] = av_clip_uint8(CV3FILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+        break;
+    case 13:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 14:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 15:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    }
+}
+
+#define LHFILTER(src)    ((((src)[0]+(src)[1])*19 >> 1)-((src)[-1]+(src)[2  ])*2+(((src)[-2  ]+(src)[3  ])>>1)+8>>4)
+#define LVFILTER(src, i) ((((src)[0]+(src)[i])*19 >> 1)-((src)[-i]+(src)[2*i])*2+(((src)[-2*i]+(src)[3*i])>>1)+8>>4)
+
+static void bink2f_y_mc(Bink2Context *c, int x, int y,
+                        uint8_t *dst, int stride,
+                        uint8_t *src, int sstride,
+                        int width, int height,
+                        int mv_x, int mv_y, int mode)
+{
+    uint8_t *msrc;
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    //ff_dlog(NULL, "LUMA %d: %dx%d | %dx%d\n", mode, x, y, mv_x, mv_y);
+    if (mode == 0) {
+        copy_block16(dst, msrc, stride, sstride, 16);
+    } else if (mode == 1) {
+        for (int j = 0; j < 16; j++) {
+            for (int i = 0; i < 16; i++)
+                dst[i] = av_clip_uint8(LHFILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+    } else if (mode == 2) {
+        for (int j = 0; j < 16; j++) {
+            for (int i = 0; i < 16; i++)
+                dst[i*stride] = av_clip_uint8(LVFILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+    } else if (mode == 3) {
+        uint8_t temp[21 * 16];
+
+        msrc -= 2 * sstride;
+        for (int i = 0; i < 21; i++) {
+            for (int j = 0; j < 16; j++)
+                temp[i*16+j] = av_clip_uint8(LHFILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 16; j++) {
+            for (int i = 0; i < 16; i++)
+                dst[i] = av_clip_uint8(LVFILTER(temp+(j+2)*16+i, 16));
+            dst  += stride;
+        }
+    }
+}
+
+static int bink2f_mcompensate_chroma(Bink2Context *c, int x, int y,
+                                     uint8_t *dst, int stride,
+                                     uint8_t *src, int sstride,
+                                     int width, int height)
+{
+    MVectors *mv = &c->current_mv[c->mb_pos].mv;
+    int mv_x, mv_y, mode;
+
+    mv_x  = (mv->v[0][0] >> 2) + x;
+    mv_y  = (mv->v[0][1] >> 2) + y;
+    mode  =  mv->v[0][0] & 3;
+    mode |= (mv->v[0][1] & 3) << 2;
+    bink2f_c_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x = (mv->v[1][0] >> 2) + x + 8;
+    mv_y = (mv->v[1][1] >> 2) + y;
+    mode  =  mv->v[1][0] & 3;
+    mode |= (mv->v[1][1] & 3) << 2;
+    bink2f_c_mc(c, x, y, dst + x + 8, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x = (mv->v[2][0] >> 2) + x;
+    mv_y = (mv->v[2][1] >> 2) + y + 8;
+    mode  =  mv->v[2][0] & 3;
+    mode |= (mv->v[2][1] & 3) << 2;
+    bink2f_c_mc(c, x, y, dst + x + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x = (mv->v[3][0] >> 2) + x + 8;
+    mv_y = (mv->v[3][1] >> 2) + y + 8;
+    mode  =  mv->v[3][0] & 3;
+    mode |= (mv->v[3][1] & 3) << 2;
+    bink2f_c_mc(c, x, y, dst + x + 8 + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    return 0;
+}
+
+static float bink2f_average_block(uint8_t *src, int stride)
+{
+    int sum = 0;
+
+    for (int i = 0; i < 8; i++) {
+        int avg_a = (src[i+0*stride] + src[i+1*stride] + 1) >> 1;
+        int avg_b = (src[i+2*stride] + src[i+3*stride] + 1) >> 1;
+        int avg_c = (src[i+4*stride] + src[i+5*stride] + 1) >> 1;
+        int avg_d = (src[i+6*stride] + src[i+7*stride] + 1) >> 1;
+        int avg_e = (avg_a + avg_b + 1) >> 1;
+        int avg_f = (avg_c + avg_d + 1) >> 1;
+        int avg_g = (avg_e + avg_f + 1) >> 1;
+        sum += avg_g;
+    }
+
+    return sum;
+}
+
+static void bink2f_average_chroma(Bink2Context *c, int x, int y,
+                                  uint8_t *src, int stride,
+                                  float *dc)
+{
+    for (int i = 0; i < 4; i++) {
+        int X = i & 1;
+        int Y = i >> 1;
+        dc[i] = bink2f_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride);
+    }
+}
+
+static void bink2f_average_luma(Bink2Context *c, int x, int y,
+                                uint8_t *src, int stride,
+                                float *dc)
+{
+    for (int i = 0; i < 16; i++) {
+        int I = luma_repos[i];
+        int X = I & 3;
+        int Y = I >> 2;
+        dc[i] = bink2f_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride);
+        ff_dlog(NULL, "   DC avg %d:%f\n", i, dc[i]);
+    }
+}
+
+static int bink2f_mcompensate_luma(Bink2Context *c, int x, int y,
+                                   uint8_t *dst, int stride,
+                                   uint8_t *src, int sstride,
+                                   int width, int height)
+{
+    MVectors *mv = &c->current_mv[c->mb_pos].mv;
+    int mv_x, mv_y, mode;
+
+    mv_x  = (mv->v[0][0] >> 1) + x;
+    mv_y  = (mv->v[0][1] >> 1) + y;
+    mode  =  mv->v[0][0] & 1;
+    mode |= (mv->v[0][1] & 1) << 1;
+    bink2f_y_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x  = (mv->v[1][0] >> 1) + x + 16;
+    mv_y  = (mv->v[1][1] >> 1) + y;
+    mode  =  mv->v[1][0] & 1;
+    mode |= (mv->v[1][1] & 1) << 1;
+    bink2f_y_mc(c, x, y, dst + x + 16, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x  = (mv->v[2][0] >> 1) + x;
+    mv_y  = (mv->v[2][1] >> 1) + y + 16;
+    mode  =  mv->v[2][0] & 1;
+    mode |= (mv->v[2][1] & 1) << 1;
+    bink2f_y_mc(c, x, y, dst + x + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x  = (mv->v[3][0] >> 1) + x + 16;
+    mv_y  = (mv->v[3][1] >> 1) + y + 16;
+    mode  =  mv->v[3][0] & 1;
+    mode |= (mv->v[3][1] & 1) << 1;
+    bink2f_y_mc(c, x, y, dst + x + 16 + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    return 0;
+}
+
+static int bink2f_decode_mv(Bink2Context *c, GetBitContext *gb, int x, int y,
+                            int flags, MVectors *mv)
+{
+    for (int i = 0; i < 2; i++) {
+        int val = 0, bits = get_bits(gb, 3);
+
+        if (bits == 7)
+            bits += get_bits(gb, 2);
+        if (bits) {
+            for (int j = 0; j < 4; j++)
+                mv->v[j][i] = get_bits(gb, bits);
+            for (int j = 0; j < 4; j++)
+                if (mv->v[j][i] && get_bits1(gb))
+                    mv->v[j][i] = -mv->v[j][i];
+        }
+
+        if ((flags & 0x80) && (flags & 0x20)) {
+            val = get_bits(gb, 5) * 16;
+            if (val && get_bits1(gb))
+                val = -val;
+        }
+
+        mv->v[0][i] += val;
+        mv->v[1][i] += val;
+        mv->v[2][i] += val;
+        mv->v[3][i] += val;
+        //ff_dlog(NULL, "MV val %d\n", val);
+    }
+
+    //for (int i = 0; i < 4; i++)
+        //ff_dlog(NULL, "MV %dx%d %d: %dx%d\n", x, y, i, mv->v[i][0], mv->v[i][1]);
+
+    return 0;
+}
+
+static int bink2f_decode_slice(Bink2Context *c,
+                               uint8_t *dst[4], int stride[4],
+                               uint8_t *src[4], int sstride[4],
+                               int is_kf, int start, int end)
+{
+    GetBitContext *gb = &c->gb;
+    int w = c->avctx->width;
+    int h = c->avctx->height;
+    int flags, ret = 0;
+
+    memset(c->prev_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_mv));
+
+    for (int y = start; y < end; y += 32) {
+        unsigned y_cbp_intra = 0, u_cbp_intra = 0, v_cbp_intra = 0, a_cbp_intra = 0;
+        unsigned y_cbp_inter = 0, u_cbp_inter = 0, v_cbp_inter = 0, a_cbp_inter = 0;
+        int y_intra_q = 8, u_intra_q = 8, v_intra_q = 8, a_intra_q = 8;
+        int y_inter_q = 8, u_inter_q = 8, v_inter_q = 8, a_inter_q = 8;
+
+        memset(c->current_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_mv));
+
+        for (int x = 0; x < c->avctx->width; x += 32) {
+            MVectors mv = { 0 };
+            int type = is_kf ? INTRA_BLOCK : get_bits(gb, 2);
+
+            ff_dlog(NULL, " MB %d,%d\n", x/32, y/32);
+
+            c->mb_pos = x / 32;
+            c->current_dc[c->mb_pos].block_type = type;
+            flags = 0;
+            if (y == start)
+                flags |= 0x80;
+            if (!x)
+                flags |= 0x20;
+            if (x == 32)
+                flags |= 0x200;
+            if (x + 32 >= c->avctx->width)
+                flags |= 0x40;
+
+            ff_dlog(NULL, " MB type %d @ %d\n", type, get_bits_count(gb));
+            switch (type) {
+            case INTRA_BLOCK:
+                if (!(flags & 0xA0) && c->prev_dc[c->mb_pos - 1].block_type != INTRA_BLOCK) {
+                    bink2f_average_luma  (c, x  -32, -32, dst[0], stride[0], c->prev_dc[c->mb_pos - 1].dc[0]);
+                    bink2f_average_chroma(c, x/2-16, -16, dst[2], stride[2], c->prev_dc[c->mb_pos - 1].dc[1]);
+                    bink2f_average_chroma(c, x/2-16, -16, dst[1], stride[1], c->prev_dc[c->mb_pos - 1].dc[2]);
+                }
+                if (!(flags & 0x20) && c->current_dc[c->mb_pos - 1].block_type != INTRA_BLOCK) {
+                    bink2f_average_luma  (c, x  -32, 0, dst[0], stride[0], c->current_dc[c->mb_pos - 1].dc[0]);
+                    bink2f_average_chroma(c, x/2-16, 0, dst[2], stride[2], c->current_dc[c->mb_pos - 1].dc[1]);
+                    bink2f_average_chroma(c, x/2-16, 0, dst[1], stride[1], c->current_dc[c->mb_pos - 1].dc[2]);
+                }
+                if ((flags & 0x20) && !(flags & 0x80) && c->prev_dc[c->mb_pos + 1].block_type != INTRA_BLOCK) {
+                    bink2f_average_luma  (c, x  +32, -32, dst[0], stride[0], c->prev_dc[c->mb_pos + 1].dc[0]);
+                    bink2f_average_chroma(c, x/2+16, -16, dst[2], stride[2], c->prev_dc[c->mb_pos + 1].dc[1]);
+                    bink2f_average_chroma(c, x/2+16, -16, dst[1], stride[1], c->prev_dc[c->mb_pos + 1].dc[2]);
+                }
+                if (!(flags & 0x80) && c->prev_dc[c->mb_pos].block_type != INTRA_BLOCK) {
+                    bink2f_average_luma  (c, x,   -32, dst[0], stride[0], c->prev_dc[c->mb_pos].dc[0]);
+                    bink2f_average_chroma(c, x/2, -16, dst[2], stride[2], c->prev_dc[c->mb_pos].dc[1]);
+                    bink2f_average_chroma(c, x/2, -16, dst[1], stride[1], c->prev_dc[c->mb_pos].dc[2]);
+                }
+
+                bink2f_predict_mv(c, x, y, flags, mv);
+                c->comp = 0;
+                ret = bink2f_decode_intra_luma(c, c->block, &y_cbp_intra, &y_intra_q,
+                                               dst[0] + x, stride[0], flags);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 1;
+                ret = bink2f_decode_intra_chroma(c, c->block, &u_cbp_intra, &u_intra_q,
+                                                 dst[2] + x/2, stride[2], flags);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 2;
+                ret = bink2f_decode_intra_chroma(c, c->block, &v_cbp_intra, &v_intra_q,
+                                                 dst[1] + x/2, stride[1], flags);
+                if (ret < 0)
+                    goto fail;
+                if (c->has_alpha) {
+                    c->comp = 3;
+                    ret = bink2f_decode_intra_luma(c, c->block, &a_cbp_intra, &a_intra_q,
+                                                   dst[3] + x, stride[3], flags);
+                    if (ret < 0)
+                        goto fail;
+                }
+                break;
+            case SKIP_BLOCK:
+                copy_block16(dst[0] + x, src[0] + x + sstride[0] * y,
+                             stride[0], sstride[0], 32);
+                copy_block16(dst[0] + x + 16, src[0] + x + 16 + sstride[0] * y,
+                             stride[0], sstride[0], 32);
+                copy_block16(dst[1] + (x/2), src[1] + (x/2) + sstride[1] * (y/2),
+                             stride[1], sstride[1], 16);
+                copy_block16(dst[2] + (x/2), src[2] + (x/2) + sstride[2] * (y/2),
+                             stride[2], sstride[2], 16);
+                if (c->has_alpha) {
+                    copy_block16(dst[3] + x, src[3] + x + sstride[3] * y,
+                                 stride[3], sstride[3], 32);
+                    copy_block16(dst[3] + x + 16, src[3] + x + 16 + sstride[3] * y,
+                                 stride[3], sstride[3], 32);
+                }
+                break;
+            case MOTION_BLOCK:
+                bink2f_decode_mv(c, gb, x, y, flags, &mv);
+                bink2f_predict_mv(c, x, y, flags, mv);
+                c->comp = 0;
+                ret = bink2f_mcompensate_luma(c, x, y,
+                                              dst[0], stride[0],
+                                              src[0], sstride[0],
+                                              w, h);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 1;
+                ret = bink2f_mcompensate_chroma(c, x/2, y/2,
+                                                dst[2], stride[2],
+                                                src[2], sstride[2],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 2;
+                ret = bink2f_mcompensate_chroma(c, x/2, y/2,
+                                                dst[1], stride[1],
+                                                src[1], sstride[1],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                break;
+            case RESIDUE_BLOCK:
+                bink2f_decode_mv(c, gb, x, y, flags, &mv);
+                bink2f_predict_mv(c, x, y, flags, mv);
+                ret = bink2f_mcompensate_luma(c, x, y,
+                                              dst[0], stride[0],
+                                              src[0], sstride[0],
+                                              w, h);
+                if (ret < 0)
+                    goto fail;
+                ret = bink2f_mcompensate_chroma(c, x/2, y/2,
+                                                dst[2], stride[2],
+                                                src[2], sstride[2],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                ret = bink2f_mcompensate_chroma(c, x/2, y/2,
+                                                dst[1], stride[1],
+                                                src[1], sstride[1],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 0;
+                ret = bink2f_decode_inter_luma(c, c->block, &y_cbp_inter, &y_inter_q,
+                                               dst[0] + x, stride[0], flags);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 1;
+                ret = bink2f_decode_inter_chroma(c, c->block, &u_cbp_inter, &u_inter_q,
+                                                 dst[2] + x/2, stride[2], flags);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 2;
+                ret = bink2f_decode_inter_chroma(c, c->block, &v_cbp_inter, &v_inter_q,
+                                                 dst[1] + x/2, stride[1], flags);
+                if (ret < 0)
+                    goto fail;
+                if (c->has_alpha) {
+                    c->comp = 3;
+                    ret = bink2f_decode_inter_luma(c, c->block, &a_cbp_inter, &a_inter_q,
+                                                   dst[3] + x, stride[3], flags);
+                    if (ret < 0)
+                        goto fail;
+                }
+                break;
+            default:
+                return AVERROR_INVALIDDATA;
+            }
+        }
+
+        dst[0] += stride[0] * 32;
+        dst[1] += stride[1] * 16;
+        dst[2] += stride[2] * 16;
+        dst[3] += stride[3] * 32;
+
+        FFSWAP(MVPredict *, c->current_mv, c->prev_mv);
+        FFSWAP(DCPredict *, c->current_dc, c->prev_dc);
+    }
+fail:
+    emms_c();
+
+    return ret;
+}
diff --git a/libavcodec/bink2g.c b/libavcodec/bink2g.c
new file mode 100644
index 0000000000..3f8d14e6eb
--- /dev/null
+++ b/libavcodec/bink2g.c
@@ -0,0 +1,1342 @@ 
+/*
+ * Bink video 2 decoder
+ * Copyright (c) 2014 Konstantin Shishkov
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * 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
+ */
+
+static inline void bink2g_idct_1d(int16_t *blk, int step, int shift)
+{
+#define idct_mul_a(val) ((val) + ((val) >> 2))
+#define idct_mul_b(val) ((val) >> 1)
+#define idct_mul_c(val) ((val) - ((val) >> 2) - ((val) >> 4))
+#define idct_mul_d(val) ((val) + ((val) >> 2) - ((val) >> 4))
+#define idct_mul_e(val) ((val) >> 2)
+    int tmp00 =  blk[3*step] + blk[5*step];
+    int tmp01 =  blk[3*step] - blk[5*step];
+    int tmp02 =  idct_mul_a(blk[2*step]) + idct_mul_b(blk[6*step]);
+    int tmp03 =  idct_mul_b(blk[2*step]) - idct_mul_a(blk[6*step]);
+    int tmp0  = (blk[0*step] + blk[4*step]) + tmp02;
+    int tmp1  = (blk[0*step] + blk[4*step]) - tmp02;
+    int tmp2  =  blk[0*step] - blk[4*step];
+    int tmp3  =  blk[1*step] + tmp00;
+    int tmp4  =  blk[1*step] - tmp00;
+    int tmp5  =  tmp01 + blk[7*step];
+    int tmp6  =  tmp01 - blk[7*step];
+    int tmp7  =  tmp4 + idct_mul_c(tmp6);
+    int tmp8  =  idct_mul_c(tmp4) - tmp6;
+    int tmp9  =  idct_mul_d(tmp3) + idct_mul_e(tmp5);
+    int tmp10 =  idct_mul_e(tmp3) - idct_mul_d(tmp5);
+    int tmp11 =  tmp2 + tmp03;
+    int tmp12 =  tmp2 - tmp03;
+
+    blk[0*step] = (tmp0  + tmp9)  >> shift;
+    blk[1*step] = (tmp11 + tmp7)  >> shift;
+    blk[2*step] = (tmp12 + tmp8)  >> shift;
+    blk[3*step] = (tmp1  + tmp10) >> shift;
+    blk[4*step] = (tmp1  - tmp10) >> shift;
+    blk[5*step] = (tmp12 - tmp8)  >> shift;
+    blk[6*step] = (tmp11 - tmp7)  >> shift;
+    blk[7*step] = (tmp0  - tmp9)  >> shift;
+}
+
+static void bink2g_idct_put(uint8_t *dst, int stride, int16_t *block)
+{
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i, 8, 0);
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i * 8, 1, 6);
+    for (int i = 0; i < 8; i++) {
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(block[j * 8 + i]);
+        dst += stride;
+    }
+}
+
+static void bink2g_idct_add(uint8_t *dst, int stride, int16_t *block)
+{
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i, 8, 0);
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i * 8, 1, 6);
+    for (int i = 0; i < 8; i++) {
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(dst[j] + block[j * 8 + i]);
+        dst += stride;
+    }
+}
+
+static int bink2g_get_type(GetBitContext *gb, int *lru)
+{
+    int val;
+
+    ff_dlog(NULL, " type show %X @ %d\n", show_bits(gb, 4), get_bits_count(gb));
+    switch (get_unary(gb, 1, 3)) {
+    case 0:
+        val = lru[0];
+        break;
+    case 1:
+        val = lru[1];
+        FFSWAP(int, lru[0], lru[1]);
+        break;
+    case 2:
+        val = lru[3];
+        FFSWAP(int, lru[2], lru[3]);
+        break;
+    case 3:
+        val = lru[2];
+        FFSWAP(int, lru[1], lru[2]);
+        break;
+    }
+
+    return val;
+}
+
+static int bink2g_decode_dq(GetBitContext *gb)
+{
+    int dq = get_unary(gb, 1, 4);
+
+    if (dq == 3)
+        dq += get_bits1(gb);
+    else if (dq == 4)
+        dq += get_bits(gb, 5) + 1;
+    if (dq && get_bits1(gb))
+        dq = -dq;
+
+    return dq;
+}
+
+typedef uint8_t byte;
+typedef int8_t sbyte;
+typedef unsigned uint;
+
+static void bink2g_get_cbp_flags(GetBitContext *gb, int offset, int size, uint8_t *dst)
+{
+    unsigned flag;
+    int i, j;
+    byte bVar4;
+    sbyte sVar5;
+    byte bVar6;
+    int iVar7;
+    int uVar8;
+    int uVar9;
+    int local_20;
+    int local_1c;
+    int v;
+    int temp;
+
+    v = 0;
+    if (get_bits1(gb) == 0) {
+        for (j = 0; j < size >> 3; j++)
+            dst[j] = get_bits(gb, 8);
+        dst[j] = get_bitsz(gb, size & 7);
+    } else {
+        flag = 0;
+        local_1c = 0;
+        i = size;
+        if (size <= 0)
+            return;
+        do {
+            bVar4 = (byte)offset;
+            if (get_bits1(gb) == 0) {
+                if (local_1c == 3) {
+                    flag ^= 1;
+                } else {
+                    flag = get_bits1(gb);
+                }
+                local_1c = 2;
+                temp = i - 1;
+                bVar6 = (byte)(offset + 1);
+                if (temp < 4) {
+                    uVar8 = get_bitsz(gb, temp);
+                    uVar8 <<= bVar6 & 0x1f;
+                    i = 0;
+                    offset = offset + 1 + temp;
+                } else {
+                    uVar8 = (get_bits(gb, 4)) << (bVar6 & 0x1f);
+                    offset += 5;
+                    i -= 5;
+                }
+                v = v | flag << (bVar4 & 0x1f) | uVar8;
+                if (7 < offset) {
+                    *dst = v;
+                    dst++;
+                    v >>= 8;
+                    offset -= 8;
+                }
+            } else {
+                uVar9 = 5;
+                if (i < 4) {
+                    uVar9 = 2;
+                } else {
+                    if (i < 0x10)
+                        uVar9 = 4;
+                }
+                local_20 = uVar9 + 1;
+                if (local_1c == 3) {
+                    flag ^= 1;
+                }
+                else {
+                    local_20 = uVar9 + 2;
+                    flag = get_bits1(gb);
+                }
+                if (i < local_20) {
+                    local_20 = i;
+                }
+                i -= local_20;
+                if (i > 0) {
+                    sVar5 = (sbyte)uVar9;
+                    temp = get_bits(gb, sVar5);
+                    i -= temp;
+                    local_20 += temp;
+                    local_1c = 3;
+                    if (temp == (1 << sVar5) - 1U) {
+                        local_1c = 1;
+                    }
+                }
+                temp = (int)(flag << 0x1f) >> 0x1f & 0xff;
+                if (8 < local_20) {
+                    iVar7 = (local_20 - 9 >> 3) + 1;
+                    do {
+                        v |= temp << (bVar4 & 0x1f);
+                        *dst = v;
+                        dst++;
+                        v >>= 8;
+                        local_20 -= 8;
+                        iVar7 += -1;
+                    } while (iVar7 != 0);
+                }
+                if (local_20 > 0) {
+                    offset += local_20;
+                    v |= ((1 << ((byte)local_20 & 0x1f)) - 1U & temp) << (bVar4 & 0x1f);
+                    if (7 < offset) {
+                        *dst = v;
+                        dst++;
+                        v >>= 8;
+                        offset -= 8;
+                    }
+                }
+            }
+        } while (i > 0);
+
+        if (offset != 0)
+            *dst = v;
+    }
+}
+
+static unsigned bink2g_decode_cbp_luma(Bink2Context *c,
+                                       GetBitContext *gb, unsigned prev_cbp)
+{
+    unsigned ones = 0, cbp, mask;
+
+    for (int i = 0; i < 16; i++) {
+        if (prev_cbp & (1 << i))
+            ones += 1;
+    }
+
+    cbp = 0;
+    mask = 0;
+    if (ones > 7) {
+        ones = 16 - ones;
+        mask = 0xFFFF;
+    }
+
+    if (get_bits1(gb) == 0) {
+        if (ones < 4) {
+            for (int j = 0; j < 16; j += 4)
+                if (!get_bits1(gb))
+                    cbp |= get_bits(gb, 4) << j;
+        } else {
+            cbp = get_bits(gb, 16);
+        }
+    }
+
+    cbp ^= mask;
+    if (!(c->frame_flags & 0x40000) || cbp) {
+        if (get_bits1(gb))
+            cbp = cbp | cbp << 16;
+    }
+
+    return cbp;
+}
+
+static unsigned bink2g_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp)
+{
+    unsigned cbp;
+
+    cbp = prev_cbp & 0xF0000 | bink2g_chroma_cbp_pat[prev_cbp & 0xF];
+    if (get_bits1(gb) == 0) {
+        cbp = get_bits(gb, 4);
+        if (get_bits1(gb))
+            cbp |= cbp << 16;
+    }
+
+    return cbp;
+}
+
+static void bink2g_predict_dc(Bink2Context *c,
+                              int is_luma, int mindc, int maxdc,
+                              int flags, int tdc[16])
+{
+    int *LTdc = c->prev_idc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
+    int *Tdc = c->prev_idc[c->mb_pos].dc[c->comp];
+    int *Ldc = c->current_idc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
+    int *dc = c->current_idc[c->mb_pos].dc[c->comp];
+
+    if (is_luma && (flags & 0x20) && (flags & 0x80)) {
+        dc[0]  = av_clip((mindc < 0 ? 0 : 1024) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clip(dc[0] + tdc[1], mindc, maxdc);
+        dc[2]  = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clip(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clip(dc[4] + tdc[5], mindc, maxdc);
+        dc[6]  = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clip(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clip(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma && (flags & 0x80)) {
+        dc[0]  = av_clip(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clip(dc[0] + tdc[1], mindc, maxdc);
+        dc[2]  = av_clip(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clip(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clip(dc[4] + tdc[5], mindc, maxdc);
+        dc[6]  = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clip(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clip(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma && (flags & 0x20)) {
+        dc[0]  = av_clip(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clip(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc);
+        dc[2]  = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clip(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clip(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc);
+        dc[6]  = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clip(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clip(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma) {
+        dc[0]  = av_clip(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clip(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc);
+        dc[2]  = av_clip(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clip(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clip(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc);
+        dc[6]  = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clip(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clip(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) {
+        dc[0] = av_clip((mindc < 0 ? 0 : 1024) + tdc[0], mindc, maxdc);
+        dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc);
+        dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x80)) {
+        dc[0] = av_clip(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc);
+        dc[2] = av_clip(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x20)) {
+        dc[0] = av_clip(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clip(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc);
+        dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma) {
+        dc[0] = av_clip(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clip(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc);
+        dc[2] = av_clip(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    }
+}
+
+static void bink2g_decode_dc(Bink2Context *c, GetBitContext *gb, int *dc,
+                             int is_luma, int q, int mindc, int maxdc,
+                             int flags)
+{
+    const int num_dc = is_luma ? 16 : 4;
+    int tdc[16];
+    int pat;
+
+    q = FFMAX(q, 8);
+    pat = bink2g_dc_pat[q];
+
+    memset(tdc, 0, sizeof(tdc));
+
+    if (get_bits1(gb)) {
+        for (int i = 0; i < num_dc; i++) {
+            int cnt = get_unary(gb, 0, 12);
+
+            if (cnt > 3)
+                cnt = (1 << (cnt - 3)) + get_bits(gb, cnt - 3) + 2;
+            if (cnt && get_bits1(gb))
+                cnt = -cnt;
+            tdc[i] = (cnt * pat + 0x200) >> 10;
+            //ff_dlog(NULL, "  dc = %d @ %d\n", cnt, get_bits_count(gb));
+            //ff_dlog(NULL, "  tdc = %d @ %d\n", tdc[i], get_bits_count(gb));
+        }
+    }
+
+    bink2g_predict_dc(c, is_luma, mindc, maxdc, flags, tdc);
+}
+
+static int bink2g_decode_ac(GetBitContext *gb, const uint8_t scan[64],
+                            int16_t block[4][64], unsigned cbp,
+                            int q, const uint16_t qmat[4][64])
+{
+    int idx, next, val, skip;
+    VLC *skip_vlc;
+
+    for (int i = 0; i < 4; i++)
+        memset(block[i], 0, sizeof(int16_t) * 64);
+
+    if ((cbp & 0xf) == 0)
+        return 0;
+
+    skip_vlc = &bink2g_ac_skip0_vlc;
+    if (cbp & 0xffff0000)
+        skip_vlc = &bink2g_ac_skip1_vlc;
+
+    for (int i = 0; i < 4; i++, cbp >>= 1) {
+        if (!(cbp & 1))
+            continue;
+
+        //ff_dlog(NULL, "  block %d\n", i);
+        next = 0;
+        idx  = 1;
+        while (idx < 64) {
+            next--;
+            if (next < 1) {
+                skip = get_vlc2(gb, skip_vlc->table, skip_vlc->bits, 1);
+                //ff_dlog(NULL, "   AC skip sym %d @ %d\n", skip, get_bits_count(gb));
+                if (skip < 0)
+                    return AVERROR_INVALIDDATA;
+                next = bink2_next_skips[skip];
+                skip = bink2g_skips[skip];
+                if (skip == 11)
+                    skip = get_bits(gb, 6);
+                //ff_dlog(NULL, "   AC skip = %d + %d\n", skip, idx);
+                idx += skip;
+                if (idx >= 64)
+                    break;
+            }
+
+            val = get_unary(gb, 0, 12) + 1;
+            if (val > 3)
+                val = get_bits(gb, val - 3) + (1 << (val - 3)) + 2;
+            if (get_bits1(gb))
+                val = -val;
+            //ff_dlog(NULL, "   AC val = %d @ %d\n", val, get_bits_count(gb));
+            block[i][scan[idx]] = ((val * qmat[q & 3][scan[idx]] * (1 << (q >> 2))) + 64) >> 7;
+            //ff_dlog(NULL, "   AC val = %d @ %d\n", block[i][scan[idx]], get_bits_count(gb));
+            idx++;
+        }
+    }
+
+    return 0;
+}
+
+static int bink2g_decode_intra_luma(Bink2Context *c,
+                                    GetBitContext *gb, int16_t block[4][64],
+                                    unsigned *prev_cbp, int q,
+                                    BlockDSPContext *dsp, uint8_t *dst, int stride,
+                                    int flags)
+{
+    int *dc = c->current_idc[c->mb_pos].dc[c->comp];
+    unsigned cbp;
+    int ret;
+
+    *prev_cbp = cbp = bink2g_decode_cbp_luma(c, gb, *prev_cbp);
+    ff_dlog(NULL, "  intra Y CBP %X @ %d\n", cbp, get_bits_count(gb));
+
+    bink2g_decode_dc(c, gb, dc, 1, q, 0, 2047, flags);
+
+    for (int i = 0; i < 4; i++) {
+        ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp >> (4*i),
+                               q, bink2g_luma_intra_qmat);
+        if (ret < 0)
+            return ret;
+
+        for (int j = 0; j < 4; j++) {
+            block[j][0] = dc[i * 4 + j] * 8 + 32;
+            bink2g_idct_put(dst + (luma_repos[i * 4 + j] & 3) * 8 +
+                            (luma_repos[i * 4 + j] >> 2) * 8 * stride, stride, block[j]);
+        }
+    }
+
+    return 0;
+}
+
+static int bink2g_decode_intra_chroma(Bink2Context *c,
+                                      GetBitContext *gb, int16_t block[4][64],
+                                      unsigned *prev_cbp, int q,
+                                      BlockDSPContext *dsp, uint8_t *dst, int stride,
+                                      int flags)
+{
+    int *dc = c->current_idc[c->mb_pos].dc[c->comp];
+    unsigned cbp;
+    int ret;
+
+    *prev_cbp = cbp = bink2g_decode_cbp_chroma(gb, *prev_cbp);
+    ff_dlog(NULL, "  intra C CBP %X @ %d\n", cbp, get_bits_count(gb));
+
+    bink2g_decode_dc(c, gb, dc, 0, q, 0, 2047, flags);
+
+    ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp,
+                           q, bink2g_chroma_intra_qmat);
+    if (ret < 0)
+        return ret;
+
+    for (int j = 0; j < 4; j++) {
+        block[j][0] = dc[j] * 8 + 32;
+        bink2g_idct_put(dst + (j & 1) * 8 +
+                        (j >> 1) * 8 * stride, stride, block[j]);
+    }
+
+    return 0;
+}
+
+static int bink2g_decode_inter_luma(Bink2Context *c,
+                                    GetBitContext *gb, int16_t block[4][64],
+                                    unsigned *prev_cbp, int q,
+                                    BlockDSPContext *dsp, uint8_t *dst, int stride,
+                                    int flags)
+{
+    int *dc = c->current_idc[c->mb_pos].dc[c->comp];
+    unsigned cbp;
+    int ret;
+
+    *prev_cbp = cbp = bink2g_decode_cbp_luma(c, gb, *prev_cbp);
+    ff_dlog(NULL, "  inter Y CBP %X @ %d\n", cbp, get_bits_count(gb));
+
+    bink2g_decode_dc(c, gb, dc, 1, q, -1023, 1023, 0xA8);
+
+    for (int i = 0; i < 4; i++) {
+        ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp >> (4 * i),
+                               q, bink2g_inter_qmat);
+        if (ret < 0)
+            return ret;
+
+        for (int j = 0; j < 4; j++) {
+            block[j][0] = dc[i * 4 + j] * 8 + 32;
+            bink2g_idct_add(dst + (luma_repos[i * 4 + j] & 3) * 8 +
+                            (luma_repos[i * 4 + j] >> 2) * 8 * stride,
+                            stride, block[j]);
+        }
+    }
+
+    return 0;
+}
+
+static int bink2g_decode_inter_chroma(Bink2Context *c,
+                                      GetBitContext *gb, int16_t block[4][64],
+                                      unsigned *prev_cbp, int q,
+                                      BlockDSPContext *dsp, uint8_t *dst, int stride,
+                                      int flags)
+{
+    int *dc = c->current_idc[c->mb_pos].dc[c->comp];
+    unsigned cbp;
+    int ret;
+
+    *prev_cbp = cbp = bink2g_decode_cbp_chroma(gb, *prev_cbp);
+    ff_dlog(NULL, "  inter C CBP %X @ %d\n", cbp, get_bits_count(gb));
+
+    bink2g_decode_dc(c, gb, dc, 0, q, -1023, 1023, 0xA8);
+
+    ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp,
+                           q, bink2g_inter_qmat);
+    if (ret < 0)
+        return ret;
+
+    for (int j = 0; j < 4; j++) {
+        block[j][0] = dc[j] * 8 + 32;
+        bink2g_idct_add(dst + (j & 1) * 8 +
+                        (j >> 1) * 8 * stride, stride, block[j]);
+    }
+
+    return 0;
+}
+
+static void bink2g_predict_mv(Bink2Context *c, int x, int y, int flags, MVectors mv)
+{
+    MVectors *c_mv = &c->current_mv[c->mb_pos].mv;
+    MVectors *l_mv = &c->current_mv[FFMAX(c->mb_pos - 1, 0)].mv;
+    MVectors *lt_mv = &c->prev_mv[FFMAX(c->mb_pos - 1, 0)].mv;
+    MVectors *t_mv = &c->prev_mv[c->mb_pos].mv;
+
+    if (mv.nb_vectors == 1) {
+        if (flags & 0x80) {
+            if (!(flags & 0x20)) {
+                mv.v[0][0] += mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]);
+                mv.v[0][1] += mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]);
+            }
+        } else {
+            if (!(flags & 0x20)) {
+                mv.v[0][0] += mid_pred(lt_mv->v[3][0], t_mv->v[2][0], l_mv->v[1][0]);
+                mv.v[0][1] += mid_pred(lt_mv->v[3][1], t_mv->v[2][1], l_mv->v[1][1]);
+            } else {
+                mv.v[0][0] += mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]);
+                mv.v[0][1] += mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]);
+            }
+        }
+
+        c_mv->v[0][0] = mv.v[0][0];
+        c_mv->v[0][1] = mv.v[0][1];
+        c_mv->v[1][0] = mv.v[0][0];
+        c_mv->v[1][1] = mv.v[0][1];
+        c_mv->v[2][0] = mv.v[0][0];
+        c_mv->v[2][1] = mv.v[0][1];
+        c_mv->v[3][0] = mv.v[0][0];
+        c_mv->v[3][1] = mv.v[0][1];
+
+        ff_dlog(NULL, "  predicted MVs:");
+        for (int i = 0; i < 4; i++)
+            ff_dlog(NULL, " %d,%d", c_mv->v[i][0], c_mv->v[i][1]);
+        ff_dlog(NULL, "\n");
+        return;
+    }
+
+    if (!(flags & 0x80)) {
+        if (flags & 0x20) {
+            c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]);
+            c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]);
+            c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]);
+            c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]);
+            c_mv->v[2][0] = mv.v[2][0] + mid_pred(t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]);
+            c_mv->v[2][1] = mv.v[2][1] + mid_pred(t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]);
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]);
+        } else {
+            c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[2][0], lt_mv->v[3][0], l_mv->v[1][0]);
+            c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[2][1], lt_mv->v[3][1], l_mv->v[1][1]);
+            c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0],  c_mv->v[0][0]);
+            c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1],  c_mv->v[0][1]);
+            c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0],  c_mv->v[0][0]);
+            c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1],  c_mv->v[0][1]);
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0],  c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1],  c_mv->v[2][1]);
+        }
+    } else {
+        if (flags & 0x20) {
+            c_mv->v[0][0] = mv.v[0][0];
+            c_mv->v[0][1] = mv.v[0][1];
+            c_mv->v[1][0] = mv.v[1][0] + mv.v[0][0];
+            c_mv->v[1][1] = mv.v[1][1] + mv.v[0][1];
+            c_mv->v[2][0] = mv.v[2][0] + mv.v[0][0];
+            c_mv->v[2][1] = mv.v[2][1] + mv.v[0][1];
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]);
+        } else {
+            c_mv->v[0][0] = mv.v[0][0] + mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]);
+            c_mv->v[0][1] = mv.v[0][1] + mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]);
+            c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0], c_mv->v[0][0]);
+            c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1], c_mv->v[0][1]);
+            c_mv->v[1][0] = mv.v[1][0] + mid_pred(l_mv->v[1][0], c_mv->v[0][0], c_mv->v[2][0]);
+            c_mv->v[1][1] = mv.v[1][1] + mid_pred(l_mv->v[1][1], c_mv->v[0][1], c_mv->v[2][1]);
+            c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]);
+            c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]);
+        }
+    }
+
+    ff_dlog(NULL, "  predicted MVs:");
+    for (int i = 0; i < 4; i++)
+        ff_dlog(NULL, " %d,%d", c_mv->v[i][0], c_mv->v[i][1]);
+    ff_dlog(NULL, "\n");
+}
+
+static int bink2g_decode_mv(Bink2Context *c, GetBitContext *gb, int x, int y,
+                            MVectors *mv)
+{
+    int num_mvs = get_bits1(gb) ? 1 : 4;
+
+    mv->nb_vectors = num_mvs;
+
+    for (int i = 0; i < 2; i++) {
+        for (int j = 0; j < num_mvs; j++) {
+            int val = get_vlc2(gb, bink2g_mv_vlc.table, bink2g_mv_vlc.bits, 1);
+
+            ff_dlog(NULL, " MV val = %d @ %d\n", val, get_bits_count(gb));
+            if (val < 0)
+                return AVERROR_INVALIDDATA;
+            if (val >= 8 && val != 15)
+                val = val - 15;
+            if (val == 15) {
+                int bits = get_unary(gb, 1, 12) + 4;
+                val = get_bits(gb, bits) + (1 << bits) - 1;
+                if (val & 1)
+                    val = (-(val >> 1) - 1);
+                else
+                    val =    val >> 1;
+            }
+            mv->v[j][i] = val;
+            ff_dlog(NULL, " MV [%d,%d] = %d @ %d\n", j, i, val, get_bits_count(gb));
+        }
+    }
+
+    return 0;
+}
+
+static void update_intra_q(Bink2Context *c, int8_t *intra_q, int dq, int flags)
+{
+    if (flags & 0x20 && flags & 0x80)
+        *intra_q = 16 + dq;
+    else if (flags & 0x80)
+        *intra_q = c->current_q[c->mb_pos - 1].intra_q + dq;
+    else if (flags & 0x20)
+        *intra_q = c->prev_q[c->mb_pos].intra_q + dq;
+    else
+        *intra_q = mid_pred(c->prev_q[c->mb_pos].intra_q,
+                            c->current_q[c->mb_pos - 1].intra_q,
+                            c->prev_q[c->mb_pos - 1].intra_q) + dq;
+}
+
+static void update_inter_q(Bink2Context *c, int8_t *inter_q, int dq, int flags)
+{
+    if (flags & 0x20 && flags & 0x80)
+        *inter_q = 16 + dq;
+    else if (flags & 0x80)
+        *inter_q = c->current_q[c->mb_pos - 1].inter_q + dq;
+    else if (flags & 0x20)
+        *inter_q = c->prev_q[c->mb_pos].inter_q + dq;
+    else
+        *inter_q = mid_pred(c->prev_q[c->mb_pos].inter_q,
+                            c->current_q[c->mb_pos - 1].inter_q,
+                            c->prev_q[c->mb_pos - 1].inter_q) + dq;
+}
+
+#define CH1FILTER(src)    ((6*(src)[0] + 2*(src)[1] + 4) >> 3)
+#define CH2FILTER(src)    ((  (src)[0] +   (src)[1] + 1) >> 1)
+#define CH3FILTER(src)    ((2*(src)[0] + 6*(src)[1] + 4) >> 3)
+
+#define CV1FILTER(src, i)    ((6*(src)[0] + 2*(src)[i] + 4) >> 3)
+#define CV2FILTER(src, i)    ((  (src)[0] +   (src)[i] + 1) >> 1)
+#define CV3FILTER(src, i)    ((2*(src)[0] + 6*(src)[i] + 4) >> 3)
+
+static void bink2g_c_mc(Bink2Context *c, int x, int y,
+                        uint8_t *dst, int stride,
+                        uint8_t *src, int sstride,
+                        int width, int height,
+                        int mv_x, int mv_y,
+                        int mode)
+{
+    uint8_t *msrc;
+    uint8_t temp[8*9];
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    //ff_dlog(NULL, "CHROMA %d: %dx%d | %dx%d\n", mode, x, y, mv_x, mv_y);
+    switch (mode) {
+    case 0:
+        copy_block8(dst, msrc, stride, sstride, 8);
+        break;
+    case 1:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CH1FILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+        break;
+    case 2:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CH2FILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+        break;
+    case 3:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CH3FILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+        break;
+    case 4:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i*stride] = av_clip_uint8(CV1FILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+        break;
+    case 5:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 6:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 7:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 8:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i*stride] = av_clip_uint8(CV2FILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+        break;
+    case 9:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 10:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 11:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 12:
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i*stride] = av_clip_uint8(CV3FILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+        break;
+    case 13:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 14:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    case 15:
+        for (int i = 0; i < 9; i++) {
+            for (int j = 0; j < 8; j++)
+                temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 8; j++) {
+            for (int i = 0; i < 8; i++)
+                dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8));
+            dst  += stride;
+        }
+        break;
+    }
+}
+
+static int bink2g_mcompensate_chroma(Bink2Context *c, int x, int y,
+                                     uint8_t *dst, int stride,
+                                     uint8_t *src, int sstride,
+                                     int width, int height)
+{
+    MVectors *mv = &c->current_mv[c->mb_pos].mv;
+    int mv_x, mv_y, mode;
+
+    mv_x  = (mv->v[0][0] >> 2) + x;
+    mv_y  = (mv->v[0][1] >> 2) + y;
+    mode  =  mv->v[0][0] & 3;
+    mode |= (mv->v[0][1] & 3) << 2;
+    bink2g_c_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x = (mv->v[1][0] >> 2) + x + 8;
+    mv_y = (mv->v[1][1] >> 2) + y;
+    mode  =  mv->v[1][0] & 3;
+    mode |= (mv->v[1][1] & 3) << 2;
+    bink2g_c_mc(c, x, y, dst + x + 8, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x = (mv->v[2][0] >> 2) + x;
+    mv_y = (mv->v[2][1] >> 2) + y + 8;
+    mode  =  mv->v[2][0] & 3;
+    mode |= (mv->v[2][1] & 3) << 2;
+    bink2g_c_mc(c, x, y, dst + x + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x = (mv->v[3][0] >> 2) + x + 8;
+    mv_y = (mv->v[3][1] >> 2) + y + 8;
+    mode  =  mv->v[3][0] & 3;
+    mode |= (mv->v[3][1] & 3) << 2;
+    bink2g_c_mc(c, x, y, dst + x + 8 + 8 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    return 0;
+}
+
+#define LHFILTER(src)    ((((src)[0]+(src)[1])*19 >> 1)-((src)[-1]+(src)[2  ])*2+(((src)[-2  ]+(src)[3  ])>>1)+8>>4)
+#define LVFILTER(src, i) ((((src)[0]+(src)[i])*19 >> 1)-((src)[-i]+(src)[2*i])*2+(((src)[-2*i]+(src)[3*i])>>1)+8>>4)
+
+static void bink2g_y_mc(Bink2Context *c, int x, int y,
+                        uint8_t *dst, int stride,
+                        uint8_t *src, int sstride,
+                        int width, int height,
+                        int mv_x, int mv_y, int mode)
+{
+    uint8_t *msrc;
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    //ff_dlog(NULL, "LUMA %d: %dx%d | %dx%d\n", mode, x, y, mv_x, mv_y);
+    if (mode == 0) {
+        copy_block16(dst, msrc, stride, sstride, 16);
+    } else if (mode == 1) {
+        for (int j = 0; j < 16; j++) {
+            for (int i = 0; i < 16; i++)
+                dst[i] = av_clip_uint8(LHFILTER(msrc + i));
+            dst  += stride;
+            msrc += sstride;
+        }
+    } else if (mode == 2) {
+        for (int j = 0; j < 16; j++) {
+            for (int i = 0; i < 16; i++)
+                dst[i*stride] = av_clip_uint8(LVFILTER(msrc + i*sstride, sstride));
+            dst  += 1;
+            msrc += 1;
+        }
+    } else if (mode == 3) {
+        uint8_t temp[21 * 16];
+
+        msrc -= 2 * sstride;
+        for (int i = 0; i < 21; i++) {
+            for (int j = 0; j < 16; j++)
+                temp[i*16+j] = av_clip_uint8(LHFILTER(msrc + j));
+            msrc += sstride;
+        }
+        for (int j = 0; j < 16; j++) {
+            for (int i = 0; i < 16; i++)
+                dst[i] = av_clip_uint8(LVFILTER(temp+(j+2)*16+i, 16));
+            dst  += stride;
+        }
+    }
+}
+
+static int bink2g_mcompensate_luma(Bink2Context *c, int x, int y,
+                                   uint8_t *dst, int stride,
+                                   uint8_t *src, int sstride,
+                                   int width, int height)
+{
+    MVectors *mv = &c->current_mv[c->mb_pos].mv;
+    int mv_x, mv_y, mode;
+
+    mv_x  = (mv->v[0][0] >> 1) + x;
+    mv_y  = (mv->v[0][1] >> 1) + y;
+    mode  =  mv->v[0][0] & 1;
+    mode |= (mv->v[0][1] & 1) << 1;
+    bink2g_y_mc(c, x, y, dst + x, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x  = (mv->v[1][0] >> 1) + x + 16;
+    mv_y  = (mv->v[1][1] >> 1) + y;
+    mode  =  mv->v[1][0] & 1;
+    mode |= (mv->v[1][1] & 1) << 1;
+    bink2g_y_mc(c, x, y, dst + x + 16, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x  = (mv->v[2][0] >> 1) + x;
+    mv_y  = (mv->v[2][1] >> 1) + y + 16;
+    mode  =  mv->v[2][0] & 1;
+    mode |= (mv->v[2][1] & 1) << 1;
+    bink2g_y_mc(c, x, y, dst + x + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    mv_x  = (mv->v[3][0] >> 1) + x + 16;
+    mv_y  = (mv->v[3][1] >> 1) + y + 16;
+    mode  =  mv->v[3][0] & 1;
+    mode |= (mv->v[3][1] & 1) << 1;
+    bink2g_y_mc(c, x, y, dst + x + 16 + 16 * stride, stride, src, sstride, width, height, mv_x, mv_y, mode);
+
+    return 0;
+}
+
+static int bink2g_average_block(uint8_t *src, int stride)
+{
+    int sum = 0;
+
+    for (int i = 0; i < 8; i++) {
+        int avg_a = (src[i+0*stride] + src[i+1*stride] + 1) >> 1;
+        int avg_b = (src[i+2*stride] + src[i+3*stride] + 1) >> 1;
+        int avg_c = (src[i+4*stride] + src[i+5*stride] + 1) >> 1;
+        int avg_d = (src[i+6*stride] + src[i+7*stride] + 1) >> 1;
+        int avg_e = (avg_a + avg_b + 1) >> 1;
+        int avg_f = (avg_c + avg_d + 1) >> 1;
+        int avg_g = (avg_e + avg_f + 1) >> 1;
+        sum += avg_g;
+    }
+
+    return sum;
+}
+
+static void bink2g_average_chroma(Bink2Context *c, int x, int y,
+                                  uint8_t *src, int stride,
+                                  int *dc)
+{
+    for (int i = 0; i < 4; i++) {
+        int X = i & 1;
+        int Y = i >> 1;
+        dc[i] = bink2g_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride);
+    }
+}
+
+static void bink2g_average_luma(Bink2Context *c, int x, int y,
+                                uint8_t *src, int stride,
+                                int *dc)
+{
+    for (int i = 0; i < 16; i++) {
+        int I = luma_repos[i];
+        int X = I & 3;
+        int Y = I >> 2;
+        dc[i] = bink2g_average_block(src + x + X * 8 + (y + Y * 8) * stride, stride);
+        //ff_dlog(NULL, "   DC avg %d:%d\n", i, dc[i]);
+    }
+}
+
+static int bink2g_decode_slice(Bink2Context *c,
+                               uint8_t *dst[4], int stride[4],
+                               uint8_t *src[4], int sstride[4],
+                               int is_kf, int start, int end)
+{
+    GetBitContext *gb = &c->gb;
+    int w = c->avctx->width;
+    int h = c->avctx->height;
+    int ret = 0, dq, flags;
+
+    memset(c->prev_q, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_q));
+    memset(c->prev_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_mv));
+
+    for (int y = start; y < end; y += 32) {
+        int types_lru[4] = { MOTION_BLOCK, RESIDUE_BLOCK, SKIP_BLOCK, INTRA_BLOCK };
+        unsigned y_cbp_intra = 0, u_cbp_intra = 0, v_cbp_intra = 0, a_cbp_intra = 0;
+        unsigned y_cbp_inter = 0, u_cbp_inter = 0, v_cbp_inter = 0, a_cbp_inter = 0;
+
+        memset(c->current_q, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_q));
+        memset(c->current_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_mv));
+
+        for (int x = 0; x < c->avctx->width; x += 32) {
+            int type = is_kf ? INTRA_BLOCK : bink2g_get_type(gb, types_lru);
+            int8_t *intra_q = &c->current_q[x / 32].intra_q;
+            int8_t *inter_q = &c->current_q[x / 32].inter_q;
+            MVectors mv = { 0 };
+
+            if (!is_kf)
+                ff_dlog(NULL, " lru %d %d %d %d @ %d\n",
+                        types_lru[0], types_lru[1], types_lru[2], types_lru[3],
+                        get_bits_count(gb));
+            ff_dlog(NULL, " MB %d,%d @ %d\n", x/32, y/32, get_bits_count(gb));
+
+            c->mb_pos = x / 32;
+            c->current_idc[c->mb_pos].block_type = type;
+            flags = 0;
+            if (y == start)
+                flags |= 0x80;
+            if (!x)
+                flags |= 0x20;
+            if (x == 32)
+                flags |= 0x200;
+            if (x + 32 >= c->avctx->width)
+                flags |= 0x40;
+            ff_dlog(NULL, " MB type %d @ %d\n", type, get_bits_count(gb));
+            switch (type) {
+            case INTRA_BLOCK:
+                if (!(flags & 0xA0) && c->prev_idc[c->mb_pos - 1].block_type != INTRA_BLOCK) {
+                    bink2g_average_luma  (c, x  -32, -32, dst[0], stride[0], c->prev_idc[c->mb_pos - 1].dc[0]);
+                    bink2g_average_chroma(c, x/2-16, -16, dst[2], stride[2], c->prev_idc[c->mb_pos - 1].dc[1]);
+                    bink2g_average_chroma(c, x/2-16, -16, dst[1], stride[1], c->prev_idc[c->mb_pos - 1].dc[2]);
+                    if (c->has_alpha)
+                        bink2g_average_luma(c, x-32, -32, dst[3], stride[3], c->prev_idc[c->mb_pos - 1].dc[3]);
+                }
+                if (!(flags & 0x20) && c->current_idc[c->mb_pos - 1].block_type != INTRA_BLOCK) {
+                    bink2g_average_luma  (c, x  -32, 0, dst[0], stride[0], c->current_idc[c->mb_pos - 1].dc[0]);
+                    bink2g_average_chroma(c, x/2-16, 0, dst[2], stride[2], c->current_idc[c->mb_pos - 1].dc[1]);
+                    bink2g_average_chroma(c, x/2-16, 0, dst[1], stride[1], c->current_idc[c->mb_pos - 1].dc[2]);
+                    if (c->has_alpha)
+                        bink2g_average_luma(c, x-32, 0, dst[3], stride[3], c->current_idc[c->mb_pos - 1].dc[3]);
+                }
+                if ((flags & 0x20) && !(flags & 0x80) && c->prev_idc[c->mb_pos + 1].block_type != INTRA_BLOCK) {
+                    bink2g_average_luma  (c, x  +32, -32, dst[0], stride[0], c->prev_idc[c->mb_pos + 1].dc[0]);
+                    bink2g_average_chroma(c, x/2+16, -16, dst[2], stride[2], c->prev_idc[c->mb_pos + 1].dc[1]);
+                    bink2g_average_chroma(c, x/2+16, -16, dst[1], stride[1], c->prev_idc[c->mb_pos + 1].dc[2]);
+                    if (c->has_alpha)
+                        bink2g_average_luma(c, x+32, -32, dst[3], stride[3], c->prev_idc[c->mb_pos + 1].dc[3]);
+                }
+                if (!(flags & 0x80) && c->prev_idc[c->mb_pos].block_type != INTRA_BLOCK) {
+                    bink2g_average_luma  (c, x,   -32, dst[0], stride[0], c->prev_idc[c->mb_pos].dc[0]);
+                    bink2g_average_chroma(c, x/2, -16, dst[2], stride[2], c->prev_idc[c->mb_pos].dc[1]);
+                    bink2g_average_chroma(c, x/2, -16, dst[1], stride[1], c->prev_idc[c->mb_pos].dc[2]);
+                    if (c->has_alpha)
+                        bink2g_average_luma(c, x, -32, dst[3], stride[3], c->prev_idc[c->mb_pos].dc[3]);
+                }
+
+                bink2g_predict_mv(c, x, y, flags, mv);
+                update_inter_q(c, inter_q, 0, flags);
+                dq = bink2g_decode_dq(gb);
+                update_intra_q(c, intra_q, dq, flags);
+                ff_dlog(NULL, "  MB quant %d @ %d\n", *intra_q, get_bits_count(gb));
+                if (*intra_q < 0 || *intra_q >= 37) {
+                    ret = AVERROR_INVALIDDATA;
+                    goto fail;
+                }
+                c->comp = 0;
+                ret = bink2g_decode_intra_luma(c, gb, c->iblock, &y_cbp_intra, *intra_q, &c->dsp,
+                                               dst[0] + x, stride[0], flags);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 1;
+                ret = bink2g_decode_intra_chroma(c, gb, c->iblock, &u_cbp_intra, *intra_q, &c->dsp,
+                                                 dst[2] + x/2, stride[2], flags);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 2;
+                ret = bink2g_decode_intra_chroma(c, gb, c->iblock, &v_cbp_intra, *intra_q, &c->dsp,
+                                                 dst[1] + x/2, stride[1], flags);
+                if (ret < 0)
+                    goto fail;
+                if (c->has_alpha) {
+                    c->comp = 3;
+                    ret = bink2g_decode_intra_luma(c, gb, c->iblock, &a_cbp_intra, *intra_q, &c->dsp,
+                                                   dst[3] + x, stride[3], flags);
+                    if (ret < 0)
+                        goto fail;
+                }
+                break;
+            case SKIP_BLOCK:
+                update_inter_q(c, inter_q, 0, flags);
+                update_intra_q(c, intra_q, 0, flags);
+                copy_block16(dst[0] + x, src[0] + x + sstride[0] * y,
+                             stride[0], sstride[0], 32);
+                copy_block16(dst[0] + x + 16, src[0] + x + 16 + sstride[0] * y,
+                             stride[0], sstride[0], 32);
+                copy_block16(dst[1] + (x/2), src[1] + (x/2) + sstride[1] * (y/2),
+                             stride[1], sstride[1], 16);
+                copy_block16(dst[2] + (x/2), src[2] + (x/2) + sstride[2] * (y/2),
+                             stride[2], sstride[2], 16);
+                if (c->has_alpha) {
+                    copy_block16(dst[3] + x, src[3] + x + sstride[3] * y,
+                                 stride[3], sstride[3], 32);
+                    copy_block16(dst[3] + x + 16, src[3] + x + 16 + sstride[3] * y,
+                                 stride[3], sstride[3], 32);
+                }
+                break;
+            case MOTION_BLOCK:
+                update_intra_q(c, intra_q, 0, flags);
+                update_inter_q(c, inter_q, 0, flags);
+                ret = bink2g_decode_mv(c, gb, x, y, &mv);
+                if (ret < 0)
+                    goto fail;
+                bink2g_predict_mv(c, x, y, flags, mv);
+                c->comp = 0;
+                ret = bink2g_mcompensate_luma(c, x, y,
+                                              dst[0], stride[0],
+                                              src[0], sstride[0],
+                                              w, h);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 1;
+                ret = bink2g_mcompensate_chroma(c, x/2, y/2,
+                                                dst[2], stride[2],
+                                                src[2], sstride[2],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 2;
+                ret = bink2g_mcompensate_chroma(c, x/2, y/2,
+                                                dst[1], stride[1],
+                                                src[1], sstride[1],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                if (c->has_alpha) {
+                    c->comp = 3;
+                    ret = bink2g_mcompensate_luma(c, x, y,
+                                                  dst[3], stride[3],
+                                                  src[3], sstride[3],
+                                                  w, h);
+                    if (ret < 0)
+                        goto fail;
+                }
+                break;
+            case RESIDUE_BLOCK:
+                update_intra_q(c, intra_q, 0, flags);
+                ret = bink2g_decode_mv(c, gb, x, y, &mv);
+                if (ret < 0)
+                    goto fail;
+                bink2g_predict_mv(c, x, y, flags, mv);
+                dq = bink2g_decode_dq(gb);
+                update_inter_q(c, inter_q, dq, flags);
+                ff_dlog(NULL, "  MB quant %d @ %d\n", *inter_q, get_bits_count(gb));
+                if (*inter_q < 0 || *inter_q >= 37) {
+                    ret = AVERROR_INVALIDDATA;
+                    goto fail;
+                }
+                c->comp = 0;
+                ret = bink2g_mcompensate_luma(c, x, y,
+                                              dst[0], stride[0],
+                                              src[0], sstride[0],
+                                              w, h);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 1;
+                ret = bink2g_mcompensate_chroma(c, x/2, y/2,
+                                                dst[2], stride[2],
+                                                src[2], sstride[2],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                c->comp = 2;
+                ret = bink2g_mcompensate_chroma(c, x/2, y/2,
+                                                dst[1], stride[1],
+                                                src[1], sstride[1],
+                                                w/2, h/2);
+                if (ret < 0)
+                    goto fail;
+                if (c->has_alpha) {
+                    c->comp = 3;
+                    ret = bink2g_mcompensate_luma(c, x, y,
+                                                  dst[3], stride[3],
+                                                  src[3], sstride[3],
+                                                  w, h);
+                    if (ret < 0)
+                        goto fail;
+                }
+                c->comp = 0;
+                ret = bink2g_decode_inter_luma(c, gb, c->iblock, &y_cbp_inter, *inter_q, &c->dsp,
+                                               dst[0] + x, stride[0], flags);
+                if (ret < 0)
+                    goto fail;
+                if (get_bits1(gb)) {
+                    c->comp = 1;
+                    ret = bink2g_decode_inter_chroma(c, gb, c->iblock, &u_cbp_inter, *inter_q, &c->dsp,
+                                                     dst[2] + x/2, stride[2], flags);
+                    if (ret < 0)
+                        goto fail;
+                    c->comp = 2;
+                    ret = bink2g_decode_inter_chroma(c, gb, c->iblock, &v_cbp_inter, *inter_q, &c->dsp,
+                                                     dst[1] + x/2, stride[1], flags);
+                    if (ret < 0)
+                        goto fail;
+                } else {
+                    u_cbp_inter = 0;
+                    v_cbp_inter = 0;
+                }
+                if (c->has_alpha) {
+                    c->comp = 3;
+                    ret = bink2g_decode_inter_luma(c, gb, c->iblock, &a_cbp_inter, *inter_q, &c->dsp,
+                                                   dst[3] + x, stride[3], flags);
+                    if (ret < 0)
+                        goto fail;
+                }
+                break;
+            default:
+                return AVERROR_INVALIDDATA;
+            }
+        }
+
+        dst[0] += stride[0] * 32;
+        dst[1] += stride[1] * 16;
+        dst[2] += stride[2] * 16;
+        dst[3] += stride[3] * 32;
+
+        FFSWAP(MVPredict *, c->current_mv, c->prev_mv);
+        FFSWAP(QuantPredict *, c->current_q, c->prev_q);
+        FFSWAP(DCIPredict *, c->current_idc, c->prev_idc);
+    }
+fail:
+    emms_c();
+
+    return ret;
+}
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index a3de8e1c2b..0e8df1a56e 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1705,6 +1705,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"),
         .props     = AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_BINKVIDEO2,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "binkvideo2",
+        .long_name = NULL_IF_CONFIG_SMALL("Bink video 2"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* various PCM "codecs" */
     {
diff --git a/libavformat/bink.c b/libavformat/bink.c
index 44eb04362e..29e59c7276 100644
--- a/libavformat/bink.c
+++ b/libavformat/bink.c
@@ -148,8 +148,7 @@  static int read_header(AVFormatContext *s)
     vst->codecpar->codec_id   = AV_CODEC_ID_BINKVIDEO;
 
     if ((vst->codecpar->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) {
-        av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n");
-        vst->codecpar->codec_id = AV_CODEC_ID_NONE;
+        vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO2;
     }
 
     if (ff_get_extradata(s, vst->codecpar, pb, 4) < 0)