diff mbox series

[FFmpeg-devel] avcodec: add bink2 video decoder

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

Checks

Context Check Description
andriy/ffmpeg-patchwork pending
andriy/ffmpeg-patchwork success Applied patch
andriy/ffmpeg-patchwork success Configure finished
andriy/ffmpeg-patchwork success Make finished
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Paul B Mahol March 20, 2020, 1:31 p.m. UTC
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 configure               |    1 +
 libavcodec/Makefile     |    1 +
 libavcodec/allcodecs.c  |    1 +
 libavcodec/avcodec.h    |    1 +
 libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
 libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
 libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
 libavcodec/codec_desc.c |    7 +
 libavformat/bink.c      |    3 +-
 9 files changed, 3203 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/bink2.c
 create mode 100644 libavcodec/bink2f.c
 create mode 100644 libavcodec/bink2g.c

Comments

James Almer March 20, 2020, 2:08 p.m. UTC | #1
On 3/20/2020 10:31 AM, Paul B Mahol wrote:
> +static av_cold int bink2_decode_end(AVCodecContext *avctx)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +
> +    av_frame_free(&c->last);
> +    av_freep(&c->current_q);
> +    av_freep(&c->prev_q);
> +    av_freep(&c->current_dc);
> +    av_freep(&c->prev_dc);
> +    av_freep(&c->current_idc);
> +    av_freep(&c->prev_idc);
> +    av_freep(&c->current_mv);
> +    av_freep(&c->prev_mv);
> +    av_freep(&c->col_cbp);
> +    av_freep(&c->row_cbp);
> +
> +    return 0;
> +}
> +
> +AVCodec ff_bink2_decoder = {
> +    .name           = "binkvideo2",
> +    .long_name      = NULL_IF_CONFIG_SMALL("Bink video 2"),
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_BINKVIDEO2,
> +    .priv_data_size = sizeof(Bink2Context),
> +    .init           = bink2_decode_init,
> +    .close          = bink2_decode_end,
> +    .decode         = bink2_decode_frame,
> +    .capabilities   = AV_CODEC_CAP_DR1,
> +};

Missing a flush() callback unreffing c->last, and probably also zeroing
some of the above arrays.
Vittorio Giovara March 20, 2020, 5:15 p.m. UTC | #2
On Fri, Mar 20, 2020 at 9:31 AM Paul B Mahol <onemda@gmail.com> wrote:

> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3203 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c
>
> diff --git a/configure b/configure
> index 18f2841765..1d89d49b41 100755
> --- a/configure
> +++ b/configure
> @@ -2678,6 +2678,7 @@ atrac3pal_decoder_select="mdct sinewin"
>  atrac9_decoder_select="mdct"
>  avrn_decoder_select="exif jpegtables"
>  bink_decoder_select="blockdsp hpeldsp"
> +bink2_decoder_select="blockdsp"
>  binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
>  binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
>  cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index c1c9a44f2b..a79b4c6524 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -230,6 +230,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 b3184af954..d032547a9d 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -60,6 +60,7 @@ extern AVCodec ff_ayuv_decoder;
>  extern AVCodec ff_bethsoftvid_decoder;
>  extern AVCodec ff_bfi_decoder;
>  extern AVCodec ff_bink_decoder;
> +extern AVCodec ff_bink2_decoder;
>  extern AVCodec ff_bitpacked_decoder;
>  extern AVCodec ff_bmp_encoder;
>  extern AVCodec ff_bmp_decoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 78c483c25c..e8b20fa527 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -463,6 +463,7 @@ enum AVCodecID {
>      AV_CODEC_ID_MVDV,
>      AV_CODEC_ID_MVHA,
>      AV_CODEC_ID_CDTOONS,
> +    AV_CODEC_ID_BINKVIDEO2,
>
>      /* various PCM "codecs" */
>      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at
> the start of audio codecs
> diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
> new file mode 100644
> index 0000000000..0ebce7feeb
> --- /dev/null
> +++ b/libavcodec/bink2.c
> @@ -0,0 +1,869 @@
> +/*
> + * 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 "copy_block.h"
> +#include "idctdsp.h"
> +#include "internal.h"
> +#include "mathops.h"
> +
> +#define BITSTREAM_READER_LE
> +#include "get_bits.h"
> +#include "unary.h"
> +
> +#define BINK_FLAG_ALPHA 0x00100000
> +#define DC_MPRED(A, B, C) FFMIN(FFMAX((C) + (B) - (A), FFMIN3(A, B, C)),
> FFMAX3(A, B, C))
> +#define DC_MPRED2(A, B) FFMIN(FFMAX((A), (B)), FFMAX(FFMIN((A), (B)), 2 *
> (A) - (B)))
> +
> +static VLC bink2f_quant_vlc;
> +static VLC bink2f_ac_val0_vlc;
> +static VLC bink2f_ac_val1_vlc;
> +static VLC bink2f_ac_skip0_vlc;
> +static VLC bink2f_ac_skip1_vlc;
> +static VLC bink2g_ac_skip0_vlc;
> +static VLC bink2g_ac_skip1_vlc;
> +static VLC bink2g_mv_vlc;
> +
> +static const uint8_t kb2h_num_slices[] = {
> +    2, 3, 4, 8,
> +};
> +
> +static const uint8_t luma_repos[] = {
> +    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
> +};
> +
> +static const uint16_t bink2g_luma_intra_qmat[4][64] = {
> +    {
> +     1024,   1432,   1506,   1181,
> +     1843,   2025,   5271,   8592,
> +     1313,   1669,   1630,   1672,
> +     2625,   3442,   8023,  12794,
> +     1076,   1755,   1808,   1950,
> +     3980,   4875,   8813,  11909,
> +     1350,   1868,   2127,   2016,
> +     4725,   4450,   7712,   9637,
> +     2458,   3103,   4303,   4303,
> +     6963,   6835,  11079,  13365,
> +     3375,   5704,   5052,   6049,
> +     9198,   7232,  10725,   9834,
> +     5486,   7521,   7797,   7091,
> +    11079,  10016,  13559,  12912,
> +     7279,   7649,   7020,   6097,
> +     9189,   9047,  12661,  13768,
> +    },
> +    {
> +     1218,   1703,   1791,   1405,
> +     2192,   2408,   6268,  10218,
> +     1561,   1985,   1938,   1988,
> +     3122,   4093,   9541,  15215,
> +     1279,   2087,   2150,   2319,
> +     4733,   5798,  10481,  14162,
> +     1606,   2222,   2530,   2398,
> +     5619,   5292,   9171,  11460,
> +     2923,   3690,   5117,   5118,
> +     8281,   8128,  13176,  15894,
> +     4014,   6783,   6008,   7194,
> +    10938,   8600,  12755,  11694,
> +     6524,   8944,   9272,   8433,
> +    13176,  11911,  16125,  15354,
> +     8657,   9096,   8348,   7250,
> +    10927,  10759,  15056,  16373,
> +    },
> +    {
> +     1448,   2025,   2130,   1671,
> +     2607,   2864,   7454,  12151,
> +     1856,   2360,   2305,   2364,
> +     3713,   4867,  11346,  18094,
> +     1521,   2482,   2557,   2758,
> +     5628,   6894,  12464,  16841,
> +     1909,   2642,   3008,   2852,
> +     6683,   6293,  10906,  13629,
> +     3476,   4388,   6085,   6086,
> +     9847,   9666,  15668,  18901,
> +     4773,   8066,   7145,   8555,
> +    13007,  10227,  15168,  13907,
> +     7758,  10637,  11026,  10028,
> +    15668,  14165,  19175,  18259,
> +    10294,  10817,   9927,   8622,
> +    12995,  12794,  17905,  19470,
> +    },
> +    {
> +     1722,   2408,   2533,   1987,
> +     3100,   3406,   8864,  14450,
> +     2208,   2807,   2741,   2811,
> +     4415,   5788,  13493,  21517,
> +     1809,   2951,   3041,   3280,
> +     6693,   8199,  14822,  20028,
> +     2271,   3142,   3578,   3391,
> +     7947,   7484,  12969,  16207,
> +     4133,   5218,   7236,   7238,
> +    11711,  11495,  18633,  22478,
> +     5677,   9592,   8497,  10174,
> +    15469,  12162,  18038,  16538,
> +     9226,  12649,  13112,  11926,
> +    18633,  16845,  22804,  21715,
> +    12242,  12864,  11806,  10254,
> +    15454,  15215,  21293,  23155,
> +    },
> +};
> +
> +static const uint16_t bink2g_chroma_intra_qmat[4][64] = {
> +    {
> +     1024,   1193,   1434,   2203,
> +     5632,   4641,   5916,   6563,
> +     1193,   1622,   1811,   3606,
> +     6563,   5408,   6894,   7649,
> +     1434,   1811,   3515,   4875,
> +     5916,   4875,   6215,   6894,
> +     2203,   3606,   4875,   3824,
> +     4641,   3824,   4875,   5408,
> +     5632,   6563,   5916,   4641,
> +     5632,   4641,   5916,   6563,
> +     4641,   5408,   4875,   3824,
> +     4641,   3824,   4875,   5408,
> +     5916,   6894,   6215,   4875,
> +     5916,   4875,   6215,   6894,
> +     6563,   7649,   6894,   5408,
> +     6563,   5408,   6894,   7649,
> +    },
> +    {
> +     1218,   1419,   1706,   2620,
> +     6698,   5519,   7035,   7805,
> +     1419,   1929,   2153,   4288,
> +     7805,   6432,   8199,   9096,
> +     1706,   2153,   4180,   5798,
> +     7035,   5798,   7390,   8199,
> +     2620,   4288,   5798,   4548,
> +     5519,   4548,   5798,   6432,
> +     6698,   7805,   7035,   5519,
> +     6698,   5519,   7035,   7805,
> +     5519,   6432,   5798,   4548,
> +     5519,   4548,   5798,   6432,
> +     7035,   8199,   7390,   5798,
> +     7035,   5798,   7390,   8199,
> +     7805,   9096,   8199,   6432,
> +     7805,   6432,   8199,   9096,
> +    },
> +    {
> +     1448,   1688,   2028,   3116,
> +     7965,   6563,   8367,   9282,
> +     1688,   2294,   2561,   5099,
> +     9282,   7649,   9750,  10817,
> +     2028,   2561,   4971,   6894,
> +     8367,   6894,   8789,   9750,
> +     3116,   5099,   6894,   5408,
> +     6563,   5408,   6894,   7649,
> +     7965,   9282,   8367,   6563,
> +     7965,   6563,   8367,   9282,
> +     6563,   7649,   6894,   5408,
> +     6563,   5408,   6894,   7649,
> +     8367,   9750,   8789,   6894,
> +     8367,   6894,   8789,   9750,
> +     9282,  10817,   9750,   7649,
> +     9282,   7649,   9750,  10817,
> +    },
> +    {
> +     1722,   2007,   2412,   3706,
> +     9472,   7805,   9950,  11038,
> +     2007,   2729,   3045,   6064,
> +    11038,   9096,  11595,  12864,
> +     2412,   3045,   5912,   8199,
> +     9950,   8199,  10452,  11595,
> +     3706,   6064,   8199,   6432,
> +     7805,   6432,   8199,   9096,
> +     9472,  11038,   9950,   7805,
> +     9472,   7805,   9950,  11038,
> +     7805,   9096,   8199,   6432,
> +     7805,   6432,   8199,   9096,
> +     9950,  11595,  10452,   8199,
> +     9950,   8199,  10452,  11595,
> +    11038,  12864,  11595,   9096,
> +    11038,   9096,  11595,  12864,
> +    },
> +};
> +
> +
> +static const uint16_t bink2g_inter_qmat[4][64] = {
> +    {
> +     1024,   1193,   1076,    844,
> +     1052,    914,   1225,   1492,
> +     1193,   1391,   1254,    983,
> +     1227,   1065,   1463,   1816,
> +     1076,   1254,   1161,    936,
> +     1195,   1034,   1444,   1741,
> +      844,    983,    936,    811,
> +     1055,    927,   1305,   1584,
> +     1052,   1227,   1195,   1055,
> +     1451,   1336,   1912,   2354,
> +      914,   1065,   1034,    927,
> +     1336,   1313,   1945,   2486,
> +     1225,   1463,   1444,   1305,
> +     1912,   1945,   3044,   4039,
> +     1492,   1816,   1741,   1584,
> +     2354,   2486,   4039,   5679,
> +    },
> +    {
> +     1218,   1419,   1279,   1003,
> +     1252,   1087,   1457,   1774,
> +     1419,   1654,   1491,   1169,
> +     1459,   1267,   1739,   2159,
> +     1279,   1491,   1381,   1113,
> +     1421,   1230,   1717,   2070,
> +     1003,   1169,   1113,    965,
> +     1254,   1103,   1552,   1884,
> +     1252,   1459,   1421,   1254,
> +     1725,   1589,   2274,   2799,
> +     1087,   1267,   1230,   1103,
> +     1589,   1562,   2313,   2956,
> +     1457,   1739,   1717,   1552,
> +     2274,   2313,   3620,   4803,
> +     1774,   2159,   2070,   1884,
> +     2799,   2956,   4803,   6753,
> +    },
> +    {
> +     1448,   1688,   1521,   1193,
> +     1488,   1293,   1732,   2110,
> +     1688,   1967,   1773,   1391,
> +     1735,   1507,   2068,   2568,
> +     1521,   1773,   1642,   1323,
> +     1690,   1462,   2042,   2462,
> +     1193,   1391,   1323,   1147,
> +     1492,   1311,   1845,   2241,
> +     1488,   1735,   1690,   1492,
> +     2052,   1889,   2704,   3328,
> +     1293,   1507,   1462,   1311,
> +     1889,   1857,   2751,   3515,
> +     1732,   2068,   2042,   1845,
> +     2704,   2751,   4306,   5712,
> +     2110,   2568,   2462,   2241,
> +     3328,   3515,   5712,   8031,
> +    },
> +    {
> +     1722,   2007,   1809,   1419,
> +     1770,   1537,   2060,   2509,
> +     2007,   2339,   2108,   1654,
> +     2063,   1792,   2460,   3054,
> +     1809,   2108,   1953,   1574,
> +     2010,   1739,   2428,   2928,
> +     1419,   1654,   1574,   1364,
> +     1774,   1559,   2195,   2664,
> +     1770,   2063,   2010,   1774,
> +     2440,   2247,   3216,   3958,
> +     1537,   1792,   1739,   1559,
> +     2247,   2209,   3271,   4181,
> +     2060,   2460,   2428,   2195,
> +     3216,   3271,   5120,   6793,
> +     2509,   3054,   2928,   2664,
> +     3958,   4181,   6793,   9550,
> +    },
> +};
> +
> +static uint8_t bink2g_chroma_cbp_pat[16] = {
> +    0x00, 0x00, 0x00, 0x0F,
> +    0x00, 0x0F, 0x0F, 0x0F,
> +    0x00, 0x0F, 0x0F, 0x0F,
> +    0x0F, 0x0F, 0x0F, 0x0F,
> +};
> +
> +static const int32_t bink2g_dc_pat[] = {
> +    1024, 1218, 1448, 1722, 2048,
> +    2435, 2896, 3444, 4096, 4871,
> +    5793, 6889, 8192, 9742, 11585, 13777, 16384,
> +    19484, 23170,  27555, 32768, 38968, 46341,
> +    55109, 65536, 77936, 92682, 110218, 131072,
> +    155872, 185364, 220436, 262144, 311744,
> +    370728, 440872, 524288,
> +};
> +
> +static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };
> +
> +static const uint8_t bink2f_quant_codes[16] = {
> +    0x01, 0x02, 0x04, 0x08, 0x10, 0x30, 0x50, 0x70,
> +    0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0,
> +};
> +
> +static const uint8_t bink2f_quant_bits[16] = {
> +    1, 2, 3, 4, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
> +};
> +
> +static const uint16_t bink2f_ac_val_codes[2][13] = {
> +    {
> +        0x04, 0x01, 0x02, 0x00, 0x08, 0x18, 0xF8, 0x178, 0x138,
> +        0x38, 0x1B8, 0x78, 0xB8
> +    },
> +    {
> +        0x0A, 0x01, 0x04, 0x08, 0x06, 0x00, 0x02, 0x1A, 0x2A,
> +        0x16A, 0x1EA, 0x6A, 0xEA
> +    },
> +};
> +
> +static const uint8_t bink2f_ac_val_bits[2][13] = {
> +    { 3, 1, 2, 4, 5, 6, 8, 9, 9, 9, 9, 9, 9 },
> +    { 6, 1, 3, 4, 3, 4, 4, 5, 7, 9, 9, 9, 9 },
> +};
> +
> +#define NUM_AC_SKIPS 14
> +static const uint16_t bink2f_ac_skip_codes[2][NUM_AC_SKIPS] = {
> +    {
> +        0x00, 0x01, 0x0D, 0x15, 0x45, 0x85, 0xA5, 0x165,
> +        0x65, 0x1E5, 0xE5, 0x25, 0x03, 0x05
> +    },
> +    {
> +        0x00, 0x01, 0x03, 0x07, 0x1F, 0x1B, 0x0F, 0x2F,
> +        0x5B, 0xDB, 0x1DB, 0x3B, 0x05, 0x0B
> +    }
> +};
> +
> +static const uint8_t bink2f_ac_skip_bits[2][NUM_AC_SKIPS] = {
> +    { 1, 3, 4, 5, 7, 8, 8, 9, 9, 9, 9, 8, 2, 8 },
> +    { 1, 3, 4, 4, 5, 7, 6, 6, 8, 9, 9, 6, 3, 5 }
> +};
> +
> +static const uint8_t bink2f_skips[] = {
> +    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 62, 0, 0, 0,
> +};
> +
> +static const uint8_t bink2g_skips[] = {
> +    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0,
> +};
> +
> +static const uint8_t bink2f_next_skips[] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
> +};
> +
> +static const uint8_t bink2_next_skips[] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
> +};
> +
> +static const uint16_t bink2g_ac_skip_codes[2][NUM_AC_SKIPS] = {
> +    {
> +        0x01, 0x00, 0x004, 0x02C, 0x06C, 0x0C, 0x4C,
> +        0xAC, 0xEC, 0x12C, 0x16C, 0x1AC, 0x02, 0x1C,
> +    },
> +    {
> +        0x01, 0x04, 0x00, 0x08, 0x02, 0x32, 0x0A,
> +        0x12, 0x3A, 0x7A, 0xFA, 0x72, 0x06, 0x1A,
> +    },
> +};
> +
> +static const uint8_t bink2g_ac_skip_bits[2][NUM_AC_SKIPS] = {
> +    { 1, 3, 4, 9, 9, 7, 7, 9, 8, 9, 9, 9, 2, 5 },
> +    { 1, 3, 4, 4, 5, 7, 5, 6, 7, 8, 8, 7, 3, 6 },
> +};
> +
> +static const uint8_t bink2g_mv_codes[] = {
> +    0x01, 0x06, 0x0C, 0x1C, 0x18, 0x38, 0x58, 0x78,
> +    0x68, 0x48, 0x28, 0x08, 0x14, 0x04, 0x02, 0x00,
> +};
> +
> +static const uint8_t bink2g_mv_bits[] = {
> +    1, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 3, 4,
> +};
> +
> +static const float bink2f_dc_quant[16] = {
> +    4, 4, 4, 4, 4, 6, 7, 8, 10, 12, 16, 24, 32, 48, 64, 128
> +};
> +
> +static const float bink2f_ac_quant[16] = {
> +    1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 6.0, 7.0, 8.0, 12.0, 16.0, 24.0, 32.0,
> 48.0, 64.0, 128.0
> +};
> +
> +static const float bink2f_luma_intra_qmat[64] = {
> +    0.125,    0.190718, 0.16332,  0.235175, 0.3,      0.392847, 0.345013,
> 0.210373,
> +    0.208056, 0.288582, 0.317145, 0.387359, 0.450788, 0.790098, 0.562995,
> 0.263095,
> +    0.228649, 0.294491, 0.341421, 0.460907, 0.653281, 0.731424, 0.60988,
> 0.252336,
> +    0.205778, 0.346585, 0.422498, 0.501223, 0.749621, 1.004719, 0.636379,
> 0.251428,
> +    0.225,    0.381436, 0.604285, 0.823113, 0.85,     1.070509, 0.69679,
> 0.265553,
> +    0.235708, 0.476783, 0.70576,  0.739104, 0.795516, 0.802512, 0.600616,
> 0.249289,
> +    0.331483, 0.600528, 0.689429, 0.692062, 0.69679,  0.643138, 0.43934,
> 0.188511,
> +    0.248309, 0.440086, 0.42807,  0.397419, 0.386259, 0.270966, 0.192244,
> 0.094199,
> +};
> +
> +static const float bink2f_luma_inter_qmat[64] = {
> +    0.125,    0.17338,  0.16332,  0.146984, 0.128475, 0.106393, 0.077046,
> 0.043109,
> +    0.17338,  0.240485, 0.226532, 0.203873, 0.1782,   0.147571, 0.109474,
> 0.062454,
> +    0.16332,  0.226532, 0.219321, 0.202722, 0.181465, 0.149711, 0.112943,
> 0.062584,
> +    0.146984, 0.203873, 0.202722, 0.201647, 0.183731, 0.153976, 0.11711,
> 0.065335,
> +    0.128475, 0.1782,   0.181465, 0.183731, 0.177088, 0.155499, 0.120267,
> 0.068016,
> +    0.106393, 0.147571, 0.149711, 0.153976, 0.155499, 0.145756, 0.116636,
> 0.068495,
> +    0.077046, 0.109474, 0.112943, 0.11711,  0.120267, 0.116636, 0.098646,
> 0.060141,
> +    0.043109, 0.062454, 0.062584, 0.065335, 0.068016, 0.068495, 0.060141,
> 0.038853,
> +};
> +
> +static const float bink2f_chroma_qmat[64] = {
> +    0.125,      0.17338,    0.217761,   0.383793,   0.6875,
>  0.54016501, 0.37207201, 0.18968099,
> +    0.17338,    0.28056601, 0.32721299, 0.74753499, 0.95358998,
> 0.74923098, 0.51607901, 0.26309499,
> +    0.217761,   0.32721299, 0.66387498, 1.056244,   0.89826202, 0.70576,
>   0.48613599, 0.24783,
> +    0.383793,   0.74753499, 1.056244,   0.95059502, 0.80841398,
> 0.635167,   0.437511,   0.223041,
> +    0.6875,     0.95358998, 0.89826202, 0.80841398, 0.6875,
>  0.54016501, 0.37207201, 0.18968099,
> +    0.54016501, 0.74923098, 0.70576,    0.635167,   0.54016501,
> 0.42440501, 0.292335,   0.149031,
> +    0.37207201, 0.51607901, 0.48613599, 0.437511,   0.37207201,
> 0.292335,   0.201364,   0.102655,
> +    0.18968099, 0.26309499, 0.24783,    0.223041,   0.18968099,
> 0.149031,   0.102655,   0.052333001
> +};
> +
> +static const uint8_t bink2f_luma_scan[64] = {
> +     0,  2,  1,  8,  9, 17, 10, 16,
> +    24,  3, 18, 25, 32, 11, 33, 26,
> +     4, 40, 19, 12, 27, 41, 34,  5,
> +    20, 48,  6, 28, 15, 42, 23, 35,
> +    21, 13, 14,  7, 31, 43, 49, 36,
> +    22, 56, 39, 50, 30, 44, 29, 51,
> +    57, 47, 58, 59, 63, 61, 55, 38,
> +    52, 62, 45, 37, 60, 46, 54, 53
> +};
> +
> +static const uint8_t bink2f_chroma_scan[64] = {
> +     0,  1,  8,  2,  9, 16, 10, 17,
> +     3, 24, 11, 18, 25, 13, 14,  4,
> +    15,  5,  6,  7, 12, 19, 20, 21,
> +    22, 23, 26, 27, 28, 29, 30, 31,
> +    32, 33, 34, 35, 36, 37, 38, 39,
> +    40, 41, 42, 43, 44, 45, 46, 47,
> +    48, 49, 50, 51, 52, 53, 54, 55,
> +    56, 57, 58, 59, 60, 61, 62, 63
> +};
> +
> +static const uint8_t bink2g_scan[64] = {
> +     0,   8,   1,   2,  9,  16,  24,  17,
> +    10,   3,   4,  11, 18,  25,  32,  40,
> +    33,  26,  19,  12,  5,   6,  13,  20,
> +    27,  34,  41,  48, 56,  49,  42,  35,
> +    28,  21,  14,   7, 15,  22,  29,  36,
> +    43,  50,  57,  58, 51,  44,  37,  30,
> +    23,  31,  38,  45, 52,  59,  60,  53,
> +    46,  39,  47,  54, 61,  62,  55,  63,
> +};
> +
> +typedef struct QuantPredict {
> +    int8_t intra_q;
> +    int8_t inter_q;
> +} QuantPredict;
> +
> +typedef struct DCPredict {
> +    float dc[4][16];
> +    int   block_type;
> +} DCPredict;
> +
> +typedef struct DCIPredict {
> +    int dc[4][16];
> +    int block_type;
> +} DCIPredict;
> +
> +typedef struct MVectors {
> +    int v[4][2];
> +    int nb_vectors;
> +} MVectors;
> +
> +typedef struct MVPredict {
> +    MVectors mv;
> +} MVPredict;
> +
> +/*
> + * Decoder context
> + */
> +typedef struct Bink2Context {
> +    AVCodecContext  *avctx;
> +    GetBitContext   gb;
> +    BlockDSPContext dsp;
> +    AVFrame         *last;
> +    int             version;              ///< internal Bink file version
> +    int             has_alpha;
> +
> +    DECLARE_ALIGNED(16, float, block[4][64]);
> +    DECLARE_ALIGNED(16, int16_t, iblock[4][64]);
> +
> +    QuantPredict    *current_q;
> +    QuantPredict    *prev_q;
> +
> +    DCPredict       *current_dc;
> +    DCPredict       *prev_dc;
> +
> +    DCIPredict      *current_idc;
> +    DCIPredict      *prev_idc;
> +
> +    MVPredict       *current_mv;
> +    MVPredict       *prev_mv;
> +
> +    uint8_t         *col_cbp;
> +    uint8_t         *row_cbp;
> +
> +    int             num_slices;
> +    int             slice_height[4];
> +
> +    int             comp;
> +    int             mb_pos;
> +    unsigned        flags;
> +    unsigned        frame_flags;
> +} Bink2Context;
> +
> +/**
> + * Bink2 video block types
> + */
> +enum BlockTypes {
> +    INTRA_BLOCK = 0, ///< intra DCT block
> +    SKIP_BLOCK,      ///< skipped block
> +    MOTION_BLOCK,    ///< block is copied from previous frame with some
> offset
> +    RESIDUE_BLOCK,   ///< motion block with some difference added
> +};
> +
> +static const uint8_t ones_count[16] = {
> +    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
> +};
> +
> +#include "bink2f.c"
> +#include "bink2g.c"
> +
> +static 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, void *data,
> +                              int *got_frame, AVPacket *pkt)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +    GetBitContext *gb = &c->gb;
> +    AVFrame *frame = data;
> +    uint8_t *dst[4];
> +    uint8_t *src[4];
> +    int stride[4];
> +    int sstride[4];
> +    uint32_t off = 0;
> +    int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY);
> +    int ret, w, h;
> +    int height_a;
> +
> +    w = avctx->width;
> +    h = avctx->height;
> +    ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32));
> +    if (ret < 0)
> +        return ret;
> +    avctx->width  = w;
> +    avctx->height = h;
> +
> +    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
> +        return ret;
> +
> +    for (int i = 0; i < 4; i++) {
> +        src[i]     = c->last->data[i];
> +        dst[i]     = frame->data[i];
> +        stride[i]  = frame->linesize[i];
> +        sstride[i] = c->last->linesize[i];
> +    }
> +
> +    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 av_cold int bink2_decode_end(AVCodecContext *avctx)
> +{
> +    Bink2Context * const c = avctx->priv_data;
> +
> +    av_frame_free(&c->last);
> +    av_freep(&c->current_q);
> +    av_freep(&c->prev_q);
> +    av_freep(&c->current_dc);
> +    av_freep(&c->prev_dc);
> +    av_freep(&c->current_idc);
> +    av_freep(&c->prev_idc);
> +    av_freep(&c->current_mv);
> +    av_freep(&c->prev_mv);
> +    av_freep(&c->col_cbp);
> +    av_freep(&c->row_cbp);
> +
> +    return 0;
> +}
> +
> +AVCodec ff_bink2_decoder = {
> +    .name           = "binkvideo2",
> +    .long_name      = NULL_IF_CONFIG_SMALL("Bink video 2"),
> +    .type           = AVMEDIA_TYPE_VIDEO,
> +    .id             = AV_CODEC_ID_BINKVIDEO2,
> +    .priv_data_size = sizeof(Bink2Context),
> +    .init           = bink2_decode_init,
> +    .close          = bink2_decode_end,
> +    .decode         = bink2_decode_frame,
> +    .capabilities   = AV_CODEC_CAP_DR1,
> +};
>

