diff mbox series

[FFmpeg-devel] avcodec: add bink2 video decoder

Message ID 20220524133650.18299-1-onemda@gmail.com
State New
Headers show
Series [FFmpeg-devel] avcodec: add bink2 video decoder | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_armv7_RPi4 success Make finished
andriy/make_fate_armv7_RPi4 success Make fate finished

Commit Message

Paul B Mahol May 24, 2022, 1:36 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 configure               |    1 +
 libavcodec/Makefile     |    1 +
 libavcodec/allcodecs.c  |    1 +
 libavcodec/bink2.c      |  479 +++++++++++++
 libavcodec/bink2f.c     | 1234 ++++++++++++++++++++++++++++++++
 libavcodec/bink2g.c     | 1479 +++++++++++++++++++++++++++++++++++++++
 libavcodec/codec_desc.c |    7 +
 libavcodec/codec_id.h   |    1 +
 libavformat/bink.c      |    7 +-
 9 files changed, 3206 insertions(+), 4 deletions(-)
 create mode 100644 libavcodec/bink2.c
 create mode 100644 libavcodec/bink2f.c
 create mode 100644 libavcodec/bink2g.c

Comments

Tomas Härdin May 25, 2022, 6:17 p.m. UTC | #1
tis 2022-05-24 klockan 15:36 +0200 skrev Paul B Mahol:
> 
> +    c->current_q = av_malloc_array((avctx->width + 31) / 32,
> sizeof(*c->current_q));
> +    if (!c->current_q)
> +        return AVERROR(ENOMEM);

You can exploit BINK_MAX_WIDTH and BINK_MAX_HEIGHT to make the size of
these arrays constant, thus simplifying the code.

/Tomas
Andreas Rheinhardt May 28, 2022, 10:39 a.m. UTC | #2
Paul B Mahol:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/bink2.c      |  479 +++++++++++++
>  libavcodec/bink2f.c     | 1234 ++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1479 +++++++++++++++++++++++++++++++++++++++

The latter two files are not standalone files, but are included in
bink2.c. That means that bink2.d will contain bink2f.c and bink2g.c as
prerequisites for bink2.c. Yet if the code were to be changed so that
these files would no longer exist, then the build would fail if you have
an old bink2.d with bink2[fg]].c prerequisites, because make would not
know how to create these prerequisites.
To fix this, rename these files so that they are either templates or
headers.

>  libavcodec/codec_desc.c |    7 +
>  libavcodec/codec_id.h   |    1 +
>  libavformat/bink.c      |    7 +-
>  9 files changed, 3206 insertions(+), 4 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c
>
Paul B Mahol June 1, 2022, 8:09 a.m. UTC | #3
Renamed to headers, will apply right now!
Andreas Rheinhardt June 1, 2022, 8:57 a.m. UTC | #4
Paul B Mahol:
> Renamed to headers, will apply right now!

In this case you will likely either add these headers to SKIPHEADERS or
add the necessary headers to them to make them standalone.

- Andreas
Andreas Rheinhardt June 1, 2022, 9:03 a.m. UTC | #5
Paul B Mahol:
> On Wed, Jun 1, 2022 at 10:57 AM Andreas Rheinhardt <
> andreas.rheinhardt@outlook.com> wrote:
> 
>> Paul B Mahol:
>>> Renamed to headers, will apply right now!
>>
>> In this case you will likely either add these headers to SKIPHEADERS or
>> add the necessary headers to them to make them standalone.
>>
>>
> Why? fate source test does not complain.
> 
> 

fate-source only checks for license headers, not for proper inclusions.
"make checkheaders" does the latter. It is not part of the standard fate
run.

- Andreas
Paul B Mahol June 1, 2022, 9:04 a.m. UTC | #6
On Wed, Jun 1, 2022 at 10:57 AM Andreas Rheinhardt <
andreas.rheinhardt@outlook.com> wrote:

> Paul B Mahol:
> > Renamed to headers, will apply right now!
>
> In this case you will likely either add these headers to SKIPHEADERS or
> add the necessary headers to them to make them standalone.
>
>
Why? fate source test does not complain.



> - Andreas
> _______________________________________________
> 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".
>
Anton Khirnov June 1, 2022, 9:45 a.m. UTC | #7
Quoting Andreas Rheinhardt (2022-06-01 11:03:28)
> "make checkheaders" does the latter. It is not part of the standard fate

Any reason it isn't?
diff mbox series

Patch

diff --git a/configure b/configure
index f115b21064..516c3a5db4 100755
--- a/configure
+++ b/configure
@@ -2782,6 +2782,7 @@  atrac3pal_decoder_select="mdct sinewin"
 atrac9_decoder_select="mdct"
 av1_decoder_select="cbs_av1"
 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 38425d2f22..e6eb8c0854 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -252,6 +252,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 c47133aa18..3ae41827a2 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -66,6 +66,7 @@  extern const FFCodec ff_ayuv_decoder;
 extern const FFCodec ff_bethsoftvid_decoder;
 extern const FFCodec ff_bfi_decoder;
 extern const FFCodec ff_bink_decoder;
