[FFmpeg-devel] [PATCH] avcodec: add bink2 video decoder

Paul B Mahol onemda at gmail.com
Tue May 24 16:36:50 EEST 2022


Signed-off-by: Paul B Mahol <onemda at 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

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) {
-- 
2.36.1



More information about the ffmpeg-devel mailing list