From patchwork Fri Mar 20 13:31:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 18307 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 61BAD449AD4 for ; Fri, 20 Mar 2020 15:31:27 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2ED0E68B743; Fri, 20 Mar 2020 15:31:27 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f50.google.com (mail-wr1-f50.google.com [209.85.221.50]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 16E8268B087 for ; Fri, 20 Mar 2020 15:31:21 +0200 (EET) Received: by mail-wr1-f50.google.com with SMTP id h4so7524816wru.2 for ; Fri, 20 Mar 2020 06:31:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=k4zVSSaORpCRU4MWvlp4XRBsBPTGFuBWCUjyiy2vrP4=; b=CgREZNl2HNrR6cInLhF4AQ+YmfeTalV+QfQ3OkkhkdP+/vLIpUSNI1g7U+oNV1MIim Bf/zm1LyHvj6jGtuDZRQT6FhtlqNWLal8oabCf7sNi4DDM5csF65irmiUnGHO8zQu/T+ 0nfrYwcVvOYUhdkFi7vVnPih7e99uLH8LyEvI0zlnp3xw8ISXl775fKC96vBU8wfLddL 4aQiQQ6EzanqzUoy9eewcDbn9KpQvc/KWgLsbYFXWkrEiWZqMY0LyETnfQhGX81IWg2S ywRsaQzQQHr/io2SjPfe1WeIE0TYoOngLI9Jtwr6g/iGqLm6yIybIfOF5fWuCJEOhGwv FHFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id; bh=k4zVSSaORpCRU4MWvlp4XRBsBPTGFuBWCUjyiy2vrP4=; b=aX6xwc6KcQyr2i0G7jYc4FlffVM+4wq6Gh9Vt0QtOC7c+9ri3+5Bh8kNbhYRDLbKzJ CuIrGTffYsNxqgSnVdFqm0OGLqSTCCYN2uO1HIYJATFftrMMs45a4SuR3kcBww0hb3Rh BrxhKSV/lv8ESRvAsfTAygzGgPzcQa9exwUD5nLqb3AGpoDA6kR0njcHS5VnLjKABeAp 9sH6OmeRNo3ZNyWX/uFMo4/ilUHtAIe35bkrDp3UQCEk+3j9EtPW15MjSnC8cms/B+BM IPhjPoQysrIhYUvXsEfibt8d4nUk8Sk8Qr8jGJQV7Ueyu2sXmLXJtAUqGPnaSuhXVSmJ yVIw== X-Gm-Message-State: ANhLgQ1ItxvR+AOIbNal5E4VmgtEVdql6rwO89fdPVDKSVyNoD9t0KWj NkpFpP/Rp6iPXUKTLM/xKwEfZ2f/ X-Google-Smtp-Source: ADFU+vtdKEpD2nDl1ihiwgwR0kyEW6z5ZB3xLsqCtbMvQMAOm48ZZAsTajAETvlrkhjaL2OzhVIpJw== X-Received: by 2002:adf:f68a:: with SMTP id v10mr6557328wrp.80.1584711076667; Fri, 20 Mar 2020 06:31:16 -0700 (PDT) Received: from localhost.localdomain ([37.244.255.176]) by smtp.gmail.com with ESMTPSA id l12sm8053147wrt.73.2020.03.20.06.31.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 20 Mar 2020 06:31:15 -0700 (PDT) From: Paul B Mahol To: ffmpeg-devel@ffmpeg.org Date: Fri, 20 Mar 2020 14:31:05 +0100 Message-Id: <20200320133105.22480-1-onemda@gmail.com> X-Mailer: git-send-email 2.17.1 Subject: [FFmpeg-devel] [PATCH] avcodec: add bink2 video decoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches MIME-Version: 1.0 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Signed-off-by: Paul B Mahol --- 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, +}; 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)