+extern const FFCodec ff_bink2_decoder;
 extern const FFCodec ff_bitpacked_decoder;
 extern const FFCodec ff_bitpacked_encoder;
 extern const FFCodec ff_bmp_encoder;
diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
new file mode 100644
index 0000000000..102d844c89
--- /dev/null
+++ b/libavcodec/bink2.c
@@ -0,0 +1,479 @@ 
+/*
+ * 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
+ */
+
+#include "libavutil/avassert.h"
+#include "libavutil/attributes.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/internal.h"
+#include "avcodec.h"
+#include "blockdsp.h"
+#include "codec_internal.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 uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };
+
+static const uint8_t bink2_next_skips[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
+};
+
+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
+};
+
+#include "bink2f.c"
+#include "bink2g.c"
+
+static void bink2_get_block_flags(GetBitContext *gb, int offset, int size, uint8_t *dst)
+{
+    int j, v = 0, flags_left, mode = 0, nv;
+    unsigned cache, flag = 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);
+
+        return;
+    }
+
+    flags_left = size;
+    while (flags_left > 0) {
+        cache = offset;
+        if (get_bits1(gb) == 0) {
+            if (mode == 3) {
+                flag ^= 1;
+            } else {
+                flag = get_bits1(gb);
+            }
+            mode = 2;
+            if (flags_left < 5) {
+                nv = get_bitsz(gb, flags_left - 1);
+                nv <<= (offset + 1) & 0x1f;
+                offset += flags_left;
+                flags_left = 0;
+            } else {
+                nv = get_bits(gb, 4) << ((offset + 1) & 0x1f);
+                offset += 5;
+                flags_left -= 5;
+            }
+            v |= flag << (cache & 0x1f) | nv;
+            if (offset >= 8) {
+                *dst++ = v & 0xff;
+                v >>= 8;
+                offset -= 8;
+            }
+        } else {
+            int temp, bits, nb_coded;
+
+            bits = flags_left < 4 ? 2 : flags_left < 16 ? 4 : 5;
+            nb_coded = bits + 1;
+            if (mode == 3) {
+                flag ^= 1;
+            } else {
+                nb_coded++;
+                flag = get_bits1(gb);
+            }
+            nb_coded = FFMIN(nb_coded, flags_left);
+            flags_left -= nb_coded;
+            if (flags_left > 0) {
+                temp = get_bits(gb, bits);
+                flags_left -= temp;
+                nb_coded += temp;
+                mode = temp == (1 << bits) - 1U ? 1 : 3;
+            }
+
+            temp = (flag << 0x1f) >> 0x1f & 0xff;
+            while (nb_coded > 8) {
+                v |= temp << (cache & 0x1f);
+                *dst++ = v & 0xff;
+                v >>= 8;
+                nb_coded -= 8;
+            }
+            if (nb_coded > 0) {
+                offset += nb_coded;
+                v |= ((1 << (nb_coded & 0x1f)) - 1U & temp) << (cache & 0x1f);
+                if (offset >= 8) {
+                    *dst++ = v & 0xff;
+                    v >>= 8;
+                    offset -= 8;
+                }
+            }
+        }
+    }
+
+    if (offset != 0)
+        *dst = v;
+}
+
+static int bink2_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+                              int *got_frame, AVPacket *pkt)
+{
+    Bink2Context * const c = avctx->priv_data;
+    GetBitContext *gb = &c->gb;
+    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];
+    }
+
+    if (!is_kf && (!src[0] || !src[1] || !src[2]))
+        return AVERROR_INVALIDDATA;
+
+    c->frame_flags = AV_RL32(pkt->data);
+    ff_dlog(avctx, "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))
+            bink2_get_block_flags(gb, 1, (((avctx->height + 15) & ~15) >> 3) - 1, c->row_cbp);
+        if (!(c->frame_flags & 0x4000))
+            bink2_get_block_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 (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 void bink2_flush(AVCodecContext *avctx)
+{
+    Bink2Context *c = avctx->priv_data;
+
+    av_frame_unref(c->last);
+}
+
+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;
+}
+
+const FFCodec ff_bink2_decoder = {
+    .p.name         = "binkvideo2",
+    .p.long_name    = NULL_IF_CONFIG_SMALL("Bink video 2"),
+    .p.type         = AVMEDIA_TYPE_VIDEO,
+    .p.id           = AV_CODEC_ID_BINKVIDEO2,
+    .priv_data_size = sizeof(Bink2Context),
+    .init           = bink2_decode_init,
+    .close          = bink2_decode_end,
+    FF_CODEC_DECODE_CB(bink2_decode_frame),
+    .flush          = bink2_flush,
+    .p.capabilities = AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_THREADSAFE |
+                      FF_CODEC_CAP_INIT_CLEANUP,
+};
diff --git a/libavcodec/bink2f.c b/libavcodec/bink2f.c
new file mode 100644
index 0000000000..d5ed96fd9c
--- /dev/null
+++ b/libavcodec/bink2f.c
@@ -0,0 +1,1234 @@ 
+/*
+ * 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 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 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 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.f;
+
+    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(lrintf(block[j] - 512.0f));
+        block += 8;
+        dst += stride;
+    }
+}
+
+static void bink2f_idct_add(uint8_t *dst, int stride,
+                            float *block)
+{
+    block[0] += 512.f;
+
+    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] + lrintf(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 (av_popcount(cbp & 0xF)) {
+            if (av_popcount(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 (av_popcount(cbplo & 0xF)) {
+        if (av_popcount(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] = {
+    1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6,
+};
+
+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);
+    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] + 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;
+            }
+            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;
+
+        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;
+            }
+
+            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 = bink2_next_skips[skip];
+                skip = bink2f_skips[skip];
+                if (skip == 11)
+                    skip = get_bits(gb, 6);
+                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);
+    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, 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);
+    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, 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]);
+        }
+    }
+}
+
+#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];
+
+    if (mv_x < 0 || mv_x >= width ||
+        mv_y < 0 || mv_y >= height)
+        return;
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    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;
+
+    if (mv_x < 0 || mv_x >= width ||
+        mv_y < 0 || mv_y >= height)
+        return;
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    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);
+    }
+}
+
+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;
+    }
+
+    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);
+
+            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;
+
+            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..8e050148e6
--- /dev/null
+++ b/libavcodec/bink2g.c
@@ -0,0 +1,1479 @@ 
+/*
+ * 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 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,
+};
+
+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 uint8_t bink2g_skips[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0,
+};
+
+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 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 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;
+
+    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;
+}
+
+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;
+        }
+    }
+
+    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;
+
+        next = 0;
+        idx  = 1;
+        while (idx < 64) {
+            next--;
+            if (next < 1) {
+                skip = get_vlc2(gb, skip_vlc->table, skip_vlc->bits, 1);
+                if (skip < 0)
+                    return AVERROR_INVALIDDATA;
+                next = bink2_next_skips[skip];
+                skip = bink2g_skips[skip];
+                if (skip == 11)
+                    skip = get_bits(gb, 6);
+                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;
+            block[i][scan[idx]] = ((val * qmat[q & 3][scan[idx]] * (1 << (q >> 2))) + 64) >> 7;
+            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);
+
+    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);
+
+    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);
+
+    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);
+
+    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];
+
+        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]);
+        }
+    }
+}
+
+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);
+
+            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;
+        }
+    }
+
+    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];
+
+    if (mv_x < 0 || mv_x >= width ||
+        mv_y < 0 || mv_y >= height)
+        return;
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    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;
+
+    if (mv_x < 0 || mv_x >= width ||
+        mv_y < 0 || mv_y >= height)
+        return;
+
+    msrc = src + mv_x + mv_y * sstride;
+
+    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);
+    }
+}
+
+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 };
+
+            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;
+            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);
+                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);
+                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 e7f0f6a8d4..3bcf22e6e7 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1879,6 +1879,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
                      AV_CODEC_PROP_LOSSLESS,
         .mime_types= MT("image/jxl"),
     },
+    {
+        .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/libavcodec/codec_id.h b/libavcodec/codec_id.h
index 8b317fa121..03234b7543 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -310,6 +310,7 @@  enum AVCodecID {
     AV_CODEC_ID_GEM,
     AV_CODEC_ID_VBN,
     AV_CODEC_ID_JPEGXL,
+    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/libavformat/bink.c b/libavformat/bink.c
index f4079dfb1d..abfc769a0b 100644
--- a/libavformat/bink.c
+++ b/libavformat/bink.c
@@ -72,7 +72,7 @@  static int probe(const AVProbeData *p)
               b[3] == 'k')) ||
              (b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */
              (b[3] == 'a' || b[3] == 'd' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' ||
-              b[3] == 'i' || b[3] == 'j' || b[3] == 'k'))) &&
+              b[3] == 'i' || b[3] == 'j' || b[3] == 'k' || b[3] == 'n'))) &&
             AV_RL32(b+8) > 0 &&  // num_frames
             AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH &&
             AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT &&
@@ -149,8 +149,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 ((ret = ff_get_extradata(s, vst->codecpar, pb, 4)) < 0)
@@ -169,7 +168,7 @@  static int read_header(AVFormatContext *s)
     revision = ((vst->codecpar->codec_tag >> 24) % 0xFF);
 
     if ((signature == AV_RL32("BIK") && (revision == 'k')) ||
-        (signature == AV_RL32("KB2") && (revision == 'i' || revision == 'j' || revision == 'k')))
+        (signature == AV_RL32("KB2") && (revision == 'i' || revision == 'j' || revision == 'k') || revision == 'n'))
         avio_skip(pb, 4); /* unknown new field */
 
     if (bink->num_audio_tracks) {