could be wrong, but the decode_end seems to clean memory correctly, so you
could add the internal capabilitiy that cleans memory on init error.
Peter Ross March 21, 2020, 3:32 a.m. UTC | #3
On Fri, Mar 20, 2020 at 02:31:05PM +0100, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3203 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c

> --- /dev/null
> +++ b/libavcodec/bink2.c
> @@ -0,0 +1,869 @@
> +/*
> + * Bink video 2 decoder
> + * Copyright (c) 2014 Konstantin Shishkov
> + * Copyright (c) 2019 Paul B Mahol
> + *
> + * This file is part of FFmpeg.

this is awesome guys!


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

identical to libavcodec/msvideo1enc.c: remap[16]


> +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,
> +};

libavcodec/diractab.c: ff_dirac_qscale_tab[]


> +static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };

libavcodec/vble.c: LUT[256]


> +static const uint8_t bink2f_next_skips[] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
> +};
> +
> +static const uint8_t bink2_next_skips[] = {
> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
>

bink2f_next_skips and bink2_next_skips are identical. can you double check?


> +static const uint8_t ones_count[16] = {
> +    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
> +};

libavcodec/vc1_mc.c: popcount4[16]


-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
James Almer March 21, 2020, 4:11 a.m. UTC | #4
On 3/20/2020 10:31 AM, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3203 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c
> 
> diff --git a/configure b/configure
> index 18f2841765..1d89d49b41 100755
> --- a/configure
> +++ b/configure
> @@ -2678,6 +2678,7 @@ atrac3pal_decoder_select="mdct sinewin"
>  atrac9_decoder_select="mdct"
>  avrn_decoder_select="exif jpegtables"
>  bink_decoder_select="blockdsp hpeldsp"
> +bink2_decoder_select="blockdsp"
>  binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
>  binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
>  cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index c1c9a44f2b..a79b4c6524 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -230,6 +230,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 b3184af954..d032547a9d 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -60,6 +60,7 @@ extern AVCodec ff_ayuv_decoder;
>  extern AVCodec ff_bethsoftvid_decoder;
>  extern AVCodec ff_bfi_decoder;
>  extern AVCodec ff_bink_decoder;
> +extern AVCodec ff_bink2_decoder;
>  extern AVCodec ff_bitpacked_decoder;
>  extern AVCodec ff_bmp_encoder;
>  extern AVCodec ff_bmp_decoder;
> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
> index 78c483c25c..e8b20fa527 100644
> --- a/libavcodec/avcodec.h
> +++ b/libavcodec/avcodec.h
> @@ -463,6 +463,7 @@ enum AVCodecID {
>      AV_CODEC_ID_MVDV,
>      AV_CODEC_ID_MVHA,
>      AV_CODEC_ID_CDTOONS,
> +    AV_CODEC_ID_BINKVIDEO2,
>  
>      /* various PCM "codecs" */
>      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
> diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
> new file mode 100644
> index 0000000000..0ebce7feeb
> --- /dev/null
> +++ b/libavcodec/bink2.c
> @@ -0,0 +1,869 @@
> +/*
> + * 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 "copy_block.h"
> +#include "idctdsp.h"

Seems unused.

> +#include "internal.h"
> +#include "mathops.h"
> +
> +#define BITSTREAM_READER_LE
> +#include "get_bits.h"
> +#include "unary.h"

[...]

> +#include "bink2f.c"
> +#include "bink2g.c"

You should compile these separately, and share the functions that are
directly called in bink2.c
Also, move the bink2f and bink2g tables to their corresponding files.
Paul B Mahol March 21, 2020, 9:26 a.m. UTC | #5
I do not plan to remove any of this,

So please refrain from posting such "reviews".

On 3/21/20, Peter Ross <pross@xvid.org> wrote:
> On Fri, Mar 20, 2020 at 02:31:05PM +0100, Paul B Mahol wrote:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>  configure               |    1 +
>>  libavcodec/Makefile     |    1 +
>>  libavcodec/allcodecs.c  |    1 +
>>  libavcodec/avcodec.h    |    1 +
>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>>  libavcodec/codec_desc.c |    7 +
>>  libavformat/bink.c      |    3 +-
>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>  create mode 100644 libavcodec/bink2.c
>>  create mode 100644 libavcodec/bink2f.c
>>  create mode 100644 libavcodec/bink2g.c
>
>> --- /dev/null
>> +++ b/libavcodec/bink2.c
>> @@ -0,0 +1,869 @@
>> +/*
>> + * Bink video 2 decoder
>> + * Copyright (c) 2014 Konstantin Shishkov
>> + * Copyright (c) 2019 Paul B Mahol
>> + *
>> + * This file is part of FFmpeg.
>
> this is awesome guys!
>
>
>> +static const uint8_t luma_repos[] = {
>> +    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
>> +};
>
> identical to libavcodec/msvideo1enc.c: remap[16]
>
>
>> +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,
>> +};
>
> libavcodec/diractab.c: ff_dirac_qscale_tab[]
>
>
>> +static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };
>
> libavcodec/vble.c: LUT[256]
>
>
>> +static const uint8_t bink2f_next_skips[] = {
>> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
>> +};
>> +
>> +static const uint8_t bink2_next_skips[] = {
>> +    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
>>
>
> bink2f_next_skips and bink2_next_skips are identical. can you double check?
>
>
>> +static const uint8_t ones_count[16] = {
>> +    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
>> +};
>
> libavcodec/vc1_mc.c: popcount4[16]
>
>
> -- Peter
> (A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
>
Jan Ekström March 21, 2020, 11 a.m. UTC | #6
On Sat, Mar 21, 2020 at 11:27 AM Paul B Mahol <onemda@gmail.com> wrote:
>
> I do not plan to remove any of this,
>
> So please refrain from posting such "reviews".
>

While I have respect for your technical capabilities, can you please
refrain from behaving in such a toxic and off-putting manner?

Someone clearly took the effort to find things, and as far as I can
see it is a valid review.

If you have some actual reasons behind your response, please write
them down instead of writing what essentially can be read as "go
away".

If you are having anger/emotional issues - please just step away from
the computer. It probably does not help your or others if you insult
and/or belittle others.

Best regards,
Jan
Paul B Mahol March 21, 2020, 11:30 a.m. UTC | #7
On 3/21/20, Jan Ekström <jeebjp@gmail.com> wrote:
> On Sat, Mar 21, 2020 at 11:27 AM Paul B Mahol <onemda@gmail.com> wrote:
>>
>> I do not plan to remove any of this,
>>
>> So please refrain from posting such "reviews".
>>
>
> While I have respect for your technical capabilities, can you please
> refrain from behaving in such a toxic and off-putting manner?
>
> Someone clearly took the effort to find things, and as far as I can
> see it is a valid review.
>
> If you have some actual reasons behind your response, please write
> them down instead of writing what essentially can be read as "go
> away".
>
> If you are having anger/emotional issues - please just step away from
> the computer. It probably does not help your or others if you insult
> and/or belittle others.


I'm not gonna remove those tables, no matter how "valid" your comments are.

>
> Best regards,
> Jan
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Jan Ekström March 21, 2020, 11:36 a.m. UTC | #8
On Sat, Mar 21, 2020 at 1:30 PM Paul B Mahol <onemda@gmail.com> wrote:
>
> On 3/21/20, Jan Ekström <jeebjp@gmail.com> wrote:
> > On Sat, Mar 21, 2020 at 11:27 AM Paul B Mahol <onemda@gmail.com> wrote:
> >>
> >> I do not plan to remove any of this,
> >>
> >> So please refrain from posting such "reviews".
> >>
> >
> > While I have respect for your technical capabilities, can you please
> > refrain from behaving in such a toxic and off-putting manner?
> >
> > Someone clearly took the effort to find things, and as far as I can
> > see it is a valid review.
> >
> > If you have some actual reasons behind your response, please write
> > them down instead of writing what essentially can be read as "go
> > away".
> >
> > If you are having anger/emotional issues - please just step away from
> > the computer. It probably does not help your or others if you insult
> > and/or belittle others.
>
>
> I'm not gonna remove those tables, no matter how "valid" your comments are.
>

Then just explain yourself, please. That is all I'm asking for.

Jan
Jan Ekström March 21, 2020, 11:47 a.m. UTC | #9
On Fri, Mar 20, 2020 at 3:31 PM Paul B Mahol <onemda@gmail.com> wrote:
>
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---

I am not sure how well I'd be able to review the technicalities, and
thus I only have the following requests:
- Since I didn't see a mention of the current limitations of this
implementation (such as the lack of deblocking that you mentioned on
IRC), please at the very least mention that in the commit message.
- Is it possible to get a FATE test for this, or would you like
someone else do generate such? If you would like someone else to
generate the reference for you, do you know of any nice wrapper on top
of the RAD Bink2 DLLs to dump YCbCr reference pictures so our
comparison would be against the reference?

Best regards,
Jan
Paul B Mahol March 21, 2020, 11:51 a.m. UTC | #10
On 3/21/20, Jan Ekström <jeebjp@gmail.com> wrote:
> On Fri, Mar 20, 2020 at 3:31 PM Paul B Mahol <onemda@gmail.com> wrote:
>>
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>
> I am not sure how well I'd be able to review the technicalities, and
> thus I only have the following requests:
> - Since I didn't see a mention of the current limitations of this
> implementation (such as the lack of deblocking that you mentioned on
> IRC), please at the very least mention that in the commit message.
> - Is it possible to get a FATE test for this, or would you like
> someone else do generate such? If you would like someone else to
> generate the reference for you, do you know of any nice wrapper on top
> of the RAD Bink2 DLLs to dump YCbCr reference pictures so our
> comparison would be against the reference?

The RAD Bink2 tool support this last time I tried, you just need to
use lossless encoder, like utvideo.

>
> Best regards,
> Jan
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Nicolas George March 21, 2020, 12:56 p.m. UTC | #11
Paul B Mahol (12020-03-21):
> I'm not gonna remove those tables, no matter how "valid" your comments are.

Then you're not gonna apply this patch either. That's how a collective
project works.
Paul B Mahol March 21, 2020, 1:17 p.m. UTC | #12
On 3/21/20, Nicolas George <george@nsup.org> wrote:
> Paul B Mahol (12020-03-21):
>> I'm not gonna remove those tables, no matter how "valid" your comments
>> are.
>
> Then you're not gonna apply this patch either. That's how a collective
> project works.

I'm not listening to your comments.

>
> --
>   Nicolas George
>
Paul B Mahol March 21, 2020, 5:02 p.m. UTC | #13
On 3/21/20, James Almer <jamrial@gmail.com> wrote:
> On 3/20/2020 10:31 AM, Paul B Mahol wrote:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>  configure               |    1 +
>>  libavcodec/Makefile     |    1 +
>>  libavcodec/allcodecs.c  |    1 +
>>  libavcodec/avcodec.h    |    1 +
>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>>  libavcodec/codec_desc.c |    7 +
>>  libavformat/bink.c      |    3 +-
>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>  create mode 100644 libavcodec/bink2.c
>>  create mode 100644 libavcodec/bink2f.c
>>  create mode 100644 libavcodec/bink2g.c
>>
>> diff --git a/configure b/configure
>> index 18f2841765..1d89d49b41 100755
>> --- a/configure
>> +++ b/configure
>> @@ -2678,6 +2678,7 @@ atrac3pal_decoder_select="mdct sinewin"
>>  atrac9_decoder_select="mdct"
>>  avrn_decoder_select="exif jpegtables"
>>  bink_decoder_select="blockdsp hpeldsp"
>> +bink2_decoder_select="blockdsp"
>>  binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
>>  binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
>>  cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
>> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
>> index c1c9a44f2b..a79b4c6524 100644
>> --- a/libavcodec/Makefile
>> +++ b/libavcodec/Makefile
>> @@ -230,6 +230,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 b3184af954..d032547a9d 100644
>> --- a/libavcodec/allcodecs.c
>> +++ b/libavcodec/allcodecs.c
>> @@ -60,6 +60,7 @@ extern AVCodec ff_ayuv_decoder;
>>  extern AVCodec ff_bethsoftvid_decoder;
>>  extern AVCodec ff_bfi_decoder;
>>  extern AVCodec ff_bink_decoder;
>> +extern AVCodec ff_bink2_decoder;
>>  extern AVCodec ff_bitpacked_decoder;
>>  extern AVCodec ff_bmp_encoder;
>>  extern AVCodec ff_bmp_decoder;
>> diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
>> index 78c483c25c..e8b20fa527 100644
>> --- a/libavcodec/avcodec.h
>> +++ b/libavcodec/avcodec.h
>> @@ -463,6 +463,7 @@ enum AVCodecID {
>>      AV_CODEC_ID_MVDV,
>>      AV_CODEC_ID_MVHA,
>>      AV_CODEC_ID_CDTOONS,
>> +    AV_CODEC_ID_BINKVIDEO2,
>>
>>      /* various PCM "codecs" */
>>      AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at
>> the start of audio codecs
>> diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
>> new file mode 100644
>> index 0000000000..0ebce7feeb
>> --- /dev/null
>> +++ b/libavcodec/bink2.c
>> @@ -0,0 +1,869 @@
>> +/*
>> + * 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 "copy_block.h"
>> +#include "idctdsp.h"
>
> Seems unused.
>
>> +#include "internal.h"
>> +#include "mathops.h"
>> +
>> +#define BITSTREAM_READER_LE
>> +#include "get_bits.h"
>> +#include "unary.h"
>
> [...]
>
>> +#include "bink2f.c"
>> +#include "bink2g.c"
>
> You should compile these separately, and share the functions that are
> directly called in bink2.c

You are not in position to tell me what I should do or what should I do not.
Also this two lines are gonna to stay.

> Also, move the bink2f and bink2g tables to their corresponding files.

Done.

> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
Peter Ross March 21, 2020, 11:08 p.m. UTC | #14
On Fri, Mar 20, 2020 at 02:31:05PM +0100, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3203 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c

> +++ b/libavcodec/bink2.c
> @@ -0,0 +1,869 @@
> +/*
> + * Bink video 2 decoder
> + * Copyright (c) 2014 Konstantin Shishkov
> + * Copyright (c) 2019 Paul B Mahol
> + *
> + * This file is part of FFmpeg.
> + *

> +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];

comp is only used for dc coeff predicition
suggestion: pass comp value via stack

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

imho too many compound if expressions against is_luma and flags
(i prefered the way you do this in bink2f_predict_mv)

> +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]);

> +            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);

c->comp required for MOTION_BLOCK?


> +            default:
> +                return AVERROR_INVALIDDATA;

use goto fail. decoder may have already invoked simd functions.

> +            }
> +        }
> +
> +        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;
> +}


> --- /dev/null
> +++ b/libavcodec/bink2g.c
> @@ -0,0 +1,1197 @@
> +/*

> +static void bink2g_predict_dc(Bink2Context *c,
> +                              int is_luma, int mindc, int maxdc,
> +                              int flags, int tdc[16])
> +{

see bink2f_predict_dc comments

> +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));

tdc[16] = { 0 } like you did elsewhere

> +    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);

sizeof(**block)

> +    if ((cbp & 0xf) == 0)
> +        return 0;
> +

can fold memset into loop below

> +    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;
> +

> +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]);

> +            default:
> +                return AVERROR_INVALIDDATA;

goto fail

> +            }
> +        }
> +
> +        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;
> +}

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
Paul B Mahol April 6, 2020, 10:01 a.m. UTC | #15
On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3203 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c
>

Will apply soon!
James Almer April 6, 2020, 2:10 p.m. UTC | #16
On 4/6/2020 7:01 AM, Paul B Mahol wrote:
> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> ---
>>  configure               |    1 +
>>  libavcodec/Makefile     |    1 +
>>  libavcodec/allcodecs.c  |    1 +
>>  libavcodec/avcodec.h    |    1 +
>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>>  libavcodec/codec_desc.c |    7 +
>>  libavformat/bink.c      |    3 +-
>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>  create mode 100644 libavcodec/bink2.c
>>  create mode 100644 libavcodec/bink2f.c
>>  create mode 100644 libavcodec/bink2g.c
>>
> 
> Will apply soon!

You need to first send an updated patch with the bug/leak fixes that
people reported applied, so it can be confirmed they are ok.
Paul B Mahol April 6, 2020, 2:27 p.m. UTC | #17
On 4/6/20, James Almer <jamrial@gmail.com> wrote:
> On 4/6/2020 7:01 AM, Paul B Mahol wrote:
>> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>>> ---
>>>  configure               |    1 +
>>>  libavcodec/Makefile     |    1 +
>>>  libavcodec/allcodecs.c  |    1 +
>>>  libavcodec/avcodec.h    |    1 +
>>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>>>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>>>  libavcodec/codec_desc.c |    7 +
>>>  libavformat/bink.c      |    3 +-
>>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>>  create mode 100644 libavcodec/bink2.c
>>>  create mode 100644 libavcodec/bink2f.c
>>>  create mode 100644 libavcodec/bink2g.c
>>>
>>
>> Will apply soon!
>
> You need to first send an updated patch with the bug/leak fixes that
> people reported applied, so it can be confirmed they are ok.

I fixed all bugs. gonna apply ASAP!
Anton Khirnov April 7, 2020, 2:25 p.m. UTC | #18
Quoting Paul B Mahol (2020-04-06 16:27:54)
> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
> > On 4/6/2020 7:01 AM, Paul B Mahol wrote:
> >> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
> >>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> >>> ---
> >>>  configure               |    1 +
> >>>  libavcodec/Makefile     |    1 +
> >>>  libavcodec/allcodecs.c  |    1 +
> >>>  libavcodec/avcodec.h    |    1 +
> >>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
> >>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
> >>>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
> >>>  libavcodec/codec_desc.c |    7 +
> >>>  libavformat/bink.c      |    3 +-
> >>>  9 files changed, 3203 insertions(+), 2 deletions(-)
> >>>  create mode 100644 libavcodec/bink2.c
> >>>  create mode 100644 libavcodec/bink2f.c
> >>>  create mode 100644 libavcodec/bink2g.c
> >>>
> >>
> >> Will apply soon!
> >
> > You need to first send an updated patch with the bug/leak fixes that
> > people reported applied, so it can be confirmed they are ok.
> 
> I fixed all bugs. gonna apply ASAP!

This behaviour is utterly unacceptable.
Paul B Mahol April 7, 2020, 2:29 p.m. UTC | #19
On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
> Quoting Paul B Mahol (2020-04-06 16:27:54)
>> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
>> > On 4/6/2020 7:01 AM, Paul B Mahol wrote:
>> >> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>> >>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> >>> ---
>> >>>  configure               |    1 +
>> >>>  libavcodec/Makefile     |    1 +
>> >>>  libavcodec/allcodecs.c  |    1 +
>> >>>  libavcodec/avcodec.h    |    1 +
>> >>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>> >>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>> >>>  libavcodec/bink2g.c     | 1197
>> >>> +++++++++++++++++++++++++++++++++++++++
>> >>>  libavcodec/codec_desc.c |    7 +
>> >>>  libavformat/bink.c      |    3 +-
>> >>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>> >>>  create mode 100644 libavcodec/bink2.c
>> >>>  create mode 100644 libavcodec/bink2f.c
>> >>>  create mode 100644 libavcodec/bink2g.c
>> >>>
>> >>
>> >> Will apply soon!
>> >
>> > You need to first send an updated patch with the bug/leak fixes that
>> > people reported applied, so it can be confirmed they are ok.
>>
>> I fixed all bugs. gonna apply ASAP!
>
> This behaviour is utterly unacceptable.
>

You wish, you ignore fact that I lost so much time in developing this decoder,
to need tolerate such bikesheds from "friendly" developers.

Such arrogance and fake transparency including censorship are uncalled for.

If you are new dictator/leader of FFmpeg I do not want to be part of
such community any more.
James Almer April 7, 2020, 2:33 p.m. UTC | #20
On 4/7/2020 11:29 AM, Paul B Mahol wrote:
> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
>> Quoting Paul B Mahol (2020-04-06 16:27:54)
>>> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
>>>> On 4/6/2020 7:01 AM, Paul B Mahol wrote:
>>>>> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>>>>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>>>>>> ---
>>>>>>  configure               |    1 +
>>>>>>  libavcodec/Makefile     |    1 +
>>>>>>  libavcodec/allcodecs.c  |    1 +
>>>>>>  libavcodec/avcodec.h    |    1 +
>>>>>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>>>>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>>>>>>  libavcodec/bink2g.c     | 1197
>>>>>> +++++++++++++++++++++++++++++++++++++++
>>>>>>  libavcodec/codec_desc.c |    7 +
>>>>>>  libavformat/bink.c      |    3 +-
>>>>>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>>>>>  create mode 100644 libavcodec/bink2.c
>>>>>>  create mode 100644 libavcodec/bink2f.c
>>>>>>  create mode 100644 libavcodec/bink2g.c
>>>>>>
>>>>>
>>>>> Will apply soon!
>>>>
>>>> You need to first send an updated patch with the bug/leak fixes that
>>>> people reported applied, so it can be confirmed they are ok.
>>>
>>> I fixed all bugs. gonna apply ASAP!
>>
>> This behaviour is utterly unacceptable.
>>
> 
> You wish, you ignore fact that I lost so much time in developing this decoder,
> to need tolerate such bikesheds from "friendly" developers.
> 
> Such arrogance and fake transparency including censorship are uncalled for.
> 
> If you are new dictator/leader of FFmpeg I do not want to be part of
> such community any more.

Paul, please, don't turn every single patch you send into drama for no
reason at all. It's exhausting.
All the reviews you got for this were very simple and not bikesheds.
Just resend the patch you say has all the issues fixed before pushing
it, and lets move on.
Jean-Baptiste Kempf April 7, 2020, 2:40 p.m. UTC | #21
On Tue, Apr 7, 2020, at 16:29, Paul B Mahol wrote:
> If you are new dictator/leader of FFmpeg

There is no dictator and there should not be one.

If there was one leader, it would be Michael, because of his involvement  and longevity in the project.
He denied that role, which is why we're replacing with democracy and voting.

>  I do not want to be part of such community any more.

Blackmails of type "if you don't do as I want, I will leave" have been tested since a long time on numerous OSS projects and here, and it never works.
Anton Khirnov April 7, 2020, 3:27 p.m. UTC | #22
Quoting Paul B Mahol (2020-04-07 16:29:23)
> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
> > Quoting Paul B Mahol (2020-04-06 16:27:54)
> >> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
> >> > On 4/6/2020 7:01 AM, Paul B Mahol wrote:
> >> >> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
> >> >>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
> >> >>> ---
> >> >>>  configure               |    1 +
> >> >>>  libavcodec/Makefile     |    1 +
> >> >>>  libavcodec/allcodecs.c  |    1 +
> >> >>>  libavcodec/avcodec.h    |    1 +
> >> >>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
> >> >>>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
> >> >>>  libavcodec/bink2g.c     | 1197
> >> >>> +++++++++++++++++++++++++++++++++++++++
> >> >>>  libavcodec/codec_desc.c |    7 +
> >> >>>  libavformat/bink.c      |    3 +-
> >> >>>  9 files changed, 3203 insertions(+), 2 deletions(-)
> >> >>>  create mode 100644 libavcodec/bink2.c
> >> >>>  create mode 100644 libavcodec/bink2f.c
> >> >>>  create mode 100644 libavcodec/bink2g.c
> >> >>>
> >> >>
> >> >> Will apply soon!
> >> >
> >> > You need to first send an updated patch with the bug/leak fixes that
> >> > people reported applied, so it can be confirmed they are ok.
> >>
> >> I fixed all bugs. gonna apply ASAP!
> >
> > This behaviour is utterly unacceptable.
> >
> 
> You wish, you ignore fact that I lost so much time in developing this decoder,

"lost"? If you consider that time lost then why did you do it at all?

> to need tolerate such bikesheds from "friendly" developers.

Why should the other developers lose their time arguing with you? Or why
should they tolerate your constant blatantly belligerent behaviour.

I should point out that reviewing is hard, time-consuming, unrewarded,
and underappreciated - yet incredibly important. You should be grateful
that people spend their time reading your code rather than attack or
disregard them.
Paul B Mahol April 7, 2020, 5:55 p.m. UTC | #23
On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
> Quoting Paul B Mahol (2020-04-07 16:29:23)
>> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
>> > Quoting Paul B Mahol (2020-04-06 16:27:54)
>> >> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
>> >> > On 4/6/2020 7:01 AM, Paul B Mahol wrote:
>> >> >> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>> >> >>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>> >> >>> ---
>> >> >>>  configure               |    1 +
>> >> >>>  libavcodec/Makefile     |    1 +
>> >> >>>  libavcodec/allcodecs.c  |    1 +
>> >> >>>  libavcodec/avcodec.h    |    1 +
>> >> >>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>> >> >>>  libavcodec/bink2f.c     | 1125
>> >> >>> ++++++++++++++++++++++++++++++++++++
>> >> >>>  libavcodec/bink2g.c     | 1197
>> >> >>> +++++++++++++++++++++++++++++++++++++++
>> >> >>>  libavcodec/codec_desc.c |    7 +
>> >> >>>  libavformat/bink.c      |    3 +-
>> >> >>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>> >> >>>  create mode 100644 libavcodec/bink2.c
>> >> >>>  create mode 100644 libavcodec/bink2f.c
>> >> >>>  create mode 100644 libavcodec/bink2g.c
>> >> >>>
>> >> >>
>> >> >> Will apply soon!
>> >> >
>> >> > You need to first send an updated patch with the bug/leak fixes that
>> >> > people reported applied, so it can be confirmed they are ok.
>> >>
>> >> I fixed all bugs. gonna apply ASAP!
>> >
>> > This behaviour is utterly unacceptable.
>> >
>>
>> You wish, you ignore fact that I lost so much time in developing this
>> decoder,
>
> "lost"? If you consider that time lost then why did you do it at all?

Because how would I know upfront that I would get so many negative reviews
which mostly nitpick stuff around?

>
>> to need tolerate such bikesheds from "friendly" developers.
>
> Why should the other developers lose their time arguing with you? Or why
> should they tolerate your constant blatantly belligerent behaviour.
>
> I should point out that reviewing is hard, time-consuming, unrewarded,
> and underappreciated - yet incredibly important. You should be grateful
> that people spend their time reading your code rather than attack or
> disregard them.
>
> --
> Anton Khirnov
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
James Almer April 7, 2020, 6:12 p.m. UTC | #24
On 4/7/2020 2:55 PM, Paul B Mahol wrote:
> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
>> Quoting Paul B Mahol (2020-04-07 16:29:23)
>>> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
>>>> Quoting Paul B Mahol (2020-04-06 16:27:54)
>>>>> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
>>>>>> On 4/6/2020 7:01 AM, Paul B Mahol wrote:
>>>>>>> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>>>>>>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>>>>>>>> ---
>>>>>>>>  configure               |    1 +
>>>>>>>>  libavcodec/Makefile     |    1 +
>>>>>>>>  libavcodec/allcodecs.c  |    1 +
>>>>>>>>  libavcodec/avcodec.h    |    1 +
>>>>>>>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>>>>>>>  libavcodec/bink2f.c     | 1125
>>>>>>>> ++++++++++++++++++++++++++++++++++++
>>>>>>>>  libavcodec/bink2g.c     | 1197
>>>>>>>> +++++++++++++++++++++++++++++++++++++++
>>>>>>>>  libavcodec/codec_desc.c |    7 +
>>>>>>>>  libavformat/bink.c      |    3 +-
>>>>>>>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>>>>>>>  create mode 100644 libavcodec/bink2.c
>>>>>>>>  create mode 100644 libavcodec/bink2f.c
>>>>>>>>  create mode 100644 libavcodec/bink2g.c
>>>>>>>>
>>>>>>>
>>>>>>> Will apply soon!
>>>>>>
>>>>>> You need to first send an updated patch with the bug/leak fixes that
>>>>>> people reported applied, so it can be confirmed they are ok.
>>>>>
>>>>> I fixed all bugs. gonna apply ASAP!
>>>>
>>>> This behaviour is utterly unacceptable.
>>>>
>>>
>>> You wish, you ignore fact that I lost so much time in developing this
>>> decoder,
>>
>> "lost"? If you consider that time lost then why did you do it at all?
> 
> Because how would I know upfront that I would get so many negative reviews
> which mostly nitpick stuff around?

Can you point what review was negative? Because what i saw was praise,
suggestions you could (and apparently did) ignore, plus bug reports.
Take for example Peter Ross' first review. It started with a line
congratulating you for writing this decoder, then mentioned a couple
tables that were duplicated and you could reuse. And what was your
reaction? Saying you'd ignore everything and calling his review useless.
Not to mention how you told me I'm "in no position to tell you what to
do" when i gave my own non-blocking suggestions. That's probably the
biggest WTF I've ever seen coming from you.

I don't know if you're trolling for fun, want attention, have trouble
reading intent on people's emails, or you truly have a distorted
perception of reality, but your fuse seemingly blows at merely being
told anything other than LGTM. And it's getting way beyond tiresome and
unacceptable.

> 
>>
>>> to need tolerate such bikesheds from "friendly" developers.
>>
>> Why should the other developers lose their time arguing with you? Or why
>> should they tolerate your constant blatantly belligerent behaviour.
>>
>> I should point out that reviewing is hard, time-consuming, unrewarded,
>> and underappreciated - yet incredibly important. You should be grateful
>> that people spend their time reading your code rather than attack or
>> disregard them.
>>
>> --
>> Anton Khirnov
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>
Paul B Mahol April 7, 2020, 6:19 p.m. UTC | #25
On 4/7/20, James Almer <jamrial@gmail.com> wrote:
> On 4/7/2020 2:55 PM, Paul B Mahol wrote:
>> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
>>> Quoting Paul B Mahol (2020-04-07 16:29:23)
>>>> On 4/7/20, Anton Khirnov <anton@khirnov.net> wrote:
>>>>> Quoting Paul B Mahol (2020-04-06 16:27:54)
>>>>>> On 4/6/20, James Almer <jamrial@gmail.com> wrote:
>>>>>>> On 4/6/2020 7:01 AM, Paul B Mahol wrote:
>>>>>>>> On 3/20/20, Paul B Mahol <onemda@gmail.com> wrote:
>>>>>>>>> Signed-off-by: Paul B Mahol <onemda@gmail.com>
>>>>>>>>> ---
>>>>>>>>>  configure               |    1 +
>>>>>>>>>  libavcodec/Makefile     |    1 +
>>>>>>>>>  libavcodec/allcodecs.c  |    1 +
>>>>>>>>>  libavcodec/avcodec.h    |    1 +
>>>>>>>>>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>>>>>>>>>  libavcodec/bink2f.c     | 1125
>>>>>>>>> ++++++++++++++++++++++++++++++++++++
>>>>>>>>>  libavcodec/bink2g.c     | 1197
>>>>>>>>> +++++++++++++++++++++++++++++++++++++++
>>>>>>>>>  libavcodec/codec_desc.c |    7 +
>>>>>>>>>  libavformat/bink.c      |    3 +-
>>>>>>>>>  9 files changed, 3203 insertions(+), 2 deletions(-)
>>>>>>>>>  create mode 100644 libavcodec/bink2.c
>>>>>>>>>  create mode 100644 libavcodec/bink2f.c
>>>>>>>>>  create mode 100644 libavcodec/bink2g.c
>>>>>>>>>
>>>>>>>>
>>>>>>>> Will apply soon!
>>>>>>>
>>>>>>> You need to first send an updated patch with the bug/leak fixes that
>>>>>>> people reported applied, so it can be confirmed they are ok.
>>>>>>
>>>>>> I fixed all bugs. gonna apply ASAP!
>>>>>
>>>>> This behaviour is utterly unacceptable.
>>>>>
>>>>
>>>> You wish, you ignore fact that I lost so much time in developing this
>>>> decoder,
>>>
>>> "lost"? If you consider that time lost then why did you do it at all?
>>
>> Because how would I know upfront that I would get so many negative reviews
>> which mostly nitpick stuff around?
>
> Can you point what review was negative? Because what i saw was praise,
> suggestions you could (and apparently did) ignore, plus bug reports.
> Take for example Peter Ross' first review. It started with a line
> congratulating you for writing this decoder, then mentioned a couple
> tables that were duplicated and you could reuse. And what was your
> reaction? Saying you'd ignore everything and calling his review useless.
> Not to mention how you told me I'm "in no position to tell you what to
> do" when i gave my own non-blocking suggestions. That's probably the
> biggest WTF I've ever seen coming from you.
>
> I don't know if you're trolling for fun, want attention, have trouble
> reading intent on people's emails, or you truly have a distorted
> perception of reality, but your fuse seemingly blows at merely being
> told anything other than LGTM. And it's getting way beyond tiresome and
> unacceptable.
>

I can not reuse tables that easily.

>>
>>>
>>>> to need tolerate such bikesheds from "friendly" developers.
>>>
>>> Why should the other developers lose their time arguing with you? Or why
>>> should they tolerate your constant blatantly belligerent behaviour.
>>>
>>> I should point out that reviewing is hard, time-consuming, unrewarded,
>>> and underappreciated - yet incredibly important. You should be grateful
>>> that people spend their time reading your code rather than attack or
>>> disregard them.
>>>
>>> --
>>> Anton Khirnov
>>> _______________________________________________
>>> ffmpeg-devel mailing list
>>> ffmpeg-devel@ffmpeg.org
>>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>>
>>> To unsubscribe, visit link above, or email
>>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel@ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
>>
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
diff mbox series

Patch

diff --git a/configure b/configure
index 18f2841765..1d89d49b41 100755
--- a/configure
+++ b/configure
@@ -2678,6 +2678,7 @@  atrac3pal_decoder_select="mdct sinewin"
 atrac9_decoder_select="mdct"
 avrn_decoder_select="exif jpegtables"
 bink_decoder_select="blockdsp hpeldsp"
+bink2_decoder_select="blockdsp"
 binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs"
 binkaudio_rdft_decoder_select="mdct rdft sinewin wma_freqs"
 cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index c1c9a44f2b..a79b4c6524 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -230,6 +230,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 b3184af954..d032547a9d 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -60,6 +60,7 @@  extern AVCodec ff_ayuv_decoder;
 extern AVCodec ff_bethsoftvid_decoder;
 extern AVCodec ff_bfi_decoder;
 extern AVCodec ff_bink_decoder;
+extern AVCodec ff_bink2_decoder;
 extern AVCodec ff_bitpacked_decoder;
 extern AVCodec ff_bmp_encoder;
 extern AVCodec ff_bmp_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 78c483c25c..e8b20fa527 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -463,6 +463,7 @@  enum AVCodecID {
     AV_CODEC_ID_MVDV,
     AV_CODEC_ID_MVHA,
     AV_CODEC_ID_CDTOONS,
+    AV_CODEC_ID_BINKVIDEO2,
 
     /* various PCM "codecs" */
     AV_CODEC_ID_FIRST_AUDIO = 0x10000,     ///< A dummy id pointing at the start of audio codecs
diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c
new file mode 100644
index 0000000000..0ebce7feeb
--- /dev/null
+++ b/libavcodec/bink2.c
@@ -0,0 +1,869 @@ 
+/*
+ * 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 "copy_block.h"
+#include "idctdsp.h"
+#include "internal.h"
+#include "mathops.h"
+
+#define BITSTREAM_READER_LE
+#include "get_bits.h"
+#include "unary.h"
+
+#define BINK_FLAG_ALPHA 0x00100000
+#define DC_MPRED(A, B, C) FFMIN(FFMAX((C) + (B) - (A), FFMIN3(A, B, C)), FFMAX3(A, B, C))
+#define DC_MPRED2(A, B) FFMIN(FFMAX((A), (B)), FFMAX(FFMIN((A), (B)), 2 * (A) - (B)))
+
+static VLC bink2f_quant_vlc;
+static VLC bink2f_ac_val0_vlc;
+static VLC bink2f_ac_val1_vlc;
+static VLC bink2f_ac_skip0_vlc;
+static VLC bink2f_ac_skip1_vlc;
+static VLC bink2g_ac_skip0_vlc;
+static VLC bink2g_ac_skip1_vlc;
+static VLC bink2g_mv_vlc;
+
+static const uint8_t kb2h_num_slices[] = {
+    2, 3, 4, 8,
+};
+
+static const uint8_t luma_repos[] = {
+    0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15,
+};
+
+static const uint16_t bink2g_luma_intra_qmat[4][64] = {
+    {
+     1024,   1432,   1506,   1181,
+     1843,   2025,   5271,   8592,
+     1313,   1669,   1630,   1672,
+     2625,   3442,   8023,  12794,
+     1076,   1755,   1808,   1950,
+     3980,   4875,   8813,  11909,
+     1350,   1868,   2127,   2016,
+     4725,   4450,   7712,   9637,
+     2458,   3103,   4303,   4303,
+     6963,   6835,  11079,  13365,
+     3375,   5704,   5052,   6049,
+     9198,   7232,  10725,   9834,
+     5486,   7521,   7797,   7091,
+    11079,  10016,  13559,  12912,
+     7279,   7649,   7020,   6097,
+     9189,   9047,  12661,  13768,
+    },
+    {
+     1218,   1703,   1791,   1405,
+     2192,   2408,   6268,  10218,
+     1561,   1985,   1938,   1988,
+     3122,   4093,   9541,  15215,
+     1279,   2087,   2150,   2319,
+     4733,   5798,  10481,  14162,
+     1606,   2222,   2530,   2398,
+     5619,   5292,   9171,  11460,
+     2923,   3690,   5117,   5118,
+     8281,   8128,  13176,  15894,
+     4014,   6783,   6008,   7194,
+    10938,   8600,  12755,  11694,
+     6524,   8944,   9272,   8433,
+    13176,  11911,  16125,  15354,
+     8657,   9096,   8348,   7250,
+    10927,  10759,  15056,  16373,
+    },
+    {
+     1448,   2025,   2130,   1671,
+     2607,   2864,   7454,  12151,
+     1856,   2360,   2305,   2364,
+     3713,   4867,  11346,  18094,
+     1521,   2482,   2557,   2758,
+     5628,   6894,  12464,  16841,
+     1909,   2642,   3008,   2852,
+     6683,   6293,  10906,  13629,
+     3476,   4388,   6085,   6086,
+     9847,   9666,  15668,  18901,
+     4773,   8066,   7145,   8555,
+    13007,  10227,  15168,  13907,
+     7758,  10637,  11026,  10028,
+    15668,  14165,  19175,  18259,
+    10294,  10817,   9927,   8622,
+    12995,  12794,  17905,  19470,
+    },
+    {
+     1722,   2408,   2533,   1987,
+     3100,   3406,   8864,  14450,
+     2208,   2807,   2741,   2811,
+     4415,   5788,  13493,  21517,
+     1809,   2951,   3041,   3280,
+     6693,   8199,  14822,  20028,
+     2271,   3142,   3578,   3391,
+     7947,   7484,  12969,  16207,
+     4133,   5218,   7236,   7238,
+    11711,  11495,  18633,  22478,
+     5677,   9592,   8497,  10174,
+    15469,  12162,  18038,  16538,
+     9226,  12649,  13112,  11926,
+    18633,  16845,  22804,  21715,
+    12242,  12864,  11806,  10254,
+    15454,  15215,  21293,  23155,
+    },
+};
+
+static const uint16_t bink2g_chroma_intra_qmat[4][64] = {
+    {
+     1024,   1193,   1434,   2203,
+     5632,   4641,   5916,   6563,
+     1193,   1622,   1811,   3606,
+     6563,   5408,   6894,   7649,
+     1434,   1811,   3515,   4875,
+     5916,   4875,   6215,   6894,
+     2203,   3606,   4875,   3824,
+     4641,   3824,   4875,   5408,
+     5632,   6563,   5916,   4641,
+     5632,   4641,   5916,   6563,
+     4641,   5408,   4875,   3824,
+     4641,   3824,   4875,   5408,
+     5916,   6894,   6215,   4875,
+     5916,   4875,   6215,   6894,
+     6563,   7649,   6894,   5408,
+     6563,   5408,   6894,   7649,
+    },
+    {
+     1218,   1419,   1706,   2620,
+     6698,   5519,   7035,   7805,
+     1419,   1929,   2153,   4288,
+     7805,   6432,   8199,   9096,
+     1706,   2153,   4180,   5798,
+     7035,   5798,   7390,   8199,
+     2620,   4288,   5798,   4548,
+     5519,   4548,   5798,   6432,
+     6698,   7805,   7035,   5519,
+     6698,   5519,   7035,   7805,
+     5519,   6432,   5798,   4548,
+     5519,   4548,   5798,   6432,
+     7035,   8199,   7390,   5798,
+     7035,   5798,   7390,   8199,
+     7805,   9096,   8199,   6432,
+     7805,   6432,   8199,   9096,
+    },
+    {
+     1448,   1688,   2028,   3116,
+     7965,   6563,   8367,   9282,
+     1688,   2294,   2561,   5099,
+     9282,   7649,   9750,  10817,
+     2028,   2561,   4971,   6894,
+     8367,   6894,   8789,   9750,
+     3116,   5099,   6894,   5408,
+     6563,   5408,   6894,   7649,
+     7965,   9282,   8367,   6563,
+     7965,   6563,   8367,   9282,
+     6563,   7649,   6894,   5408,
+     6563,   5408,   6894,   7649,
+     8367,   9750,   8789,   6894,
+     8367,   6894,   8789,   9750,
+     9282,  10817,   9750,   7649,
+     9282,   7649,   9750,  10817,
+    },
+    {
+     1722,   2007,   2412,   3706,
+     9472,   7805,   9950,  11038,
+     2007,   2729,   3045,   6064,
+    11038,   9096,  11595,  12864,
+     2412,   3045,   5912,   8199,
+     9950,   8199,  10452,  11595,
+     3706,   6064,   8199,   6432,
+     7805,   6432,   8199,   9096,
+     9472,  11038,   9950,   7805,
+     9472,   7805,   9950,  11038,
+     7805,   9096,   8199,   6432,
+     7805,   6432,   8199,   9096,
+     9950,  11595,  10452,   8199,
+     9950,   8199,  10452,  11595,
+    11038,  12864,  11595,   9096,
+    11038,   9096,  11595,  12864,
+    },
+};
+
+
+static const uint16_t bink2g_inter_qmat[4][64] = {
+    {
+     1024,   1193,   1076,    844,
+     1052,    914,   1225,   1492,
+     1193,   1391,   1254,    983,
+     1227,   1065,   1463,   1816,
+     1076,   1254,   1161,    936,
+     1195,   1034,   1444,   1741,
+      844,    983,    936,    811,
+     1055,    927,   1305,   1584,
+     1052,   1227,   1195,   1055,
+     1451,   1336,   1912,   2354,
+      914,   1065,   1034,    927,
+     1336,   1313,   1945,   2486,
+     1225,   1463,   1444,   1305,
+     1912,   1945,   3044,   4039,
+     1492,   1816,   1741,   1584,
+     2354,   2486,   4039,   5679,
+    },
+    {
+     1218,   1419,   1279,   1003,
+     1252,   1087,   1457,   1774,
+     1419,   1654,   1491,   1169,
+     1459,   1267,   1739,   2159,
+     1279,   1491,   1381,   1113,
+     1421,   1230,   1717,   2070,
+     1003,   1169,   1113,    965,
+     1254,   1103,   1552,   1884,
+     1252,   1459,   1421,   1254,
+     1725,   1589,   2274,   2799,
+     1087,   1267,   1230,   1103,
+     1589,   1562,   2313,   2956,
+     1457,   1739,   1717,   1552,
+     2274,   2313,   3620,   4803,
+     1774,   2159,   2070,   1884,
+     2799,   2956,   4803,   6753,
+    },
+    {
+     1448,   1688,   1521,   1193,
+     1488,   1293,   1732,   2110,
+     1688,   1967,   1773,   1391,
+     1735,   1507,   2068,   2568,
+     1521,   1773,   1642,   1323,
+     1690,   1462,   2042,   2462,
+     1193,   1391,   1323,   1147,
+     1492,   1311,   1845,   2241,
+     1488,   1735,   1690,   1492,
+     2052,   1889,   2704,   3328,
+     1293,   1507,   1462,   1311,
+     1889,   1857,   2751,   3515,
+     1732,   2068,   2042,   1845,
+     2704,   2751,   4306,   5712,
+     2110,   2568,   2462,   2241,
+     3328,   3515,   5712,   8031,
+    },
+    {
+     1722,   2007,   1809,   1419,
+     1770,   1537,   2060,   2509,
+     2007,   2339,   2108,   1654,
+     2063,   1792,   2460,   3054,
+     1809,   2108,   1953,   1574,
+     2010,   1739,   2428,   2928,
+     1419,   1654,   1574,   1364,
+     1774,   1559,   2195,   2664,
+     1770,   2063,   2010,   1774,
+     2440,   2247,   3216,   3958,
+     1537,   1792,   1739,   1559,
+     2247,   2209,   3271,   4181,
+     2060,   2460,   2428,   2195,
+     3216,   3271,   5120,   6793,
+     2509,   3054,   2928,   2664,
+     3958,   4181,   6793,   9550,
+    },
+};
+
+static uint8_t bink2g_chroma_cbp_pat[16] = {
+    0x00, 0x00, 0x00, 0x0F,
+    0x00, 0x0F, 0x0F, 0x0F,
+    0x00, 0x0F, 0x0F, 0x0F,
+    0x0F, 0x0F, 0x0F, 0x0F,
+};
+
+static const int32_t bink2g_dc_pat[] = {
+    1024, 1218, 1448, 1722, 2048,
+    2435, 2896, 3444, 4096, 4871,
+    5793, 6889, 8192, 9742, 11585, 13777, 16384,
+    19484, 23170,  27555, 32768, 38968, 46341,
+    55109, 65536, 77936, 92682, 110218, 131072,
+    155872, 185364, 220436, 262144, 311744,
+    370728, 440872, 524288,
+};
+
+static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 };
+
+static const uint8_t bink2f_quant_codes[16] = {
+    0x01, 0x02, 0x04, 0x08, 0x10, 0x30, 0x50, 0x70,
+    0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0,
+};
+
+static const uint8_t bink2f_quant_bits[16] = {
+    1, 2, 3, 4, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+static const uint16_t bink2f_ac_val_codes[2][13] = {
+    {
+        0x04, 0x01, 0x02, 0x00, 0x08, 0x18, 0xF8, 0x178, 0x138,
+        0x38, 0x1B8, 0x78, 0xB8
+    },
+    {
+        0x0A, 0x01, 0x04, 0x08, 0x06, 0x00, 0x02, 0x1A, 0x2A,
+        0x16A, 0x1EA, 0x6A, 0xEA
+    },
+};
+
+static const uint8_t bink2f_ac_val_bits[2][13] = {
+    { 3, 1, 2, 4, 5, 6, 8, 9, 9, 9, 9, 9, 9 },
+    { 6, 1, 3, 4, 3, 4, 4, 5, 7, 9, 9, 9, 9 },
+};
+
+#define NUM_AC_SKIPS 14
+static const uint16_t bink2f_ac_skip_codes[2][NUM_AC_SKIPS] = {
+    {
+        0x00, 0x01, 0x0D, 0x15, 0x45, 0x85, 0xA5, 0x165,
+        0x65, 0x1E5, 0xE5, 0x25, 0x03, 0x05
+    },
+    {
+        0x00, 0x01, 0x03, 0x07, 0x1F, 0x1B, 0x0F, 0x2F,
+        0x5B, 0xDB, 0x1DB, 0x3B, 0x05, 0x0B
+    }
+};
+
+static const uint8_t bink2f_ac_skip_bits[2][NUM_AC_SKIPS] = {
+    { 1, 3, 4, 5, 7, 8, 8, 9, 9, 9, 9, 8, 2, 8 },
+    { 1, 3, 4, 4, 5, 7, 6, 6, 8, 9, 9, 6, 3, 5 }
+};
+
+static const uint8_t bink2f_skips[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 62, 0, 0, 0,
+};
+
+static const uint8_t bink2g_skips[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0,
+};
+
+static const uint8_t bink2f_next_skips[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
+};
+
+static const uint8_t bink2_next_skips[] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,
+};
+
+static const uint16_t bink2g_ac_skip_codes[2][NUM_AC_SKIPS] = {
+    {
+        0x01, 0x00, 0x004, 0x02C, 0x06C, 0x0C, 0x4C,
+        0xAC, 0xEC, 0x12C, 0x16C, 0x1AC, 0x02, 0x1C,
+    },
+    {
+        0x01, 0x04, 0x00, 0x08, 0x02, 0x32, 0x0A,
+        0x12, 0x3A, 0x7A, 0xFA, 0x72, 0x06, 0x1A,
+    },
+};
+
+static const uint8_t bink2g_ac_skip_bits[2][NUM_AC_SKIPS] = {
+    { 1, 3, 4, 9, 9, 7, 7, 9, 8, 9, 9, 9, 2, 5 },
+    { 1, 3, 4, 4, 5, 7, 5, 6, 7, 8, 8, 7, 3, 6 },
+};
+
+static const uint8_t bink2g_mv_codes[] = {
+    0x01, 0x06, 0x0C, 0x1C, 0x18, 0x38, 0x58, 0x78,
+    0x68, 0x48, 0x28, 0x08, 0x14, 0x04, 0x02, 0x00,
+};
+
+static const uint8_t bink2g_mv_bits[] = {
+    1, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 3, 4,
+};
+
+static const float bink2f_dc_quant[16] = {
+    4, 4, 4, 4, 4, 6, 7, 8, 10, 12, 16, 24, 32, 48, 64, 128
+};
+
+static const float bink2f_ac_quant[16] = {
+    1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 6.0, 7.0, 8.0, 12.0, 16.0, 24.0, 32.0, 48.0, 64.0, 128.0
+};
+
+static const float bink2f_luma_intra_qmat[64] = {
+    0.125,    0.190718, 0.16332,  0.235175, 0.3,      0.392847, 0.345013, 0.210373,
+    0.208056, 0.288582, 0.317145, 0.387359, 0.450788, 0.790098, 0.562995, 0.263095,
+    0.228649, 0.294491, 0.341421, 0.460907, 0.653281, 0.731424, 0.60988,  0.252336,
+    0.205778, 0.346585, 0.422498, 0.501223, 0.749621, 1.004719, 0.636379, 0.251428,
+    0.225,    0.381436, 0.604285, 0.823113, 0.85,     1.070509, 0.69679,  0.265553,
+    0.235708, 0.476783, 0.70576,  0.739104, 0.795516, 0.802512, 0.600616, 0.249289,
+    0.331483, 0.600528, 0.689429, 0.692062, 0.69679,  0.643138, 0.43934,  0.188511,
+    0.248309, 0.440086, 0.42807,  0.397419, 0.386259, 0.270966, 0.192244, 0.094199,
+};
+
+static const float bink2f_luma_inter_qmat[64] = {
+    0.125,    0.17338,  0.16332,  0.146984, 0.128475, 0.106393, 0.077046, 0.043109,
+    0.17338,  0.240485, 0.226532, 0.203873, 0.1782,   0.147571, 0.109474, 0.062454,
+    0.16332,  0.226532, 0.219321, 0.202722, 0.181465, 0.149711, 0.112943, 0.062584,
+    0.146984, 0.203873, 0.202722, 0.201647, 0.183731, 0.153976, 0.11711,  0.065335,
+    0.128475, 0.1782,   0.181465, 0.183731, 0.177088, 0.155499, 0.120267, 0.068016,
+    0.106393, 0.147571, 0.149711, 0.153976, 0.155499, 0.145756, 0.116636, 0.068495,
+    0.077046, 0.109474, 0.112943, 0.11711,  0.120267, 0.116636, 0.098646, 0.060141,
+    0.043109, 0.062454, 0.062584, 0.065335, 0.068016, 0.068495, 0.060141, 0.038853,
+};
+
+static const float bink2f_chroma_qmat[64] = {
+    0.125,      0.17338,    0.217761,   0.383793,   0.6875,     0.54016501, 0.37207201, 0.18968099,
+    0.17338,    0.28056601, 0.32721299, 0.74753499, 0.95358998, 0.74923098, 0.51607901, 0.26309499,
+    0.217761,   0.32721299, 0.66387498, 1.056244,   0.89826202, 0.70576,    0.48613599, 0.24783,
+    0.383793,   0.74753499, 1.056244,   0.95059502, 0.80841398, 0.635167,   0.437511,   0.223041,
+    0.6875,     0.95358998, 0.89826202, 0.80841398, 0.6875,     0.54016501, 0.37207201, 0.18968099,
+    0.54016501, 0.74923098, 0.70576,    0.635167,   0.54016501, 0.42440501, 0.292335,   0.149031,
+    0.37207201, 0.51607901, 0.48613599, 0.437511,   0.37207201, 0.292335,   0.201364,   0.102655,
+    0.18968099, 0.26309499, 0.24783,    0.223041,   0.18968099, 0.149031,   0.102655,   0.052333001
+};
+
+static const uint8_t bink2f_luma_scan[64] = {
+     0,  2,  1,  8,  9, 17, 10, 16,
+    24,  3, 18, 25, 32, 11, 33, 26,
+     4, 40, 19, 12, 27, 41, 34,  5,
+    20, 48,  6, 28, 15, 42, 23, 35,
+    21, 13, 14,  7, 31, 43, 49, 36,
+    22, 56, 39, 50, 30, 44, 29, 51,
+    57, 47, 58, 59, 63, 61, 55, 38,
+    52, 62, 45, 37, 60, 46, 54, 53
+};
+
+static const uint8_t bink2f_chroma_scan[64] = {
+     0,  1,  8,  2,  9, 16, 10, 17,
+     3, 24, 11, 18, 25, 13, 14,  4,
+    15,  5,  6,  7, 12, 19, 20, 21,
+    22, 23, 26, 27, 28, 29, 30, 31,
+    32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47,
+    48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 58, 59, 60, 61, 62, 63
+};
+
+static const uint8_t bink2g_scan[64] = {
+     0,   8,   1,   2,  9,  16,  24,  17,
+    10,   3,   4,  11, 18,  25,  32,  40,
+    33,  26,  19,  12,  5,   6,  13,  20,
+    27,  34,  41,  48, 56,  49,  42,  35,
+    28,  21,  14,   7, 15,  22,  29,  36,
+    43,  50,  57,  58, 51,  44,  37,  30,
+    23,  31,  38,  45, 52,  59,  60,  53,
+    46,  39,  47,  54, 61,  62,  55,  63,
+};
+
+typedef struct QuantPredict {
+    int8_t intra_q;
+    int8_t inter_q;
+} QuantPredict;
+
+typedef struct DCPredict {
+    float dc[4][16];
+    int   block_type;
+} DCPredict;
+
+typedef struct DCIPredict {
+    int dc[4][16];
+    int block_type;
+} DCIPredict;
+
+typedef struct MVectors {
+    int v[4][2];
+    int nb_vectors;
+} MVectors;
+
+typedef struct MVPredict {
+    MVectors mv;
+} MVPredict;
+
+/*
+ * Decoder context
+ */
+typedef struct Bink2Context {
+    AVCodecContext  *avctx;
+    GetBitContext   gb;
+    BlockDSPContext dsp;
+    AVFrame         *last;
+    int             version;              ///< internal Bink file version
+    int             has_alpha;
+
+    DECLARE_ALIGNED(16, float, block[4][64]);
+    DECLARE_ALIGNED(16, int16_t, iblock[4][64]);
+
+    QuantPredict    *current_q;
+    QuantPredict    *prev_q;
+
+    DCPredict       *current_dc;
+    DCPredict       *prev_dc;
+
+    DCIPredict      *current_idc;
+    DCIPredict      *prev_idc;
+
+    MVPredict       *current_mv;
+    MVPredict       *prev_mv;
+
+    uint8_t         *col_cbp;
+    uint8_t         *row_cbp;
+
+    int             num_slices;
+    int             slice_height[4];
+
+    int             comp;
+    int             mb_pos;
+    unsigned        flags;
+    unsigned        frame_flags;
+} Bink2Context;
+
+/**
+ * Bink2 video block types
+ */
+enum BlockTypes {
+    INTRA_BLOCK = 0, ///< intra DCT block
+    SKIP_BLOCK,      ///< skipped block
+    MOTION_BLOCK,    ///< block is copied from previous frame with some offset
+    RESIDUE_BLOCK,   ///< motion block with some difference added
+};
+
+static const uint8_t ones_count[16] = {
+    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4
+};
+
+#include "bink2f.c"
+#include "bink2g.c"
+
+static 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, void *data,
+                              int *got_frame, AVPacket *pkt)
+{
+    Bink2Context * const c = avctx->priv_data;
+    GetBitContext *gb = &c->gb;
+    AVFrame *frame = data;
+    uint8_t *dst[4];
+    uint8_t *src[4];
+    int stride[4];
+    int sstride[4];
+    uint32_t off = 0;
+    int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY);
+    int ret, w, h;
+    int height_a;
+
+    w = avctx->width;
+    h = avctx->height;
+    ret = ff_set_dimensions(avctx, FFALIGN(w, 32), FFALIGN(h, 32));
+    if (ret < 0)
+        return ret;
+    avctx->width  = w;
+    avctx->height = h;
+
+    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
+        return ret;
+
+    for (int i = 0; i < 4; i++) {
+        src[i]     = c->last->data[i];
+        dst[i]     = frame->data[i];
+        stride[i]  = frame->linesize[i];
+        sstride[i] = c->last->linesize[i];
+    }
+
+    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 av_cold int bink2_decode_end(AVCodecContext *avctx)
+{
+    Bink2Context * const c = avctx->priv_data;
+
+    av_frame_free(&c->last);
+    av_freep(&c->current_q);
+    av_freep(&c->prev_q);
+    av_freep(&c->current_dc);
+    av_freep(&c->prev_dc);
+    av_freep(&c->current_idc);
+    av_freep(&c->prev_idc);
+    av_freep(&c->current_mv);
+    av_freep(&c->prev_mv);
+    av_freep(&c->col_cbp);
+    av_freep(&c->row_cbp);
+
+    return 0;
+}
+
+AVCodec ff_bink2_decoder = {
+    .name           = "binkvideo2",
+    .long_name      = NULL_IF_CONFIG_SMALL("Bink video 2"),
+    .type           = AVMEDIA_TYPE_VIDEO,
+    .id             = AV_CODEC_ID_BINKVIDEO2,
+    .priv_data_size = sizeof(Bink2Context),
+    .init           = bink2_decode_init,
+    .close          = bink2_decode_end,
+    .decode         = bink2_decode_frame,
+    .capabilities   = AV_CODEC_CAP_DR1,
+};
diff --git a/libavcodec/bink2f.c b/libavcodec/bink2f.c
new file mode 100644
index 0000000000..c93c826041
--- /dev/null
+++ b/libavcodec/bink2f.c
@@ -0,0 +1,1125 @@ 
+/*
+ * Bink video 2 decoder
+ * Copyright (c) 2014 Konstantin Shishkov
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static inline void bink2f_idct_1d(float *blk, int step)
+{
+    float t00 =  blk[2 * step] + blk[6 * step];
+    float t01 = (blk[2 * step] - blk[6 * step]) * 1.4142135f - t00;
+    float t02 =  blk[0 * step] + blk[4 * step];
+    float t03 =  blk[0 * step] - blk[4 * step];
+    float t04 =  blk[3 * step] + blk[5 * step];
+    float t05 =  blk[3 * step] - blk[5 * step];
+    float t06 =  blk[1 * step] + blk[7 * step];
+    float t07 =  blk[1 * step] - blk[7 * step];
+    float t08 = t02 + t00;
+    float t09 = t02 - t00;
+    float t10 = t03 + t01;
+    float t11 = t03 - t01;
+    float t12 = t06 + t04;
+    float t13 = (t06 - t04) * 1.4142135f;
+    float t14 = (t07 - t05) * 1.847759f;
+    float t15 = t05 * 2.613126f + t14 - t12;
+    float t16 = t13 - t15;
+    float t17 = t07 * 1.0823922f - t14 + t16;
+
+    blk[0*step] = t08 + t12;
+    blk[1*step] = t10 + t15;
+    blk[2*step] = t11 + t16;
+    blk[3*step] = t09 - t17;
+    blk[4*step] = t09 + t17;
+    blk[5*step] = t11 - t16;
+    blk[6*step] = t10 - t15;
+    blk[7*step] = t08 - t12;
+}
+
+static void bink2f_idct_put(uint8_t *dst, int stride, float *block)
+{
+    block[0] += 512.5f;
+
+    for (int i = 0; i < 8; i++)
+        bink2f_idct_1d(block + i, 8);
+    for (int i = 0; i < 8; i++) {
+        bink2f_idct_1d(block, 1);
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(block[j] - 512.0f);
+        block += 8;
+        dst += stride;
+    }
+}
+
+static void bink2f_idct_add(uint8_t *dst, int stride,
+                            float *block)
+{
+    block[0] += 512.5f;
+
+    for (int i = 0; i < 8; i++)
+        bink2f_idct_1d(block + i, 8);
+    for (int i = 0; i < 8; i++) {
+        bink2f_idct_1d(block, 1);
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(dst[j] + block[j] - 512.0f);
+        block += 8;
+        dst += stride;
+    }
+}
+
+static int bink2f_decode_delta_q(GetBitContext *gb)
+{
+    int dq = get_vlc2(gb, bink2f_quant_vlc.table, bink2f_quant_vlc.bits, 1);
+
+    if (dq < 0)
+        return AVERROR_INVALIDDATA;
+    if (dq && get_bits1(gb))
+        dq = -dq;
+
+    return dq;
+}
+
+static unsigned bink2f_decode_cbp_luma(GetBitContext *gb, unsigned prev_cbp)
+{
+    unsigned cbp, cbp4, cbplo, cbphi;
+
+    if (get_bits1(gb)) {
+        if (get_bits1(gb))
+            return prev_cbp;
+        cbplo = prev_cbp & 0xFFFF;
+    } else {
+        cbplo = 0;
+        cbp4 = (prev_cbp >> 4) & 0xF;
+        for (int i = 0; i < 4; i++) {
+            if (!get_bits1(gb))
+                cbp4 = get_bits(gb, 4);
+            cbplo |= cbp4 << (i * 4);
+        }
+    }
+    cbphi = 0;
+    cbp = cbplo;
+    cbp4 = prev_cbp >> 20 & 0xF;
+    for (int i = 0; i < 4; i++) {
+        if (ones_count[cbp & 0xF]) {
+            if (ones_count[cbp & 0xF] == 1) {
+                cbp4 = 0;
+                for (int j = 1; j < 16; j <<= 1) {
+                    if ((j & cbp) && get_bits1(gb))
+                        cbp4 |= j;
+                }
+            } else if (!get_bits1(gb)) {
+                cbp4 = 0;
+                for (int j = 1; j < 16; j <<= 1) {
+                    if ((j & cbp) && get_bits1(gb))
+                        cbp4 |= j;
+                }
+            }
+        } else {
+            cbp4 = 0;
+        }
+        cbp4 &= cbp;
+        cbphi = (cbphi >> 4) | (cbp4 << 0x1c);
+        cbp >>= 4;
+    }
+    return cbphi | cbplo;
+}
+
+static unsigned bink2f_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp)
+{
+    unsigned cbplo, cbphi;
+
+    if (get_bits1(gb)) {
+        if (get_bits1(gb))
+            return prev_cbp;
+        cbplo = prev_cbp & 0xF;
+    } else {
+        cbplo = get_bits(gb, 4);
+    }
+
+    cbphi = 0;
+    if (ones_count[cbplo & 0xF]) {
+        if (ones_count[cbplo & 0xF] != 1) {
+            cbphi = (prev_cbp >> 16) & cbplo;
+            if (get_bits1(gb))
+                return cbplo | (cbphi << 16);
+        }
+        cbphi = 0;
+        for (int j = 1; j < 16; j <<= 1) {
+            if ((j & cbplo) && get_bits1(gb))
+                cbphi |= j;
+        }
+    }
+    return cbplo | (cbphi << 16);
+}
+
+static const uint8_t q_dc_bits[16] = {
+    2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7
+};
+
+static void bink2f_predict_dc(Bink2Context *c,
+                              int is_luma, float mindc, float maxdc,
+                              int flags, float tdc[16])
+{
+    float *LTdc = c->prev_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
+    float *Tdc = c->prev_dc[c->mb_pos].dc[c->comp];
+    float *Ldc = c->current_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
+    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
+
+    if (is_luma && (flags & 0x20) && (flags & 0x80)) {
+        dc[0]  = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(dc[4] + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma && (flags & 0x80)) {
+        dc[0]  = av_clipf(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(dc[4] + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma && (flags & 0x20)) {
+        dc[0]  = av_clipf(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (is_luma) {
+        dc[0]  = av_clipf(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc);
+        dc[1]  = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc);
+        dc[2]  = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+        dc[4]  = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc);
+        dc[5]  = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc);
+        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
+        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
+        dc[8]  = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc);
+        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
+        dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc);
+        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
+        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
+        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
+        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
+        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) {
+        dc[0] = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x80)) {
+        dc[0] = av_clipf(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma && (flags & 0x20)) {
+        dc[0] = av_clipf(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    } else if (!is_luma) {
+        dc[0] = av_clipf(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc);
+        dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc);
+        dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc);
+        dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
+    }
+}
+
+static void bink2f_decode_dc(Bink2Context *c, GetBitContext *gb, float *dc,
+                             int is_luma, int q, int mindc, int maxdc,
+                             int flags)
+{
+    const int num_dc = is_luma ? 16 : 4;
+    float tdc[16] = { 0 };
+    int dc_bits;
+
+    dc_bits = get_bits(gb, 3);
+    if (dc_bits == 7)
+        dc_bits += get_bits(gb, 2);
+    if (!dc_bits) {
+        memset(dc, 0, sizeof(*dc) * num_dc);
+    } else {
+        for (int j = 0; j < num_dc; j += 4) {
+            for (int i = 0; i < 4; i++)
+                tdc[i + j] = get_bits(gb, dc_bits);
+
+            for (int i = 0; i < 4; i++)
+                if (tdc[i + j] && get_bits1(gb))
+                    tdc[i + j] = -tdc[i + j];
+        }
+    }
+
+    if ((flags & 0x20) && (flags & 0x80) && mindc >= 0) {
+        int bits = (q_dc_bits[q] - 1) + dc_bits;
+
+        if (bits < 10) {
+            int dc_val = get_bits(gb, 10 - bits);
+
+            if (dc_val) {
+               dc_val <<= dc_bits;
+               if (get_bits1(gb))
+                   dc_val = -dc_val;
+            }
+            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 = bink2f_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..71ae7c5041
--- /dev/null
+++ b/libavcodec/bink2g.c
@@ -0,0 +1,1197 @@ 
+/*
+ * Bink video 2 decoder
+ * Copyright (c) 2014 Konstantin Shishkov
+ * Copyright (c) 2019 Paul B Mahol
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+static inline void bink2g_idct_1d(int16_t *blk, int step, int shift)
+{
+#define idct_mul_a(val) ((val) + ((val) >> 2))
+#define idct_mul_b(val) ((val) >> 1)
+#define idct_mul_c(val) ((val) - ((val) >> 2) - ((val) >> 4))
+#define idct_mul_d(val) ((val) + ((val) >> 2) - ((val) >> 4))
+#define idct_mul_e(val) ((val) >> 2)
+    int tmp00 =  blk[3*step] + blk[5*step];
+    int tmp01 =  blk[3*step] - blk[5*step];
+    int tmp02 =  idct_mul_a(blk[2*step]) + idct_mul_b(blk[6*step]);
+    int tmp03 =  idct_mul_b(blk[2*step]) - idct_mul_a(blk[6*step]);
+    int tmp0  = (blk[0*step] + blk[4*step]) + tmp02;
+    int tmp1  = (blk[0*step] + blk[4*step]) - tmp02;
+    int tmp2  =  blk[0*step] - blk[4*step];
+    int tmp3  =  blk[1*step] + tmp00;
+    int tmp4  =  blk[1*step] - tmp00;
+    int tmp5  =  tmp01 + blk[7*step];
+    int tmp6  =  tmp01 - blk[7*step];
+    int tmp7  =  tmp4 + idct_mul_c(tmp6);
+    int tmp8  =  idct_mul_c(tmp4) - tmp6;
+    int tmp9  =  idct_mul_d(tmp3) + idct_mul_e(tmp5);
+    int tmp10 =  idct_mul_e(tmp3) - idct_mul_d(tmp5);
+    int tmp11 =  tmp2 + tmp03;
+    int tmp12 =  tmp2 - tmp03;
+
+    blk[0*step] = (tmp0  + tmp9)  >> shift;
+    blk[1*step] = (tmp11 + tmp7)  >> shift;
+    blk[2*step] = (tmp12 + tmp8)  >> shift;
+    blk[3*step] = (tmp1  + tmp10) >> shift;
+    blk[4*step] = (tmp1  - tmp10) >> shift;
+    blk[5*step] = (tmp12 - tmp8)  >> shift;
+    blk[6*step] = (tmp11 - tmp7)  >> shift;
+    blk[7*step] = (tmp0  - tmp9)  >> shift;
+}
+
+static void bink2g_idct_put(uint8_t *dst, int stride, int16_t *block)
+{
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i, 8, 0);
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i * 8, 1, 6);
+    for (int i = 0; i < 8; i++) {
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(block[j * 8 + i]);
+        dst += stride;
+    }
+}
+
+static void bink2g_idct_add(uint8_t *dst, int stride, int16_t *block)
+{
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i, 8, 0);
+    for (int i = 0; i < 8; i++)
+        bink2g_idct_1d(block + i * 8, 1, 6);
+    for (int i = 0; i < 8; i++) {
+        for (int j = 0; j < 8; j++)
+            dst[j] = av_clip_uint8(dst[j] + block[j * 8 + i]);
+        dst += stride;
+    }
+}
+
+static int bink2g_get_type(GetBitContext *gb, int *lru)
+{
+    int val;
+
+    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 ece6eadae4..4120b18e76 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1754,6 +1754,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("CDToons video"),
         .props     = AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_BINKVIDEO2,
+        .type      = AVMEDIA_TYPE_VIDEO,
+        .name      = "binkvideo2",
+        .long_name = NULL_IF_CONFIG_SMALL("Bink video 2"),
+        .props     = AV_CODEC_PROP_LOSSY,
+    },
 
     /* various PCM "codecs" */
     {
diff --git a/libavformat/bink.c b/libavformat/bink.c
index 08125ba8f1..9cb22713d0 100644
--- a/libavformat/bink.c
+++ b/libavformat/bink.c
@@ -148,8 +148,7 @@  static int read_header(AVFormatContext *s)
     vst->codecpar->codec_id   = AV_CODEC_ID_BINKVIDEO;
 
     if ((vst->codecpar->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) {
-        av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n");
-        vst->codecpar->codec_id = AV_CODEC_ID_NONE;
+        vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO2;
     }
 
     if ((ret = ff_get_extradata(s, vst->codecpar, pb, 4)) < 0)