diff --git a/configure b/configure index 98b582a5d5..89ac08f611 100755 --- a/configure +++ b/configure @@ -2919,6 +2919,7 @@ atrac3p_decoder_select="sinewin" atrac3pal_decoder_select="sinewin" av1_decoder_select="atsc_a53 cbs_av1 dovi_rpudec" bink_decoder_select="blockdsp hpeldsp" +bink2_decoder_select="blockdsp" binkaudio_dct_decoder_select="wma_freqs" binkaudio_rdft_decoder_select="wma_freqs" cavs_decoder_select="blockdsp golomb h264chroma idctdsp qpeldsp videodsp" diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 153a9e3881..ebff3c239a 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -277,6 +277,7 @@ OBJS-$(CONFIG_AVUI_ENCODER) += avuienc.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 aa0fc47647..0b806a1458 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -63,6 +63,7 @@ extern const FFCodec ff_avui_decoder; extern const FFCodec ff_bethsoftvid_decoder; extern const FFCodec ff_bfi_decoder; extern const FFCodec ff_bink_decoder; +extern const FFCodec ff_bink2_decoder; extern const FFCodec ff_bitpacked_decoder; extern const FFCodec ff_bitpacked_encoder; extern const FFCodec ff_bmp_encoder; diff --git a/libavcodec/bink2.c b/libavcodec/bink2.c new file mode 100644 index 0000000000..6519efa335 --- /dev/null +++ b/libavcodec/bink2.c @@ -0,0 +1,480 @@ +/* + * 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/emms.h" +#include "libavutil/imgutils.h" +#include "libavutil/internal.h" +#include "libavutil/mem.h" +#include "avcodec.h" +#include "blockdsp.h" +#include "codec_internal.h" +#include "copy_block.h" +#include "decode.h" +#include "idctdsp.h" +#include "internal.h" +#include "mathops.h" + +#define BITSTREAM_READER_LE +#include "get_bits.h" +#include "unary.h" +#include "bink2.h" + +#include "bink2f.h" +#include "bink2g.h" + +static void bink2_get_block_flags(GetBitContext *gb, int offset, int size, uint8_t *dst) +{ + int flags_left, mode = 0; + unsigned flag = 0; + + if (get_bits1(gb) == 0) { + for (int i = 0; i < size; i++, offset++) { + const unsigned value = get_bits1(gb); + + dst[offset >> 3] |= value << (offset & 7); + } + + return; + } + + flags_left = size; + while (flags_left > 0) { + if (get_bits1(gb) == 0) { + int count; + + if (mode == 3) { + flag ^= 1; + } else { + flag = get_bits1(gb); + } + + dst[offset >> 3] |= flag << (offset & 7); + offset++; + flags_left--; + + count = FFMIN(flags_left, 4); + for (int i = 0; i < count; i++, offset++, flags_left--) { + const unsigned value = get_bits1(gb); + + dst[offset >> 3] |= value << (offset & 7); + } + mode = 2; + } else { + int bits, run; + + bits = flags_left < 4 ? 2 : flags_left < 16 ? 4 : 5; + if (mode == 3) { + flag ^= 1; + run = bits + 1; + } else { + flag = get_bits1(gb); + run = bits + 2; + } + + run = FFMIN(run, flags_left); + if (run != flags_left) { + const unsigned extra = get_bits(gb, bits); + + run += extra; + mode = extra == (1U << bits) - 1 ? 1 : 3; + } + + for (int i = 0; i < run; i++, offset++) + dst[offset >> 3] |= flag << (offset & 7); + flags_left -= run; + } + } +} + +typedef struct Bink2ThreadData { + AVFrame *frame; + int is_kf; + int slice_end[BINK2_MAX_SLICES]; +} Bink2ThreadData; + +static int bink2_decode_slice(AVCodecContext *avctx, void *arg, + int jobnr, int threadnr) +{ + Bink2Context *parent = avctx->priv_data; + Bink2ThreadData *td = arg; + Bink2Context *c = parent->slice_ctx[jobnr]; + GetBitContext *gb = &c->gb; + AVFrame *frame = td->frame; + uint8_t *dst[4]; + uint8_t *src[4]; + int stride[4]; + int sstride[4]; + const int start = jobnr ? parent->slice_height[jobnr - 1] : 0; + const int end = parent->slice_height[jobnr]; + int bits_left, ret; + + (void)threadnr; + + for (int i = 0; i < 4; i++) { + src[i] = parent->last->data[i]; + dst[i] = frame->data[i]; + stride[i] = frame->linesize[i]; + sstride[i] = parent->last->linesize[i]; + } + + dst[0] += start * stride[0]; + dst[1] += start / 2 * stride[1]; + dst[2] += start / 2 * stride[2]; + if (c->has_alpha) + dst[3] += start * stride[3]; + + if (c->version <= 'f' || !(c->frame_flags & 0x2000)) + ret = bink2f_decode_slice(c, dst, stride, src, sstride, + td->is_kf, start, end); + else + ret = bink2g_decode_slice(c, dst, stride, src, sstride, + td->is_kf, start, end); + if (ret < 0) + return ret; + + align_get_bits(gb); + bits_left = 8 * td->slice_end[jobnr] - get_bits_count(gb); + if (bits_left < 0) + av_log(avctx, AV_LOG_WARNING, "slice %d: overread\n", jobnr); + else if (bits_left > 24) + av_log(avctx, AV_LOG_WARNING, "slice %d: underread %d\n", + jobnr, bits_left); + + return 0; +} + +static int bink2_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, AVPacket *pkt) +{ + Bink2Context * const c = avctx->priv_data; + GetBitContext *gb = &c->gb; + Bink2ThreadData td = { .frame = frame }; + int thread_ret[BINK2_MAX_SLICES] = { 0 }; + int is_kf = !!(pkt->flags & AV_PKT_FLAG_KEY); + int first_slice_bit, ret, w, h; + int height_a; + + if (pkt->size < 4) + return AVERROR_INVALIDDATA; + + 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; + + if (!is_kf && (!c->last->data[0] || + !c->last->data[1] || + !c->last->data[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; + + if (pkt->size < 4 + 4 * (c->num_slices - 1)) + return AVERROR_INVALIDDATA; + + skip_bits_long(gb, 32 + 32 * (c->num_slices - 1)); + + memset(c->row_cbp, 0, + ((((avctx->height + 31) >> 3) + 7) >> 3) * sizeof(*c->row_cbp)); + memset(c->col_cbp, 0, + ((((avctx->width + 31) >> 3) + 7) >> 3) * sizeof(*c->col_cbp)); + + 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 + 31) & ~31) >> 3) - 1, c->col_cbp); + } + + if (get_bits_left(gb) < 0) + return AVERROR_INVALIDDATA; + + td.is_kf = is_kf; + first_slice_bit = get_bits_count(gb); + for (int i = 0; i < c->num_slices; i++) { + Bink2Context *sc = c->slice_ctx[i]; + const int start = i ? td.slice_end[i - 1] : 0; + const int start_bit = i ? 8 * start : first_slice_bit; + + td.slice_end[i] = i == c->num_slices - 1 ? + pkt->size : AV_RL32(pkt->data + 4 + 4 * i); + if (td.slice_end[i] < start || + td.slice_end[i] > pkt->size || + 8 * td.slice_end[i] < start_bit) + return AVERROR_INVALIDDATA; + + sc->frame_flags = c->frame_flags; + if (i) { + if ((ret = init_get_bits8(&sc->gb, pkt->data, pkt->size)) < 0) + return ret; + skip_bits_long(&sc->gb, start_bit); + } + } + + if ((ret = avctx->execute2(avctx, bink2_decode_slice, &td, + thread_ret, c->num_slices)) < 0) + return ret; + for (int i = 0; i < c->num_slices; i++) + if (thread_ret[i] < 0) + return thread_ret[i]; + + if (c->version > 'f' && (c->frame_flags & 0x2000)) { + bink2g_postprocess_frame(c, frame->data, frame->linesize); + } + + if (is_kf) + frame->flags |= AV_FRAME_FLAG_KEY; + else + frame->flags &= ~AV_FRAME_FLAG_KEY; + 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; + + frame->colorspace = avctx->colorspace; + frame->color_range = avctx->color_range; + + *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 VLCElem table[static_size]; \ + (vlc)->table = table; \ + (vlc)->table_allocated = static_size; \ + ff_vlc_init_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + symbols, symbols_wrap, symbols_size, \ + VLC_INIT_LE | VLC_INIT_USE_STATIC); \ + } while (0) + +static int bink2_alloc_slice_state(Bink2Context *c, int width) +{ + const int mb_width = (width + 31) / 32; + + c->current_q = av_malloc_array(mb_width, sizeof(*c->current_q)); + c->prev_q = av_malloc_array(mb_width, sizeof(*c->prev_q)); + c->current_dc = av_malloc_array(mb_width, sizeof(*c->current_dc)); + c->prev_dc = av_malloc_array(mb_width, sizeof(*c->prev_dc)); + c->current_idc = av_malloc_array(mb_width, sizeof(*c->current_idc)); + c->prev_idc = av_malloc_array(mb_width, sizeof(*c->prev_idc)); + c->current_mv = av_malloc_array(mb_width, sizeof(*c->current_mv)); + c->prev_mv = av_malloc_array(mb_width, sizeof(*c->prev_mv)); + + if (!c->current_q || !c->prev_q || + !c->current_dc || !c->prev_dc || + !c->current_idc || !c->prev_idc || + !c->current_mv || !c->prev_mv) + return AVERROR(ENOMEM); + + return 0; +} + +static void bink2_free_slice_state(Bink2Context *c) +{ + 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); +} + +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->slice_ctx[0] = c; + + 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; + avctx->colorspace = AVCOL_SPC_SMPTE170M; + avctx->color_range = c->flags & BINK_FLAG_YCRCB_NEW ? + AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + ff_blockdsp_init(&c->dsp); + + 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); + + if ((ret = bink2_alloc_slice_state(c, avctx->width)) < 0) + return ret; + + { + const size_t mb_count = (size_t)((avctx->width + 31) >> 5) * + ((avctx->height + 31) >> 5); + + c->frame_idc = av_malloc_array(mb_count, sizeof(*c->frame_idc)); + c->frame_mv = av_malloc_array(mb_count, sizeof(*c->frame_mv)); + if (!c->frame_idc || !c->frame_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); + + for (int i = 1; i < BINK2_MAX_SLICES; i++) { + Bink2Context *sc = av_mallocz(sizeof(*sc)); + + if (!sc) + return AVERROR(ENOMEM); + c->slice_ctx[i] = sc; + sc->avctx = avctx; + sc->version = c->version; + sc->has_alpha = c->has_alpha; + sc->flags = c->flags; + sc->dsp = c->dsp; + sc->col_cbp = c->col_cbp; + sc->row_cbp = c->row_cbp; + sc->frame_idc = c->frame_idc; + sc->frame_mv = c->frame_mv; + if ((ret = bink2_alloc_slice_state(sc, avctx->width)) < 0) + return ret; + } + + return 0; +} + +static void bink2_flush(AVCodecContext *avctx) +{ + Bink2Context *c = avctx->priv_data; + + av_frame_unref(c->last); +} + +static av_cold int bink2_decode_end(AVCodecContext *avctx) +{ + Bink2Context * const c = avctx->priv_data; + + av_frame_free(&c->last); + for (int i = 1; i < BINK2_MAX_SLICES; i++) { + if (c->slice_ctx[i]) { + bink2_free_slice_state(c->slice_ctx[i]); + av_freep(&c->slice_ctx[i]); + } + } + bink2_free_slice_state(c); + av_freep(&c->frame_idc); + av_freep(&c->frame_mv); + av_freep(&c->col_cbp); + av_freep(&c->row_cbp); + + return 0; +} + +const FFCodec ff_bink2_decoder = { + .p.name = "binkvideo2", + .p.long_name = NULL_IF_CONFIG_SMALL("Bink video 2"), + .p.type = AVMEDIA_TYPE_VIDEO, + .p.id = AV_CODEC_ID_BINKVIDEO2, + .priv_data_size = sizeof(Bink2Context), + .init = bink2_decode_init, + .close = bink2_decode_end, + FF_CODEC_DECODE_CB(bink2_decode_frame), + .flush = bink2_flush, + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/bink2.h b/libavcodec/bink2.h new file mode 100644 index 0000000000..67d7603370 --- /dev/null +++ b/libavcodec/bink2.h @@ -0,0 +1,147 @@ +/* + * 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 + */ + +#ifndef AVCODEC_BINK2_H +#define AVCODEC_BINK2_H + +#include +#include "libavutil/mem_internal.h" +#include "avcodec.h" +#include "blockdsp.h" +#include "copy_block.h" +#include "unary.h" +#include "get_bits.h" + +static VLC bink2f_quant_vlc; +static VLC bink2f_ac_val0_vlc; +static VLC bink2f_ac_val1_vlc; +static VLC bink2f_ac_skip0_vlc; +static VLC bink2f_ac_skip1_vlc; +static VLC bink2g_ac_skip0_vlc; +static VLC bink2g_ac_skip1_vlc; +static VLC bink2g_mv_vlc; + +static const uint8_t kb2h_num_slices[] = { + 2, 3, 4, 8, +}; + +static const uint8_t luma_repos[] = { + 0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15, +}; + +static const uint8_t dq_patterns[8] = { 8, 0, 1, 0, 2, 0, 1, 0 }; + +static const uint8_t bink2_next_skips[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, +}; + +#define NUM_AC_SKIPS 14 +#define BINK2_MAX_SLICES 8 +#define BINK_FLAG_YCRCB_NEW 0x00000010 +#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))) +#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) + +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]; + uint16_t state[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; + + /* Modern Bink2 reconstruction and filtering need the neighbouring rows + * even when those rows belong to different bitstream slices. Slice jobs + * write disjoint rows here; the parent context post-processes the complete + * frame after every slice has finished. */ + DCIPredict *frame_idc; + MVPredict *frame_mv; + + uint8_t *col_cbp; + uint8_t *row_cbp; + + int num_slices; + int slice_height[BINK2_MAX_SLICES]; + struct Bink2Context *slice_ctx[BINK2_MAX_SLICES]; + + 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 +}; + +#endif /* AVCODEC_BINK2_H */ diff --git a/libavcodec/bink2f.h b/libavcodec/bink2f.h new file mode 100644 index 0000000000..4fa42d0b71 --- /dev/null +++ b/libavcodec/bink2f.h @@ -0,0 +1,1241 @@ +/* + * 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 + */ + +#ifndef AVCODEC_BINK2F_H +#define AVCODEC_BINK2F_H + +#include +#include "avcodec.h" +#include "get_bits.h" +#include "bink2.h" + +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 }, +}; + +static const uint16_t bink2f_ac_skip_codes[2][NUM_AC_SKIPS] = { + { + 0x00, 0x01, 0x0D, 0x15, 0x45, 0x85, 0xA5, 0x165, + 0x65, 0x1E5, 0xE5, 0x25, 0x03, 0x05 + }, + { + 0x00, 0x01, 0x03, 0x07, 0x1F, 0x1B, 0x0F, 0x2F, + 0x5B, 0xDB, 0x1DB, 0x3B, 0x05, 0x0B + } +}; + +static const uint8_t bink2f_ac_skip_bits[2][NUM_AC_SKIPS] = { + { 1, 3, 4, 5, 7, 8, 8, 9, 9, 9, 9, 8, 2, 8 }, + { 1, 3, 4, 4, 5, 7, 6, 6, 8, 9, 9, 6, 3, 5 } +}; + +static const uint8_t bink2f_skips[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 62, 0, 0, 0, +}; + +static const float bink2f_dc_quant[16] = { + 4, 4, 4, 4, 4, 6, 7, 8, 10, 12, 16, 24, 32, 48, 64, 128 +}; + +static const float bink2f_ac_quant[16] = { + 1.0, 2.0, 2.5, 3.0, 3.5, 4.0, 6.0, 7.0, 8.0, 12.0, 16.0, 24.0, 32.0, 48.0, 64.0, 128.0 +}; + +static const float bink2f_luma_intra_qmat[64] = { + 0.125, 0.190718, 0.16332, 0.235175, 0.3, 0.392847, 0.345013, 0.210373, + 0.208056, 0.288582, 0.317145, 0.387359, 0.450788, 0.790098, 0.562995, 0.263095, + 0.228649, 0.294491, 0.341421, 0.460907, 0.653281, 0.731424, 0.60988, 0.252336, + 0.205778, 0.346585, 0.422498, 0.501223, 0.749621, 1.004719, 0.636379, 0.251428, + 0.225, 0.381436, 0.604285, 0.823113, 0.85, 1.070509, 0.69679, 0.265553, + 0.235708, 0.476783, 0.70576, 0.739104, 0.795516, 0.802512, 0.600616, 0.249289, + 0.331483, 0.600528, 0.689429, 0.692062, 0.69679, 0.643138, 0.43934, 0.188511, + 0.248309, 0.440086, 0.42807, 0.397419, 0.386259, 0.270966, 0.192244, 0.094199, +}; + +static const float bink2f_luma_inter_qmat[64] = { + 0.125, 0.17338, 0.16332, 0.146984, 0.128475, 0.106393, 0.077046, 0.043109, + 0.17338, 0.240485, 0.226532, 0.203873, 0.1782, 0.147571, 0.109474, 0.062454, + 0.16332, 0.226532, 0.219321, 0.202722, 0.181465, 0.149711, 0.112943, 0.062584, + 0.146984, 0.203873, 0.202722, 0.201647, 0.183731, 0.153976, 0.11711, 0.065335, + 0.128475, 0.1782, 0.181465, 0.183731, 0.177088, 0.155499, 0.120267, 0.068016, + 0.106393, 0.147571, 0.149711, 0.153976, 0.155499, 0.145756, 0.116636, 0.068495, + 0.077046, 0.109474, 0.112943, 0.11711, 0.120267, 0.116636, 0.098646, 0.060141, + 0.043109, 0.062454, 0.062584, 0.065335, 0.068016, 0.068495, 0.060141, 0.038853, +}; + +static const float bink2f_chroma_qmat[64] = { + 0.125, 0.17338, 0.217761, 0.383793, 0.6875, 0.54016501, 0.37207201, 0.18968099, + 0.17338, 0.28056601, 0.32721299, 0.74753499, 0.95358998, 0.74923098, 0.51607901, 0.26309499, + 0.217761, 0.32721299, 0.66387498, 1.056244, 0.89826202, 0.70576, 0.48613599, 0.24783, + 0.383793, 0.74753499, 1.056244, 0.95059502, 0.80841398, 0.635167, 0.437511, 0.223041, + 0.6875, 0.95358998, 0.89826202, 0.80841398, 0.6875, 0.54016501, 0.37207201, 0.18968099, + 0.54016501, 0.74923098, 0.70576, 0.635167, 0.54016501, 0.42440501, 0.292335, 0.149031, + 0.37207201, 0.51607901, 0.48613599, 0.437511, 0.37207201, 0.292335, 0.201364, 0.102655, + 0.18968099, 0.26309499, 0.24783, 0.223041, 0.18968099, 0.149031, 0.102655, 0.052333001 +}; + +static const uint8_t bink2f_luma_scan[64] = { + 0, 2, 1, 8, 9, 17, 10, 16, + 24, 3, 18, 25, 32, 11, 33, 26, + 4, 40, 19, 12, 27, 41, 34, 5, + 20, 48, 6, 28, 15, 42, 23, 35, + 21, 13, 14, 7, 31, 43, 49, 36, + 22, 56, 39, 50, 30, 44, 29, 51, + 57, 47, 58, 59, 63, 61, 55, 38, + 52, 62, 45, 37, 60, 46, 54, 53 +}; + +static const uint8_t bink2f_chroma_scan[64] = { + 0, 1, 8, 2, 9, 16, 10, 17, + 3, 24, 11, 18, 25, 13, 14, 4, + 15, 5, 6, 7, 12, 19, 20, 21, + 22, 23, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 +}; + +static inline void bink2f_idct_1d(float *blk, int step) +{ + float t00 = blk[2 * step] + blk[6 * step]; + float t01 = (blk[2 * step] - blk[6 * step]) * 1.4142135f - t00; + float t02 = blk[0 * step] + blk[4 * step]; + float t03 = blk[0 * step] - blk[4 * step]; + float t04 = blk[3 * step] + blk[5 * step]; + float t05 = blk[3 * step] - blk[5 * step]; + float t06 = blk[1 * step] + blk[7 * step]; + float t07 = blk[1 * step] - blk[7 * step]; + float t08 = t02 + t00; + float t09 = t02 - t00; + float t10 = t03 + t01; + float t11 = t03 - t01; + float t12 = t06 + t04; + float t13 = (t06 - t04) * 1.4142135f; + float t14 = (t07 - t05) * 1.847759f; + float t15 = t05 * 2.613126f + t14 - t12; + float t16 = t13 - t15; + float t17 = t07 * 1.0823922f - t14 + t16; + + blk[0*step] = t08 + t12; + blk[1*step] = t10 + t15; + blk[2*step] = t11 + t16; + blk[3*step] = t09 - t17; + blk[4*step] = t09 + t17; + blk[5*step] = t11 - t16; + blk[6*step] = t10 - t15; + blk[7*step] = t08 - t12; +} + +static void bink2f_idct_put(uint8_t *dst, int stride, float *block) +{ + block[0] += 512.f; + + for (int i = 0; i < 8; i++) + bink2f_idct_1d(block + i, 8); + for (int i = 0; i < 8; i++) { + bink2f_idct_1d(block, 1); + for (int j = 0; j < 8; j++) + dst[j] = av_clip_uint8(lrintf(block[j] - 512.0f)); + block += 8; + dst += stride; + } +} + +static void bink2f_idct_add(uint8_t *dst, int stride, + float *block) +{ + block[0] += 512.f; + + for (int i = 0; i < 8; i++) + bink2f_idct_1d(block + i, 8); + for (int i = 0; i < 8; i++) { + bink2f_idct_1d(block, 1); + for (int j = 0; j < 8; j++) + dst[j] = av_clip_uint8(dst[j] + lrintf(block[j] - 512.0f)); + block += 8; + dst += stride; + } +} + +static int bink2f_decode_delta_q(GetBitContext *gb) +{ + int dq = get_vlc2(gb, bink2f_quant_vlc.table, bink2f_quant_vlc.bits, 1); + + if (dq < 0) + return AVERROR_INVALIDDATA; + if (dq && get_bits1(gb)) + dq = -dq; + + return dq; +} + +static unsigned bink2f_decode_cbp_luma(GetBitContext *gb, unsigned prev_cbp) +{ + unsigned cbp, cbp4, cbplo, cbphi; + + if (get_bits1(gb)) { + if (get_bits1(gb)) + return prev_cbp; + cbplo = prev_cbp & 0xFFFF; + } else { + cbplo = 0; + cbp4 = (prev_cbp >> 4) & 0xF; + for (int i = 0; i < 4; i++) { + if (!get_bits1(gb)) + cbp4 = get_bits(gb, 4); + cbplo |= cbp4 << (i * 4); + } + } + cbphi = 0; + cbp = cbplo; + cbp4 = prev_cbp >> 20 & 0xF; + for (int i = 0; i < 4; i++) { + if (av_popcount(cbp & 0xF)) { + if (av_popcount(cbp & 0xF) == 1) { + cbp4 = 0; + for (int j = 1; j < 16; j <<= 1) { + if ((j & cbp) && get_bits1(gb)) + cbp4 |= j; + } + } else if (!get_bits1(gb)) { + cbp4 = 0; + for (int j = 1; j < 16; j <<= 1) { + if ((j & cbp) && get_bits1(gb)) + cbp4 |= j; + } + } + } else { + cbp4 = 0; + } + cbp4 &= cbp; + cbphi = (cbphi >> 4) | (cbp4 << 0x1c); + cbp >>= 4; + } + return cbphi | cbplo; +} + +static unsigned bink2f_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp) +{ + unsigned cbplo, cbphi; + + if (get_bits1(gb)) { + if (get_bits1(gb)) + return prev_cbp; + cbplo = prev_cbp & 0xF; + } else { + cbplo = get_bits(gb, 4); + } + + cbphi = 0; + if (av_popcount(cbplo & 0xF)) { + if (av_popcount(cbplo & 0xF) != 1) { + cbphi = (prev_cbp >> 16) & cbplo; + if (get_bits1(gb)) + return cbplo | (cbphi << 16); + } + cbphi = 0; + for (int j = 1; j < 16; j <<= 1) { + if ((j & cbplo) && get_bits1(gb)) + cbphi |= j; + } + } + return cbplo | (cbphi << 16); +} + +static const uint8_t q_dc_bits[16] = { + 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 6, +}; + +static void bink2f_predict_dc(Bink2Context *c, + int is_luma, float mindc, float maxdc, + int flags, float tdc[16]) +{ + float *LTdc = c->prev_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; + float *Tdc = c->prev_dc[c->mb_pos].dc[c->comp]; + float *Ldc = c->current_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; + float *dc = c->current_dc[c->mb_pos].dc[c->comp]; + + if (is_luma && (flags & 0x20) && (flags & 0x80)) { + dc[0] = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); + dc[5] = av_clipf(dc[4] + tdc[5], mindc, maxdc); + dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); + dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); + dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (is_luma && (flags & 0x80)) { + dc[0] = av_clipf(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); + dc[5] = av_clipf(dc[4] + tdc[5], mindc, maxdc); + dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); + dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); + dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (is_luma && (flags & 0x20)) { + dc[0] = av_clipf(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); + dc[5] = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); + dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); + dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); + dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (is_luma) { + dc[0] = av_clipf(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clipf(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); + dc[5] = av_clipf(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); + dc[6] = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clipf(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); + dc[9] = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clipf(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); + dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) { + dc[0] = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } else if (!is_luma && (flags & 0x80)) { + dc[0] = av_clipf(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } else if (!is_luma && (flags & 0x20)) { + dc[0] = av_clipf(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } else if (!is_luma) { + dc[0] = av_clipf(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc); + dc[1] = av_clipf(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); + dc[2] = av_clipf(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } +} + +static void bink2f_decode_dc(Bink2Context *c, GetBitContext *gb, float *dc, + int is_luma, int q, int mindc, int maxdc, + int flags) +{ + const int num_dc = is_luma ? 16 : 4; + float tdc[16] = { 0 }; + int dc_bits; + + dc_bits = get_bits(gb, 3); + if (dc_bits == 7) + dc_bits += get_bits(gb, 2); + if (!dc_bits) { + memset(dc, 0, sizeof(*dc) * num_dc); + } else { + for (int j = 0; j < num_dc; j += 4) { + for (int i = 0; i < 4; i++) + tdc[i + j] = get_bits(gb, dc_bits); + + for (int i = 0; i < 4; i++) + if (tdc[i + j] && get_bits1(gb)) + tdc[i + j] = -tdc[i + j]; + } + } + + if ((flags & 0x20) && (flags & 0x80) && mindc >= 0) { + int bits = q_dc_bits[q] + dc_bits; + + if (bits < 10) { + int dc_val = get_bits(gb, 10 - bits); + + if (dc_val) { + dc_val <<= dc_bits; + if (get_bits1(gb)) + dc_val = -dc_val; + } + tdc[0] += dc_val; + } + } + + for (int i = 0; i < num_dc; i++) + tdc[i] *= bink2f_dc_quant[q]; + + bink2f_predict_dc(c, is_luma, mindc, maxdc, flags, tdc); +} + +static int bink2f_decode_ac(GetBitContext *gb, const uint8_t *scan, + float block[4][64], unsigned cbp, + float q, const float qmat[64]) +{ + int idx, next, val, skip; + VLC *val_vlc, *skip_vlc; + + for (int i = 0; i < 4; i++, cbp >>= 1) { + memset(block[i], 0, sizeof(**block) * 64); + + if (!(cbp & 1)) + continue; + + if (cbp & 0x10000) { + val_vlc = &bink2f_ac_val1_vlc; + skip_vlc = &bink2f_ac_skip1_vlc; + } else { + val_vlc = &bink2f_ac_val0_vlc; + skip_vlc = &bink2f_ac_skip0_vlc; + } + + next = 0; + idx = 1; + while (idx < 64) { + val = get_vlc2(gb, val_vlc->table, val_vlc->bits, 1); + if (val < 0) + return AVERROR_INVALIDDATA; + if (val) { + if (val >= 4) { + val -= 3; + val = get_bits(gb, val) + (1 << val) + 2; + } + if (get_bits1(gb)) + val = -val; + } + + block[i][scan[idx]] = val * q * qmat[scan[idx]]; + if (idx > 62) + break; + idx++; + next--; + if (next < 1) { + skip = get_vlc2(gb, skip_vlc->table, skip_vlc->bits, 1); + if (skip < 0) + return AVERROR_INVALIDDATA; + next = bink2_next_skips[skip]; + skip = bink2f_skips[skip]; + if (skip == 11) + skip = get_bits(gb, 6); + idx += skip; + } + } + } + + return 0; +} + +static int bink2f_decode_intra_luma(Bink2Context *c, + float block[4][64], + unsigned *prev_cbp, int *prev_q, + uint8_t *dst, int stride, + int flags) +{ + GetBitContext *gb = &c->gb; + float *dc = c->current_dc[c->mb_pos].dc[c->comp]; + int q, dq, ret; + unsigned cbp; + + *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp); + dq = bink2f_decode_delta_q(gb); + q = *prev_q + dq; + if (q < 0 || q >= 16) + return AVERROR_INVALIDDATA; + *prev_q = q; + + bink2f_decode_dc(c, gb, dc, 1, q, 0, 2047, flags); + + for (int i = 0; i < 4; i++) { + ret = bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (4 * i), + bink2f_ac_quant[q], bink2f_luma_intra_qmat); + if (ret < 0) + return ret; + + for (int j = 0; j < 4; j++) { + block[j][0] = dc[i * 4 + j] * 0.125f; + bink2f_idct_put(dst + (luma_repos[i*4+j]&3) * 8 + + (luma_repos[i*4+j]>>2) * 8 * stride, stride, block[j]); + } + } + + return 0; +} + +static int bink2f_decode_intra_chroma(Bink2Context *c, + float block[4][64], + unsigned *prev_cbp, int *prev_q, + uint8_t *dst, int stride, + int flags) +{ + GetBitContext *gb = &c->gb; + float *dc = c->current_dc[c->mb_pos].dc[c->comp]; + int q, dq, ret; + unsigned cbp; + + *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp); + dq = bink2f_decode_delta_q(gb); + q = *prev_q + dq; + if (q < 0 || q >= 16) + return AVERROR_INVALIDDATA; + *prev_q = q; + + bink2f_decode_dc(c, gb, dc, 0, q, 0, 2047, flags); + + ret = bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp, + bink2f_ac_quant[q], bink2f_chroma_qmat); + if (ret < 0) + return ret; + + for (int j = 0; j < 4; j++) { + block[j][0] = dc[j] * 0.125f; + bink2f_idct_put(dst + (j & 1) * 8 + (j >> 1) * 8 * stride, stride, block[j]); + } + + return 0; +} + +static int bink2f_decode_inter_luma(Bink2Context *c, + float block[4][64], + unsigned *prev_cbp, int *prev_q, + uint8_t *dst, int stride, + int flags) +{ + GetBitContext *gb = &c->gb; + float *dc = c->current_dc[c->mb_pos].dc[c->comp]; + unsigned cbp; + int q, dq; + + *prev_cbp = cbp = bink2f_decode_cbp_luma(gb, *prev_cbp); + dq = bink2f_decode_delta_q(gb); + q = *prev_q + dq; + if (q < 0 || q >= 16) + return AVERROR_INVALIDDATA; + *prev_q = q; + + bink2f_decode_dc(c, gb, dc, 1, q, -1023, 1023, 0xA8); + + for (int i = 0; i < 4; i++) { + bink2f_decode_ac(gb, bink2f_luma_scan, block, cbp >> (i * 4), + bink2f_ac_quant[q], bink2f_luma_inter_qmat); + for (int j = 0; j < 4; j++) { + block[j][0] = dc[i * 4 + j] * 0.125f; + bink2f_idct_add(dst + (luma_repos[i*4+j]&3) * 8 + + (luma_repos[i*4+j]>>2) * 8 * stride, stride, + block[j]); + } + } + + return 0; +} + +static int bink2f_decode_inter_chroma(Bink2Context *c, + float block[4][64], + unsigned *prev_cbp, int *prev_q, + uint8_t *dst, int stride, + int flags) +{ + GetBitContext *gb = &c->gb; + float *dc = c->current_dc[c->mb_pos].dc[c->comp]; + unsigned cbp; + int q, dq; + + *prev_cbp = cbp = bink2f_decode_cbp_chroma(gb, *prev_cbp); + dq = bink2f_decode_delta_q(gb); + q = *prev_q + dq; + if (q < 0 || q >= 16) + return AVERROR_INVALIDDATA; + *prev_q = q; + + bink2f_decode_dc(c, gb, dc, 0, q, -1023, 1023, 0xA8); + + bink2f_decode_ac(gb, bink2f_chroma_scan, block, cbp, + bink2f_ac_quant[q], bink2f_chroma_qmat); + + for (int i = 0; i < 4; i++) { + block[i][0] = dc[i] * 0.125f; + bink2f_idct_add(dst + (i & 1) * 8 + (i >> 1) * 8 * stride, stride, + block[i]); + } + + return 0; +} + +static void bink2f_predict_mv(Bink2Context *c, int x, int y, int flags, MVectors mv) +{ + MVectors *c_mv = &c->current_mv[c->mb_pos].mv; + MVectors *l_mv = &c->current_mv[FFMAX(c->mb_pos - 1, 0)].mv; + MVectors *lt_mv = &c->prev_mv[FFMAX(c->mb_pos - 1, 0)].mv; + MVectors *t_mv = &c->prev_mv[c->mb_pos].mv; + + if (!(flags & 0x80)) { + if (flags & 0x20) { + c_mv->v[0][0] = mv.v[0][0] + mid_pred(t_mv->v[0][0], t_mv->v[2][0], t_mv->v[3][0]); + c_mv->v[0][1] = mv.v[0][1] + mid_pred(t_mv->v[0][1], t_mv->v[2][1], t_mv->v[3][1]); + c_mv->v[1][0] = mv.v[1][0] + mid_pred(t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]); + c_mv->v[1][1] = mv.v[1][1] + mid_pred(t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]); + c_mv->v[2][0] = mv.v[2][0] + mid_pred(t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]); + c_mv->v[2][1] = mv.v[2][1] + mid_pred(t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]); + c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); + c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); + } else { + c_mv->v[0][0] = mv.v[0][0] + mid_pred(lt_mv->v[3][0], t_mv->v[2][0], l_mv->v[1][0]); + c_mv->v[0][1] = mv.v[0][1] + mid_pred(lt_mv->v[3][1], t_mv->v[2][1], l_mv->v[1][1]); + c_mv->v[1][0] = mv.v[1][0] + mid_pred( t_mv->v[2][0], t_mv->v[3][0], c_mv->v[0][0]); + c_mv->v[1][1] = mv.v[1][1] + mid_pred( t_mv->v[2][1], t_mv->v[3][1], c_mv->v[0][1]); + c_mv->v[2][0] = mv.v[2][0] + mid_pred( t_mv->v[2][0], c_mv->v[0][0], c_mv->v[1][0]); + c_mv->v[2][1] = mv.v[2][1] + mid_pred( t_mv->v[2][1], c_mv->v[0][1], c_mv->v[1][1]); + c_mv->v[3][0] = mv.v[3][0] + mid_pred( c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); + c_mv->v[3][1] = mv.v[3][1] + mid_pred( c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); + } + } else { + if (flags & 0x20) { + c_mv->v[0][0] = mv.v[0][0]; + c_mv->v[0][1] = mv.v[0][1]; + c_mv->v[1][0] = mv.v[1][0]; + c_mv->v[1][1] = mv.v[1][1]; + c_mv->v[2][0] = mv.v[2][0]; + c_mv->v[2][1] = mv.v[2][1]; + c_mv->v[3][0] = mv.v[3][0]; + c_mv->v[3][1] = mv.v[3][1]; + } else { + c_mv->v[0][0] = mv.v[0][0] + mid_pred(l_mv->v[0][0], l_mv->v[1][0], l_mv->v[3][0]); + c_mv->v[0][1] = mv.v[0][1] + mid_pred(l_mv->v[0][1], l_mv->v[1][1], l_mv->v[3][1]); + c_mv->v[2][0] = mv.v[2][0] + mid_pred(l_mv->v[1][0], l_mv->v[3][0], c_mv->v[0][0]); + c_mv->v[2][1] = mv.v[2][1] + mid_pred(l_mv->v[1][1], l_mv->v[3][1], c_mv->v[0][1]); + c_mv->v[1][0] = mv.v[1][0] + mid_pred(l_mv->v[1][0], c_mv->v[0][0], c_mv->v[2][0]); + c_mv->v[1][1] = mv.v[1][1] + mid_pred(l_mv->v[1][1], c_mv->v[0][1], c_mv->v[2][1]); + c_mv->v[3][0] = mv.v[3][0] + mid_pred(c_mv->v[0][0], c_mv->v[1][0], c_mv->v[2][0]); + c_mv->v[3][1] = mv.v[3][1] + mid_pred(c_mv->v[0][1], c_mv->v[1][1], c_mv->v[2][1]); + } + } +} + +#define CH1FILTER(src) ((6*(src)[0] + 2*(src)[1] + 4) >> 3) +#define CH2FILTER(src) (( (src)[0] + (src)[1] + 1) >> 1) +#define CH3FILTER(src) ((2*(src)[0] + 6*(src)[1] + 4) >> 3) + +#define CV1FILTER(src, i) ((6*(src)[0] + 2*(src)[i] + 4) >> 3) +#define CV2FILTER(src, i) (( (src)[0] + (src)[i] + 1) >> 1) +#define CV3FILTER(src, i) ((2*(src)[0] + 6*(src)[i] + 4) >> 3) + +static void bink2f_c_mc(Bink2Context *c, int x, int y, + uint8_t *dst, int stride, + uint8_t *src, int sstride, + int width, int height, + int mv_x, int mv_y, + int mode) +{ + uint8_t *msrc; + uint8_t temp[8*9]; + + if (mv_x < 0 || mv_x >= width || + mv_y < 0 || mv_y >= height) + return; + + msrc = src + mv_x + mv_y * sstride; + + switch (mode) { + case 0: + copy_block8(dst, msrc, stride, sstride, 8); + break; + case 1: + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CH1FILTER(msrc + i)); + dst += stride; + msrc += sstride; + } + break; + case 2: + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CH2FILTER(msrc + i)); + dst += stride; + msrc += sstride; + } + break; + case 3: + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CH3FILTER(msrc + i)); + dst += stride; + msrc += sstride; + } + break; + case 4: + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i*stride] = av_clip_uint8(CV1FILTER(msrc + i*sstride, sstride)); + dst += 1; + msrc += 1; + } + break; + case 5: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 6: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 7: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV1FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 8: + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i*stride] = av_clip_uint8(CV2FILTER(msrc + i*sstride, sstride)); + dst += 1; + msrc += 1; + } + break; + case 9: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 10: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 11: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV2FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 12: + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i*stride] = av_clip_uint8(CV3FILTER(msrc + i*sstride, sstride)); + dst += 1; + msrc += 1; + } + break; + case 13: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH1FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 14: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH2FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + case 15: + for (int i = 0; i < 9; i++) { + for (int j = 0; j < 8; j++) + temp[i*8+j] = av_clip_uint8(CH3FILTER(msrc + j)); + msrc += sstride; + } + for (int j = 0; j < 8; j++) { + for (int i = 0; i < 8; i++) + dst[i] = av_clip_uint8(CV3FILTER(temp+j*8+i, 8)); + dst += stride; + } + break; + } +} + +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; + if (c->has_alpha) + 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; +} + +#endif /* AVCODEC_BINK2F_H */ diff --git a/libavcodec/bink2g.h b/libavcodec/bink2g.h new file mode 100644 index 0000000000..be50146e4f --- /dev/null +++ b/libavcodec/bink2g.h @@ -0,0 +1,1870 @@ +/* + * 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 + */ + +#ifndef AVCODEC_BINK2G_H +#define AVCODEC_BINK2G_H + +#include +#include "avcodec.h" +#include "get_bits.h" +#include "bink2.h" + +static const uint8_t bink2g_scan[64] = { + 0, 8, 1, 2, 9, 16, 24, 17, + 10, 3, 4, 11, 18, 25, 32, 40, + 33, 26, 19, 12, 5, 6, 13, 20, + 27, 34, 41, 48, 56, 49, 42, 35, + 28, 21, 14, 7, 15, 22, 29, 36, + 43, 50, 57, 58, 51, 44, 37, 30, + 23, 31, 38, 45, 52, 59, 60, 53, + 46, 39, 47, 54, 61, 62, 55, 63, +}; + +static const uint16_t bink2g_ac_skip_codes[2][NUM_AC_SKIPS] = { + { + 0x01, 0x00, 0x004, 0x02C, 0x06C, 0x0C, 0x4C, + 0xAC, 0xEC, 0x12C, 0x16C, 0x1AC, 0x02, 0x1C, + }, + { + 0x01, 0x04, 0x00, 0x08, 0x02, 0x32, 0x0A, + 0x12, 0x3A, 0x7A, 0xFA, 0x72, 0x06, 0x1A, + }, +}; + +static const uint8_t bink2g_ac_skip_bits[2][NUM_AC_SKIPS] = { + { 1, 3, 4, 9, 9, 7, 7, 9, 8, 9, 9, 9, 2, 5 }, + { 1, 3, 4, 4, 5, 7, 5, 6, 7, 8, 8, 7, 3, 6 }, +}; + +static const uint8_t bink2g_mv_codes[] = { + 0x01, 0x06, 0x0C, 0x1C, 0x18, 0x38, 0x58, 0x78, + 0x68, 0x48, 0x28, 0x08, 0x14, 0x04, 0x02, 0x00, +}; + +static const uint8_t bink2g_mv_bits[] = { + 1, 3, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 3, 4, +}; + +static const uint8_t bink2g_skips[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 64, 0, 0, 0, +}; + +static uint8_t bink2g_chroma_cbp_pat[16] = { + 0x00, 0x00, 0x00, 0x0F, + 0x00, 0x0F, 0x0F, 0x0F, + 0x00, 0x0F, 0x0F, 0x0F, + 0x0F, 0x0F, 0x0F, 0x0F, +}; + +static const int32_t bink2g_dc_pat[] = { + 1024, 1218, 1448, 1722, 2048, + 2435, 2896, 3444, 4096, 4871, + 5793, 6889, 8192, 9742, 11585, 13777, 16384, + 19484, 23170, 27555, 32768, 38968, 46341, + 55109, 65536, 77936, 92682, 110218, 131072, + 155872, 185364, 220436, 262144, 311744, + 370728, 440872, 524288, +}; + +static const uint16_t bink2g_luma_intra_qmat[4][64] = { + { + 1024, 1432, 1506, 1181, + 1843, 2025, 5271, 8592, + 1313, 1669, 1630, 1672, + 2625, 3442, 8023, 12794, + 1076, 1755, 1808, 1950, + 3980, 4875, 8813, 11909, + 1350, 1868, 2127, 2016, + 4725, 4450, 7712, 9637, + 2458, 3103, 4303, 4303, + 6963, 6835, 11079, 13365, + 3375, 5704, 5052, 6049, + 9198, 7232, 10725, 9834, + 5486, 7521, 7797, 7091, + 11079, 10016, 13559, 12912, + 7279, 7649, 7020, 6097, + 9189, 9047, 12661, 13768, + }, + { + 1218, 1703, 1791, 1405, + 2192, 2408, 6268, 10218, + 1561, 1985, 1938, 1988, + 3122, 4093, 9541, 15215, + 1279, 2087, 2150, 2319, + 4733, 5798, 10481, 14162, + 1606, 2222, 2530, 2398, + 5619, 5292, 9171, 11460, + 2923, 3690, 5117, 5118, + 8281, 8128, 13176, 15894, + 4014, 6783, 6008, 7194, + 10938, 8600, 12755, 11694, + 6524, 8944, 9272, 8433, + 13176, 11911, 16125, 15354, + 8657, 9096, 8348, 7250, + 10927, 10759, 15056, 16373, + }, + { + 1448, 2025, 2130, 1671, + 2607, 2864, 7454, 12151, + 1856, 2360, 2305, 2364, + 3713, 4867, 11346, 18094, + 1521, 2482, 2557, 2758, + 5628, 6894, 12464, 16841, + 1909, 2642, 3008, 2852, + 6683, 6293, 10906, 13629, + 3476, 4388, 6085, 6086, + 9847, 9666, 15668, 18901, + 4773, 8066, 7145, 8555, + 13007, 10227, 15168, 13907, + 7758, 10637, 11026, 10028, + 15668, 14165, 19175, 18259, + 10294, 10817, 9927, 8622, + 12995, 12794, 17905, 19470, + }, + { + 1722, 2408, 2533, 1987, + 3100, 3406, 8864, 14450, + 2208, 2807, 2741, 2811, + 4415, 5788, 13493, 21517, + 1809, 2951, 3041, 3280, + 6693, 8199, 14822, 20028, + 2271, 3142, 3578, 3391, + 7947, 7484, 12969, 16207, + 4133, 5218, 7236, 7238, + 11711, 11495, 18633, 22478, + 5677, 9592, 8497, 10174, + 15469, 12162, 18038, 16538, + 9226, 12649, 13112, 11926, + 18633, 16845, 22804, 21715, + 12242, 12864, 11806, 10254, + 15454, 15215, 21293, 23155, + }, +}; + +static const uint16_t bink2g_chroma_intra_qmat[4][64] = { + { + 1024, 1193, 1434, 2203, + 5632, 4641, 5916, 6563, + 1193, 1622, 1811, 3606, + 6563, 5408, 6894, 7649, + 1434, 1811, 3515, 4875, + 5916, 4875, 6215, 6894, + 2203, 3606, 4875, 3824, + 4641, 3824, 4875, 5408, + 5632, 6563, 5916, 4641, + 5632, 4641, 5916, 6563, + 4641, 5408, 4875, 3824, + 4641, 3824, 4875, 5408, + 5916, 6894, 6215, 4875, + 5916, 4875, 6215, 6894, + 6563, 7649, 6894, 5408, + 6563, 5408, 6894, 7649, + }, + { + 1218, 1419, 1706, 2620, + 6698, 5519, 7035, 7805, + 1419, 1929, 2153, 4288, + 7805, 6432, 8199, 9096, + 1706, 2153, 4180, 5798, + 7035, 5798, 7390, 8199, + 2620, 4288, 5798, 4548, + 5519, 4548, 5798, 6432, + 6698, 7805, 7035, 5519, + 6698, 5519, 7035, 7805, + 5519, 6432, 5798, 4548, + 5519, 4548, 5798, 6432, + 7035, 8199, 7390, 5798, + 7035, 5798, 7390, 8199, + 7805, 9096, 8199, 6432, + 7805, 6432, 8199, 9096, + }, + { + 1448, 1688, 2028, 3116, + 7965, 6563, 8367, 9282, + 1688, 2294, 2561, 5099, + 9282, 7649, 9750, 10817, + 2028, 2561, 4971, 6894, + 8367, 6894, 8789, 9750, + 3116, 5099, 6894, 5408, + 6563, 5408, 6894, 7649, + 7965, 9282, 8367, 6563, + 7965, 6563, 8367, 9282, + 6563, 7649, 6894, 5408, + 6563, 5408, 6894, 7649, + 8367, 9750, 8789, 6894, + 8367, 6894, 8789, 9750, + 9282, 10817, 9750, 7649, + 9282, 7649, 9750, 10817, + }, + { + 1722, 2007, 2412, 3706, + 9472, 7805, 9950, 11038, + 2007, 2729, 3045, 6064, + 11038, 9096, 11595, 12864, + 2412, 3045, 5912, 8199, + 9950, 8199, 10452, 11595, + 3706, 6064, 8199, 6432, + 7805, 6432, 8199, 9096, + 9472, 11038, 9950, 7805, + 9472, 7805, 9950, 11038, + 7805, 9096, 8199, 6432, + 7805, 6432, 8199, 9096, + 9950, 11595, 10452, 8199, + 9950, 8199, 10452, 11595, + 11038, 12864, 11595, 9096, + 11038, 9096, 11595, 12864, + }, +}; + +static const uint16_t bink2g_inter_qmat[4][64] = { + { + 1024, 1193, 1076, 844, + 1052, 914, 1225, 1492, + 1193, 1391, 1254, 983, + 1227, 1065, 1463, 1816, + 1076, 1254, 1161, 936, + 1195, 1034, 1444, 1741, + 844, 983, 936, 811, + 1055, 927, 1305, 1584, + 1052, 1227, 1195, 1055, + 1451, 1336, 1912, 2354, + 914, 1065, 1034, 927, + 1336, 1313, 1945, 2486, + 1225, 1463, 1444, 1305, + 1912, 1945, 3044, 4039, + 1492, 1816, 1741, 1584, + 2354, 2486, 4039, 5679, + }, + { + 1218, 1419, 1279, 1003, + 1252, 1087, 1457, 1774, + 1419, 1654, 1491, 1169, + 1459, 1267, 1739, 2159, + 1279, 1491, 1381, 1113, + 1421, 1230, 1717, 2070, + 1003, 1169, 1113, 965, + 1254, 1103, 1552, 1884, + 1252, 1459, 1421, 1254, + 1725, 1589, 2274, 2799, + 1087, 1267, 1230, 1103, + 1589, 1562, 2313, 2956, + 1457, 1739, 1717, 1552, + 2274, 2313, 3620, 4803, + 1774, 2159, 2070, 1884, + 2799, 2956, 4803, 6753, + }, + { + 1448, 1688, 1521, 1193, + 1488, 1293, 1732, 2110, + 1688, 1967, 1773, 1391, + 1735, 1507, 2068, 2568, + 1521, 1773, 1642, 1323, + 1690, 1462, 2042, 2462, + 1193, 1391, 1323, 1147, + 1492, 1311, 1845, 2241, + 1488, 1735, 1690, 1492, + 2052, 1889, 2704, 3328, + 1293, 1507, 1462, 1311, + 1889, 1857, 2751, 3515, + 1732, 2068, 2042, 1845, + 2704, 2751, 4306, 5712, + 2110, 2568, 2462, 2241, + 3328, 3515, 5712, 8031, + }, + { + 1722, 2007, 1809, 1419, + 1770, 1537, 2060, 2509, + 2007, 2339, 2108, 1654, + 2063, 1792, 2460, 3054, + 1809, 2108, 1953, 1574, + 2010, 1739, 2428, 2928, + 1419, 1654, 1574, 1364, + 1774, 1559, 2195, 2664, + 1770, 2063, 2010, 1774, + 2440, 2247, 3216, 3958, + 1537, 1792, 1739, 1559, + 2247, 2209, 3271, 4181, + 2060, 2460, 2428, 2195, + 3216, 3271, 5120, 6793, + 2509, 3054, 2928, 2664, + 3958, 4181, 6793, 9550, + }, +}; + +static inline void bink2g_idct_1d(int16_t *blk, int step, int shift) +{ +#define idct_mul_a(val) ((val) + ((val) >> 2)) +#define idct_mul_b(val) ((val) >> 1) +#define idct_mul_c(val) ((val) - ((val) >> 2) - ((val) >> 4)) +#define idct_mul_d(val) ((val) + ((val) >> 2) - ((val) >> 4)) +#define idct_mul_e(val) ((val) >> 2) + int tmp00 = blk[3*step] + blk[5*step]; + int tmp01 = blk[3*step] - blk[5*step]; + int tmp02 = idct_mul_a(blk[2*step]) + idct_mul_b(blk[6*step]); + int tmp03 = idct_mul_b(blk[2*step]) - idct_mul_a(blk[6*step]); + int tmp0 = (blk[0*step] + blk[4*step]) + tmp02; + int tmp1 = (blk[0*step] + blk[4*step]) - tmp02; + int tmp2 = blk[0*step] - blk[4*step]; + int tmp3 = blk[1*step] + tmp00; + int tmp4 = blk[1*step] - tmp00; + int tmp5 = tmp01 + blk[7*step]; + int tmp6 = tmp01 - blk[7*step]; + int tmp7 = tmp4 + idct_mul_c(tmp6); + int tmp8 = idct_mul_c(tmp4) - tmp6; + int tmp9 = idct_mul_d(tmp3) + idct_mul_e(tmp5); + int tmp10 = idct_mul_e(tmp3) - idct_mul_d(tmp5); + int tmp11 = tmp2 + tmp03; + int tmp12 = tmp2 - tmp03; + + blk[0*step] = (tmp0 + tmp9) >> shift; + blk[1*step] = (tmp11 + tmp7) >> shift; + blk[2*step] = (tmp12 + tmp8) >> shift; + blk[3*step] = (tmp1 + tmp10) >> shift; + blk[4*step] = (tmp1 - tmp10) >> shift; + blk[5*step] = (tmp12 - tmp8) >> shift; + blk[6*step] = (tmp11 - tmp7) >> shift; + blk[7*step] = (tmp0 - tmp9) >> shift; +} + +static void bink2g_idct_put(uint8_t *dst, int stride, int16_t *block) +{ + for (int i = 0; i < 8; i++) + bink2g_idct_1d(block + i, 8, 0); + for (int i = 0; i < 8; i++) + bink2g_idct_1d(block + i * 8, 1, 6); + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) + dst[j] = av_clip_uint8(block[j * 8 + i]); + dst += stride; + } +} + +static void bink2g_idct_add(uint8_t *dst, int stride, int16_t *block) +{ + for (int i = 0; i < 8; i++) + bink2g_idct_1d(block + i, 8, 0); + for (int i = 0; i < 8; i++) + bink2g_idct_1d(block + i * 8, 1, 6); + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) + dst[j] = av_clip_uint8(dst[j] + block[j * 8 + i]); + dst += stride; + } +} + +static int bink2g_get_type(GetBitContext *gb, int *lru) +{ + int val; + + switch (get_unary(gb, 1, 3)) { + case 0: + val = lru[0]; + break; + case 1: + val = lru[1]; + FFSWAP(int, lru[0], lru[1]); + break; + case 2: + val = lru[3]; + FFSWAP(int, lru[2], lru[3]); + break; + case 3: + val = lru[2]; + FFSWAP(int, lru[1], lru[2]); + break; + } + + return val; +} + +static int bink2g_decode_dq(GetBitContext *gb) +{ + int dq = get_unary(gb, 1, 4); + + if (dq == 3) + dq += get_bits1(gb); + else if (dq == 4) + dq += get_bits(gb, 5) + 1; + if (dq && get_bits1(gb)) + dq = -dq; + + return dq; +} + +static unsigned bink2g_decode_cbp_luma(Bink2Context *c, + GetBitContext *gb, unsigned prev_cbp) +{ + unsigned ones = 0, cbp, mask; + + for (int i = 0; i < 16; i++) { + if (prev_cbp & (1 << i)) + ones += 1; + } + + cbp = 0; + mask = 0; + if (ones > 7) { + ones = 16 - ones; + mask = 0xFFFF; + } + + if (get_bits1(gb) == 0) { + if (ones < 4) { + for (int j = 0; j < 16; j += 4) + if (!get_bits1(gb)) + cbp |= get_bits(gb, 4) << j; + } else { + cbp = get_bits(gb, 16); + } + } + + cbp ^= mask; + if (!(c->frame_flags & 0x40000) || cbp) { + if (get_bits1(gb)) + cbp = cbp | cbp << 16; + } + + return cbp; +} + +static unsigned bink2g_decode_cbp_chroma(GetBitContext *gb, unsigned prev_cbp) +{ + unsigned cbp; + + cbp = prev_cbp & 0xF0000 | bink2g_chroma_cbp_pat[prev_cbp & 0xF]; + if (get_bits1(gb) == 0) { + cbp = get_bits(gb, 4); + if (get_bits1(gb)) + cbp |= cbp << 16; + } + + return cbp; +} + +static void bink2g_predict_dc(Bink2Context *c, + int is_luma, int mindc, int maxdc, + int flags, int tdc[16]) +{ + int *LTdc = c->prev_idc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; + int *Tdc = c->prev_idc[c->mb_pos].dc[c->comp]; + int *Ldc = c->current_idc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp]; + int *dc = c->current_idc[c->mb_pos].dc[c->comp]; + + if (is_luma && (flags & 0x20) && (flags & 0x80)) { + dc[0] = av_clip((mindc < 0 ? 0 : 1024) + tdc[0], mindc, maxdc); + dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clip(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); + dc[5] = av_clip(dc[4] + tdc[5], mindc, maxdc); + dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clip(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); + dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clip(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); + dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (is_luma && (flags & 0x80)) { + dc[0] = av_clip(DC_MPRED2(Ldc[5], Ldc[7]) + tdc[0], mindc, maxdc); + dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clip(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc); + dc[5] = av_clip(dc[4] + tdc[5], mindc, maxdc); + dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clip(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); + dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clip(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); + dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (is_luma && (flags & 0x20)) { + dc[0] = av_clip(DC_MPRED2(Tdc[10], Tdc[11]) + tdc[0], mindc, maxdc); + dc[1] = av_clip(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clip(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); + dc[5] = av_clip(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); + dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clip(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc); + dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clip(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc); + dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (is_luma) { + dc[0] = av_clip(DC_MPRED(LTdc[15], Ldc[5], Tdc[10]) + tdc[0], mindc, maxdc); + dc[1] = av_clip(DC_MPRED(Tdc[10], dc[0], Tdc[11]) + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED(Ldc[5], Ldc[7], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + dc[4] = av_clip(DC_MPRED(Tdc[11], dc[1], Tdc[14]) + tdc[4], mindc, maxdc); + dc[5] = av_clip(DC_MPRED(Tdc[14], dc[4], Tdc[15]) + tdc[5], mindc, maxdc); + dc[6] = av_clip(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc); + dc[7] = av_clip(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc); + dc[8] = av_clip(DC_MPRED(Ldc[7], Ldc[13], dc[2]) + tdc[8], mindc, maxdc); + dc[9] = av_clip(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc); + dc[10] = av_clip(DC_MPRED(Ldc[13], Ldc[15], dc[8]) + tdc[10], mindc, maxdc); + dc[11] = av_clip(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc); + dc[12] = av_clip(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc); + dc[13] = av_clip(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc); + dc[14] = av_clip(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc); + dc[15] = av_clip(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc); + } else if (!is_luma && (flags & 0x20) && (flags & 0x80)) { + dc[0] = av_clip((mindc < 0 ? 0 : 1024) + tdc[0], mindc, maxdc); + dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } else if (!is_luma && (flags & 0x80)) { + dc[0] = av_clip(DC_MPRED2(Ldc[1], Ldc[3]) + tdc[0], mindc, maxdc); + dc[1] = av_clip(dc[0] + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } else if (!is_luma && (flags & 0x20)) { + dc[0] = av_clip(DC_MPRED2(Tdc[2], Tdc[3]) + tdc[0], mindc, maxdc); + dc[1] = av_clip(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } else if (!is_luma) { + dc[0] = av_clip(DC_MPRED(LTdc[3], Ldc[1], Tdc[2]) + tdc[0], mindc, maxdc); + dc[1] = av_clip(DC_MPRED(Tdc[2], dc[0], Tdc[3]) + tdc[1], mindc, maxdc); + dc[2] = av_clip(DC_MPRED(Ldc[1], Ldc[3], dc[0]) + tdc[2], mindc, maxdc); + dc[3] = av_clip(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc); + } +} + +static void bink2g_decode_dc(Bink2Context *c, GetBitContext *gb, int *dc, + int is_luma, int q, int mindc, int maxdc, + int flags) +{ + const int num_dc = is_luma ? 16 : 4; + int tdc[16]; + int pat; + + q = FFMAX(q, 8); + pat = bink2g_dc_pat[q]; + + memset(tdc, 0, sizeof(tdc)); + + if (get_bits1(gb)) { + for (int i = 0; i < num_dc; i++) { + int cnt = get_unary(gb, 0, 12); + + if (cnt > 3) + cnt = (1 << (cnt - 3)) + get_bits(gb, cnt - 3) + 2; + if (cnt && get_bits1(gb)) + cnt = -cnt; + tdc[i] = (cnt * pat + 0x1FF) >> 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], + uint8_t ac_count[4]) +{ + int idx, next, val, skip; + VLC *skip_vlc; + + for (int i = 0; i < 4; i++) { + memset(block[i], 0, sizeof(int16_t) * 64); + ac_count[i] = 0; + } + + 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; + ac_count[i]++; + idx++; + } + } + + return 0; +} + +static inline uint16_t bink2g_block_state(int dc, unsigned ac_count, int intra) +{ + const unsigned strength = (ac_count < 8) + (ac_count < 4) + !ac_count; + + return (dc & 0x1FFF) | (strength << 13) | (intra ? 0x8000 : 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]; + uint16_t *state = c->current_idc[c->mb_pos].state[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++) { + uint8_t ac_count[4]; + + ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp >> (4*i), + q, bink2g_luma_intra_qmat, ac_count); + if (ret < 0) + return ret; + + for (int j = 0; j < 4; j++) { + const int block_index = i * 4 + j; + const int raster_index = luma_repos[block_index]; + + state[raster_index] = bink2g_block_state(dc[block_index], ac_count[j], 1); + block[j][0] = dc[block_index] * 8 + 32; + bink2g_idct_put(dst + (raster_index & 3) * 8 + + (raster_index >> 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]; + uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; + uint8_t ac_count[4]; + 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, ac_count); + if (ret < 0) + return ret; + + for (int j = 0; j < 4; j++) { + state[j] = bink2g_block_state(dc[j], ac_count[j], 1); + 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]; + uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; + const int maxdc = c->frame_flags & 0x40000 ? 2047 : 1023; + unsigned cbp; + int ret; + + *prev_cbp = cbp = bink2g_decode_cbp_luma(c, gb, *prev_cbp); + + bink2g_decode_dc(c, gb, dc, 1, q, -maxdc, maxdc, 0xA8); + + for (int i = 0; i < 4; i++) { + uint8_t ac_count[4]; + + ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp >> (4 * i), + q, bink2g_inter_qmat, ac_count); + if (ret < 0) + return ret; + + for (int j = 0; j < 4; j++) { + const int block_index = i * 4 + j; + const int raster_index = luma_repos[block_index]; + + state[raster_index] = bink2g_block_state(dc[block_index], ac_count[j], 0); + block[j][0] = dc[block_index] * 8 + 32; + bink2g_idct_add(dst + (raster_index & 3) * 8 + + (raster_index >> 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]; + uint16_t *state = c->current_idc[c->mb_pos].state[c->comp]; + uint8_t ac_count[4]; + const int maxdc = c->frame_flags & 0x40000 ? 2047 : 1023; + unsigned cbp; + int ret; + + *prev_cbp = cbp = bink2g_decode_cbp_chroma(gb, *prev_cbp); + + bink2g_decode_dc(c, gb, dc, 0, q, -maxdc, maxdc, 0xA8); + + ret = bink2g_decode_ac(gb, bink2g_scan, block, cbp, + q, bink2g_inter_qmat, ac_count); + if (ret < 0) + return ret; + + for (int j = 0; j < 4; j++) { + state[j] = bink2g_block_state(dc[j], ac_count[j], 0); + 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 { + const int left_v1 = mv.nb_vectors == 0 ? 3 : 1; + + 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[left_v1][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[left_v1][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; +} + +static const uint8_t bink2g_chroma_weights[4][2] = { + { 1, 0 }, + { 3, 1 }, + { 1, 1 }, + { 1, 3 }, +}; + +static const uint8_t bink2g_chroma_shifts[4] = { 0, 2, 1, 2 }; + +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) +{ + const uint8_t *msrc; + int hphase, vphase, shift, rounding; + + 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_block8(dst, msrc, stride, sstride, 8); + return; + } + + hphase = mode & 3; + vphase = mode >> 2; + shift = bink2g_chroma_shifts[hphase] + bink2g_chroma_shifts[vphase]; + rounding = 1 << (shift - 1); + + for (int y = 0; y < 8; y++) { + const uint8_t *top = msrc + y * sstride; + const uint8_t *bottom = top + (vphase != 0) * sstride; + + for (int x = 0; x < 8; x++) { + const int top_value = bink2g_chroma_weights[hphase][0] * top[x] + + bink2g_chroma_weights[hphase][1] * top[x + (hphase != 0)]; + const int bottom_value = bink2g_chroma_weights[hphase][0] * bottom[x] + + bink2g_chroma_weights[hphase][1] * bottom[x + (hphase != 0)]; + const int value = bink2g_chroma_weights[vphase][0] * top_value + + bink2g_chroma_weights[vphase][1] * bottom_value; + + dst[x] = (value + rounding) >> shift; + } + dst += stride; + } +} + +static void bink2g_filter_vertical_edge(uint8_t *p, int stride, + unsigned left, unsigned right) +{ + const unsigned index = left | (right << 2); + + if (!index || index == 15) + return; + + for (int y = 0; y < 8; y++, p += stride) { + const int b = p[-1]; + const int c = p[0]; + const int delta = c - b; + const int outer = (2 * delta + 8) >> 4; + const int inner = (4 * delta + 8) >> 4; + + if (left >= 2) + p[-2] = av_clip_uint8(p[-2] + outer); + if (left >= 1) + p[-1] = av_clip_uint8(b + inner); + if (right >= 1) + p[0] = av_clip_uint8(c - inner); + if (right >= 2) + p[1] = av_clip_uint8(p[1] - outer); + } +} + +static void bink2g_filter_horizontal_edge(uint8_t *p, int stride, + unsigned top, unsigned bottom) +{ + const unsigned index = top | (bottom << 2); + + if (!index || index == 15) + return; + + for (int x = 0; x < 8; x++, p++) { + const int b = p[-stride]; + const int c = p[0]; + const int delta = c - b; + const int outer = (2 * delta + 8) >> 4; + const int inner = (4 * delta + 8) >> 4; + + if (top >= 2) + p[-2 * stride] = av_clip_uint8(p[-2 * stride] + outer); + if (top >= 1) + p[-stride] = av_clip_uint8(b + inner); + if (bottom >= 1) + p[0] = av_clip_uint8(c - inner); + if (bottom >= 2) + p[stride] = av_clip_uint8(p[stride] - outer); + } +} + +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; +} + +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) { + int16_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] = 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 inline unsigned bink2g_filter_strength(uint16_t state) +{ + return (state >> 13) & 3; +} + +static inline int bink2g_filter_map_skip(const uint8_t *map, int position) +{ + const unsigned bit = position >> 3; + + return (map[bit >> 3] >> (bit & 7)) & 1; +} + +static inline int bink2g_mv_discontinuity(const MVectors *a, int ai, + const MVectors *b, int bi) +{ + return FFABS(a->v[ai][0] - b->v[bi][0]) > 1 || + FFABS(a->v[ai][1] - b->v[bi][1]) > 1; +} + +static inline void bink2g_force_mv_edge(const MVectors *a, int ai, + const MVectors *b, int bi, + uint16_t left_state, + uint16_t right_state, + unsigned *left, unsigned *right) +{ + if (!(left_state & 0x8000) && !(right_state & 0x8000) && + bink2g_mv_discontinuity(a, ai, b, bi)) + *left = *right = 2; +} + +static inline void bink2g_select_coding_edge(uint16_t left_state, + uint16_t right_state, + unsigned *left, + unsigned *right) +{ + const int left_intra = !!(left_state & 0x8000); + const int right_intra = !!(right_state & 0x8000); + + if (!left_intra) + *left = 0; + if (!right_intra) + *right = 0; +} + +static inline int bink2g_recon_near(uint16_t a, uint16_t b, int threshold) +{ + const int16_t ab = (int16_t)(uint16_t)(a - b); + const int16_t ba = (int16_t)(uint16_t)(b - a); + + return FFMAX(ab, ba) < threshold; +} + +static inline int bink2g_recon_mulhi(int k, int v) +{ + return ((int32_t)(int16_t)k * (int16_t)v) >> 16; +} + +static inline int bink2g_recon_curve(int base, int left, int right, int pos) +{ + switch (pos) { + case 0: return base + bink2g_recon_mulhi(26624, left); + case 1: return base + bink2g_recon_mulhi(18432, left) + (right >> 7); + case 2: return base + bink2g_recon_mulhi(12288, left) + (right >> 5); + case 3: return base + bink2g_recon_mulhi( 7168, left) + (right >> 4); + case 4: return base + bink2g_recon_mulhi( 7168, right) + (left >> 4); + case 5: return base + bink2g_recon_mulhi(12288, right) + (left >> 5); + case 6: return base + bink2g_recon_mulhi(18432, right) + (left >> 7); + default:return base + bink2g_recon_mulhi(26624, right); + } +} + +static inline uint16_t bink2g_recon_state(const DCIPredict *row, int comp, + int blocks_per_mb, int blocks_w, + int block_x, int block_y) +{ + block_x = av_clip(block_x, 0, blocks_w - 1); + return row[block_x / blocks_per_mb].state[comp] + [block_y * blocks_per_mb + block_x % blocks_per_mb]; +} + +static void bink2g_reconstruct_block(uint8_t *dst, int stride, + int width, int height, + uint16_t left, uint16_t target, + uint16_t right, uint16_t up_left, + uint16_t up, uint16_t up_right, + uint16_t down_left, uint16_t down, + uint16_t down_right, int threshold) +{ + int center[8], top[8], bottom[8]; + int d, l, r, u, v, ul, ur, dl, dr; + + if (target < 0xE000 || width <= 0 || height <= 0) + return; + + d = target & 0x1FFF; + l = bink2g_recon_near(target, left, threshold) ? left & 0x1FFF : d; + r = bink2g_recon_near(target, right, threshold) ? right & 0x1FFF : d; + u = bink2g_recon_near(target, up, threshold) ? up & 0x1FFF : d; + v = bink2g_recon_near(target, down, threshold) ? down & 0x1FFF : d; + ul = bink2g_recon_near(target, up_left, threshold) ? up_left & 0x1FFF : l; + ur = bink2g_recon_near(target, up_right, threshold) ? up_right & 0x1FFF : r; + dl = bink2g_recon_near(target, down_left, threshold) ? down_left & 0x1FFF : l; + dr = bink2g_recon_near(target, down_right, threshold) ? down_right & 0x1FFF : r; + + for (int x = 0; x < 8; x++) { + center[x] = bink2g_recon_curve(d + 4, l - d, r - d, x); + top[x] = bink2g_recon_curve(u + 4, ul - u, ur - u, x) - center[x]; + bottom[x] = bink2g_recon_curve(v + 4, dl - v, dr - v, x) - center[x]; + } + + for (int y = 0; y < FFMIN(height, 8); y++) { + for (int x = 0; x < FFMIN(width, 8); x++) + dst[x] = av_clip_uint8(bink2g_recon_curve(center[x], top[x], + bottom[x], y) >> 3); + dst += stride; + } +} + +static void bink2g_reconstruct_blocks(Bink2Context *c, uint8_t *dst, + int stride, int comp, int global_y, + const DCIPredict *up_row, int up_by, + const DCIPredict *row, int by, + const DCIPredict *down_row, int down_by) +{ + const int chroma = comp == 1 || comp == 2; + const int blocks_per_mb = chroma ? 2 : 4; + const int plane_w = chroma ? (c->avctx->width + 1) >> 1 : c->avctx->width; + const int plane_h = chroma ? (c->avctx->height + 1) >> 1 : c->avctx->height; + const int visible_blocks_w = (plane_w + 7) >> 3; + const int coded_blocks_w = ((c->avctx->width + 31) >> 5) * blocks_per_mb; + const int coded_plane_h = ((c->avctx->height + 31) >> 5) * + blocks_per_mb * 8; + const int threshold = (c->frame_flags & 0xFF) << 3; + const int have_up = global_y >= 8; + const int have_down = global_y + 8 < coded_plane_h; + + for (int bx = 0; bx < visible_blocks_w; bx++) { + const uint16_t target = bink2g_recon_state(row, comp, blocks_per_mb, + coded_blocks_w, bx, by); + const uint16_t left = bx ? + bink2g_recon_state(row, comp, blocks_per_mb, + coded_blocks_w, bx - 1, by) : target; + const uint16_t right = bx + 1 < coded_blocks_w ? + bink2g_recon_state(row, comp, blocks_per_mb, + coded_blocks_w, bx + 1, by) : target; + const uint16_t up_left = have_up && bx ? + bink2g_recon_state(up_row, comp, blocks_per_mb, + coded_blocks_w, bx - 1, up_by) : 0; + const uint16_t up = have_up ? + bink2g_recon_state(up_row, comp, blocks_per_mb, + coded_blocks_w, bx, up_by) : target; + const uint16_t up_right = have_up && bx + 1 < coded_blocks_w ? + bink2g_recon_state(up_row, comp, blocks_per_mb, + coded_blocks_w, bx + 1, up_by) : 0; + const uint16_t down_left = bx ? + have_down ? + bink2g_recon_state(down_row, comp, blocks_per_mb, + coded_blocks_w, bx - 1, down_by) : + (target & 0xE000) | (left & 0x1FFF) : 0; + const uint16_t down = have_down ? + bink2g_recon_state(down_row, comp, blocks_per_mb, + coded_blocks_w, bx, down_by) : target; + const uint16_t down_right = bx + 1 < coded_blocks_w ? + have_down ? + bink2g_recon_state(down_row, comp, blocks_per_mb, + coded_blocks_w, bx + 1, down_by) : + (target & 0xE000) | (right & 0x1FFF) : 0; + + bink2g_reconstruct_block(dst + bx * 8, stride, + plane_w - bx * 8, plane_h - global_y, + left, target, right, up_left, up, up_right, + down_left, down, down_right, threshold); + } +} + +static void bink2g_reconstruct_row(Bink2Context *c, uint8_t *dst[4], + const int stride[4], int y, + const DCIPredict *prev_idc, + const DCIPredict *current_idc, + int is_last) +{ + for (int comp = 0; comp < 3 + c->has_alpha; comp++) { + const int chroma = comp == 1 || comp == 2; + const int plane = comp == 1 ? 2 : comp == 2 ? 1 : comp; + const int blocks_per_mb = chroma ? 2 : 4; + const int plane_y = chroma ? y >> 1 : y; + + if (y > 0) { + const int by = blocks_per_mb - 1; + + bink2g_reconstruct_blocks(c, dst[plane] - 8 * stride[plane], + stride[plane], comp, plane_y - 8, + prev_idc, by - 1, + prev_idc, by, + current_idc, 0); + } + + for (int by = 0; by < blocks_per_mb - 1; by++) { + const DCIPredict *up_row = by ? current_idc : + y > 0 ? prev_idc : current_idc; + const int up_by = by ? by - 1 : + y > 0 ? blocks_per_mb - 1 : 0; + + bink2g_reconstruct_blocks(c, dst[plane] + by * 8 * stride[plane], + stride[plane], comp, plane_y + by * 8, + up_row, up_by, + current_idc, by, + current_idc, by + 1); + } + + if (is_last) { + const int by = blocks_per_mb - 1; + + bink2g_reconstruct_blocks(c, dst[plane] + by * 8 * stride[plane], + stride[plane], comp, plane_y + by * 8, + current_idc, by - 1, + current_idc, by, + current_idc, by); + } + } +} + +static void bink2g_filter_vertical_row(Bink2Context *c, uint8_t *dst[4], + const int stride[4], int comp, + const DCIPredict *row, + const MVPredict *mv_row, + int by, int rel_y) +{ + const int chroma = comp != 0; + const int plane = comp == 1 ? 2 : comp == 2 ? 1 : 0; + const int blocks_per_mb = chroma ? 2 : 4; + const int plane_w = chroma ? (c->avctx->width + 1) >> 1 : c->avctx->width; + const int blocks_w = (plane_w + 7) >> 3; + + if (c->frame_flags & 0x4000) + return; + + for (int bx = 1; bx < blocks_w; bx++) { + const int mb = bx / blocks_per_mb; + const int local_x = bx % blocks_per_mb; + const int left_mb = local_x ? mb : mb - 1; + const int left_x = local_x ? local_x - 1 : blocks_per_mb - 1; + const uint16_t left_state = row[left_mb].state[comp] + [by * blocks_per_mb + left_x]; + const uint16_t right_state = row[mb].state[comp] + [by * blocks_per_mb + local_x]; + unsigned left = bink2g_filter_strength(left_state); + unsigned right = bink2g_filter_strength(right_state); + const int edge_x = bx * (chroma ? 16 : 8); + + bink2g_select_coding_edge(left_state, right_state, &left, &right); + + if (edge_x >= c->avctx->width || + bink2g_filter_map_skip(c->col_cbp, edge_x)) + continue; + + if (chroma || !(bx & 1)) { + const int qrow = chroma ? by : by >> 1; + const int left_q = 2 * qrow + (local_x ? 0 : 1); + const int right_q = 2 * qrow + (local_x ? 1 : 0); + + bink2g_force_mv_edge(&mv_row[left_mb].mv, left_q, + &mv_row[mb].mv, right_q, + left_state, right_state, &left, &right); + } + + bink2g_filter_vertical_edge(dst[plane] + bx * 8 + + rel_y * stride[plane], + stride[plane], left, right); + } +} + +static void bink2g_filter_horizontal_row(Bink2Context *c, uint8_t *dst[4], + const int stride[4], int comp, + const DCIPredict *top_row, int top_by, + const MVPredict *top_mv, + const DCIPredict *bottom_row, int bottom_by, + const MVPredict *bottom_mv, + int rel_y, int edge_y, int slice_start) +{ + const int chroma = comp != 0; + const int plane = comp == 1 ? 2 : comp == 2 ? 1 : 0; + const int blocks_per_mb = chroma ? 2 : 4; + const int plane_w = chroma ? (c->avctx->width + 1) >> 1 : c->avctx->width; + const int blocks_w = (plane_w + 7) >> 3; + + if ((c->frame_flags & 0x8000) || edge_y == slice_start || + edge_y >= c->avctx->height || + bink2g_filter_map_skip(c->row_cbp, edge_y)) + return; + + for (int bx = 0; bx < blocks_w; bx++) { + const int mb = bx / blocks_per_mb; + const int local_x = bx % blocks_per_mb; + const uint16_t top_state = top_row[mb].state[comp] + [top_by * blocks_per_mb + local_x]; + const uint16_t bottom_state = bottom_row[mb].state[comp] + [bottom_by * blocks_per_mb + local_x]; + unsigned top = bink2g_filter_strength(top_state); + unsigned bottom = bink2g_filter_strength(bottom_state); + + bink2g_select_coding_edge(top_state, bottom_state, &top, &bottom); + + if (chroma || bottom_by == 0 || bottom_by == 2) { + const int qcol = chroma ? local_x : local_x >> 1; + const int top_q = (bottom_by ? 0 : 2) + qcol; + const int bottom_q = (bottom_by ? 2 : 0) + qcol; + + bink2g_force_mv_edge(&top_mv[mb].mv, top_q, + &bottom_mv[mb].mv, bottom_q, + top_state, bottom_state, &top, &bottom); + } + + bink2g_filter_horizontal_edge(dst[plane] + bx * 8 + + rel_y * stride[plane], + stride[plane], top, bottom); + } +} + +static void bink2g_postprocess_row(Bink2Context *c, uint8_t *dst[4], + const int stride[4], int y, + int frame_end, + const DCIPredict *prev_idc, + const DCIPredict *current_idc, + const MVPredict *prev_mv, + const MVPredict *current_mv) +{ + const int is_last = y + 32 >= frame_end; + + bink2g_reconstruct_row(c, dst, stride, y, + prev_idc, current_idc, is_last); + + for (int comp = 0; comp < 3; comp++) { + const int chroma = comp != 0; + const int blocks_per_mb = chroma ? 2 : 4; + + if (y > 0) + bink2g_filter_vertical_row(c, dst, stride, comp, prev_idc, + prev_mv, + blocks_per_mb - 1, -8); + for (int by = 0; by < blocks_per_mb - 1; by++) + bink2g_filter_vertical_row(c, dst, stride, comp, current_idc, + current_mv, by, by * 8); + if (is_last) + bink2g_filter_vertical_row(c, dst, stride, comp, current_idc, + current_mv, + blocks_per_mb - 1, + (blocks_per_mb - 1) * 8); + } + + if (y > 0) { + bink2g_filter_horizontal_row(c, dst, stride, 0, + prev_idc, 2, prev_mv, + prev_idc, 3, prev_mv, + -8, y - 8, 0); + bink2g_filter_horizontal_row(c, dst, stride, 0, + prev_idc, 3, prev_mv, + current_idc, 0, current_mv, + 0, y, 0); + for (int comp = 1; comp <= 2; comp++) { + bink2g_filter_horizontal_row(c, dst, stride, comp, + prev_idc, 0, prev_mv, + prev_idc, 1, prev_mv, + -8, y - 16, 0); + bink2g_filter_horizontal_row(c, dst, stride, comp, + prev_idc, 1, prev_mv, + current_idc, 0, current_mv, + 0, y, 0); + } + } + + bink2g_filter_horizontal_row(c, dst, stride, 0, + current_idc, 0, current_mv, + current_idc, 1, current_mv, + 8, y + 8, 0); + bink2g_filter_horizontal_row(c, dst, stride, 0, + current_idc, 1, current_mv, + current_idc, 2, current_mv, + 16, y + 16, 0); + + if (is_last) { + bink2g_filter_horizontal_row(c, dst, stride, 0, + current_idc, 2, current_mv, + current_idc, 3, current_mv, + 24, y + 24, 0); + for (int comp = 1; comp <= 2; comp++) + bink2g_filter_horizontal_row(c, dst, stride, comp, + current_idc, 0, current_mv, + current_idc, 1, current_mv, + 8, y + 16, 0); + } +} + +static void bink2g_postprocess_frame(Bink2Context *c, uint8_t *dst[4], + const int stride[4]) +{ + const int mb_width = (c->avctx->width + 31) >> 5; + const int mb_height = (c->avctx->height + 31) >> 5; + const int frame_end = mb_height << 5; + + for (int mb_y = 0; mb_y < mb_height; mb_y++) { + const int y = mb_y << 5; + const int prev_y = mb_y ? mb_y - 1 : 0; + const DCIPredict *prev_idc = c->frame_idc + prev_y * mb_width; + const DCIPredict *current_idc = c->frame_idc + mb_y * mb_width; + const MVPredict *prev_mv = c->frame_mv + prev_y * mb_width; + const MVPredict *current_mv = c->frame_mv + mb_y * mb_width; + uint8_t *row_dst[4] = { + dst[0] + y * stride[0], + dst[1] + (y >> 1) * stride[1], + dst[2] + (y >> 1) * stride[2], + c->has_alpha ? dst[3] + y * stride[3] : NULL, + }; + + bink2g_postprocess_row(c, row_dst, stride, y, frame_end, + prev_idc, current_idc, prev_mv, current_mv); + } +} + +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; + const int mb_width = (w + 31) / 32; + int ret = 0, dq, flags; + + memset(c->prev_q, 0, mb_width * sizeof(*c->prev_q)); + memset(c->prev_mv, 0, mb_width * sizeof(*c->prev_mv)); + memset(c->prev_idc, 0, mb_width * sizeof(*c->prev_idc)); + memset(c->current_idc, 0, mb_width * sizeof(*c->current_idc)); + + 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; + memset(c->current_idc[c->mb_pos].state, 0, + sizeof(c->current_idc[c->mb_pos].state)); + 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; + } + + } + + memcpy(c->frame_idc + (y >> 5) * mb_width, c->current_idc, + mb_width * sizeof(*c->frame_idc)); + memcpy(c->frame_mv + (y >> 5) * mb_width, c->current_mv, + mb_width * sizeof(*c->frame_mv)); + + dst[0] += stride[0] * 32; + dst[1] += stride[1] * 16; + dst[2] += stride[2] * 16; + if (c->has_alpha) + 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; +} + +#endif /* AVCODEC_BINK2G_H */ diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index d58c3d889c..92c27e58d4 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1959,6 +1959,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("LEAD MCMP"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_BINKVIDEO2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "binkvideo2", + .long_name = NULL_IF_CONFIG_SMALL("Bink video 2"), + .props = AV_CODEC_PROP_LOSSY, + }, /* various PCM "codecs" */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index 0a8d3bed1e..a7e874c890 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -322,6 +322,7 @@ enum AVCodecID { AV_CODEC_ID_RTV1, AV_CODEC_ID_VMIX, AV_CODEC_ID_LEAD, + AV_CODEC_ID_BINKVIDEO2, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs diff --git a/libavformat/bink.c b/libavformat/bink.c index 0632d390a2..fbb0238795 100644 --- a/libavformat/bink.c +++ b/libavformat/bink.c @@ -72,7 +72,7 @@ static int probe(const AVProbeData *p) b[3] == 'k')) || (b[0] == 'K' && b[1] == 'B' && b[2] == '2' && /* Bink 2 */ (b[3] == 'a' || b[3] == 'd' || b[3] == 'f' || b[3] == 'g' || b[3] == 'h' || - b[3] == 'i' || b[3] == 'j' || b[3] == 'k'))) && + b[3] == 'i' || b[3] == 'j' || b[3] == 'k' || b[3] == 'm' || b[3] == 'n'))) && AV_RL32(b+8) > 0 && // num_frames AV_RL32(b+20) > 0 && AV_RL32(b+20) <= BINK_MAX_WIDTH && AV_RL32(b+24) > 0 && AV_RL32(b+24) <= BINK_MAX_HEIGHT && @@ -149,8 +149,7 @@ static int read_header(AVFormatContext *s) vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO; if ((vst->codecpar->codec_tag & 0xFFFFFF) == MKTAG('K', 'B', '2', 0)) { - av_log(s, AV_LOG_WARNING, "Bink 2 video is not implemented\n"); - vst->codecpar->codec_id = AV_CODEC_ID_NONE; + vst->codecpar->codec_id = AV_CODEC_ID_BINKVIDEO2; } if ((ret = ff_get_extradata(s, vst->codecpar, pb, 4)) < 0) @@ -168,8 +167,11 @@ static int read_header(AVFormatContext *s) signature = (vst->codecpar->codec_tag & 0xFFFFFF); revision = ((vst->codecpar->codec_tag >> 24) % 0xFF); - if ((signature == AV_RL32("BIK") && (revision == 'k')) || - (signature == AV_RL32("KB2") && (revision == 'i' || revision == 'j' || revision == 'k'))) + if (signature == AV_RL32("KB2") && revision == 'm') + avio_skip(pb, 16); /* opaque KB2m header extension */ + else if ((signature == AV_RL32("BIK") && revision == 'k') || + (signature == AV_RL32("KB2") && + (revision == 'i' || revision == 'j' || revision == 'k' || revision == 'n'))) avio_skip(pb, 4); /* unknown new field */ if (bink->num_audio_tracks) {