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

Peter Ross pross at xvid.org
Sun Mar 22 01:08:39 EET 2020


On Fri, Mar 20, 2020 at 02:31:05PM +0100, Paul B Mahol wrote:
> Signed-off-by: Paul B Mahol <onemda at gmail.com>
> ---
>  configure               |    1 +
>  libavcodec/Makefile     |    1 +
>  libavcodec/allcodecs.c  |    1 +
>  libavcodec/avcodec.h    |    1 +
>  libavcodec/bink2.c      |  869 ++++++++++++++++++++++++++++
>  libavcodec/bink2f.c     | 1125 ++++++++++++++++++++++++++++++++++++
>  libavcodec/bink2g.c     | 1197 +++++++++++++++++++++++++++++++++++++++
>  libavcodec/codec_desc.c |    7 +
>  libavformat/bink.c      |    3 +-
>  9 files changed, 3203 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/bink2.c
>  create mode 100644 libavcodec/bink2f.c
>  create mode 100644 libavcodec/bink2g.c

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

> +static void bink2f_predict_dc(Bink2Context *c,
> +                              int is_luma, float mindc, float maxdc,
> +                              int flags, float tdc[16])
> +{
> +    float *LTdc = c->prev_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];

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

> +    float *Tdc = c->prev_dc[c->mb_pos].dc[c->comp];
> +    float *Ldc = c->current_dc[FFMAX(c->mb_pos - 1, 0)].dc[c->comp];
> +    float *dc = c->current_dc[c->mb_pos].dc[c->comp];
> +
> +    if (is_luma && (flags & 0x20) && (flags & 0x80)) {
> +        dc[0]  = av_clipf((mindc < 0 ? 0 : 1024.f) + tdc[0], mindc, maxdc);
> +        dc[1]  = av_clipf(dc[0] + tdc[1], mindc, maxdc);
> +        dc[2]  = av_clipf(DC_MPRED2(dc[0], dc[1]) + tdc[2], mindc, maxdc);
> +        dc[3]  = av_clipf(DC_MPRED(dc[0], dc[2], dc[1]) + tdc[3], mindc, maxdc);
> +        dc[4]  = av_clipf(DC_MPRED2(dc[1], dc[3]) + tdc[4], mindc, maxdc);
> +        dc[5]  = av_clipf(dc[4] + tdc[5], mindc, maxdc);
> +        dc[6]  = av_clipf(DC_MPRED(dc[1], dc[3], dc[4]) + tdc[6], mindc, maxdc);
> +        dc[7]  = av_clipf(DC_MPRED(dc[4], dc[6], dc[5]) + tdc[7], mindc, maxdc);
> +        dc[8]  = av_clipf(DC_MPRED2(dc[2], dc[3]) + tdc[8], mindc, maxdc);
> +        dc[9]  = av_clipf(DC_MPRED(dc[2], dc[8], dc[3]) + tdc[9], mindc, maxdc);
> +        dc[10] = av_clipf(DC_MPRED2(dc[8], dc[9]) + tdc[10], mindc, maxdc);
> +        dc[11] = av_clipf(DC_MPRED(dc[8], dc[10], dc[9]) + tdc[11], mindc, maxdc);
> +        dc[12] = av_clipf(DC_MPRED(dc[3], dc[9], dc[6]) + tdc[12], mindc, maxdc);
> +        dc[13] = av_clipf(DC_MPRED(dc[6], dc[12], dc[7]) + tdc[13], mindc, maxdc);
> +        dc[14] = av_clipf(DC_MPRED(dc[9], dc[11], dc[12]) + tdc[14], mindc, maxdc);
> +        dc[15] = av_clipf(DC_MPRED(dc[12], dc[14], dc[13]) + tdc[15], mindc, maxdc);
> +    } else if (is_luma && (flags & 0x80)) {

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

> +static int bink2f_decode_slice(Bink2Context *c,
> +                               uint8_t *dst[4], int stride[4],
> +                               uint8_t *src[4], int sstride[4],
> +                               int is_kf, int start, int end)
> +{
> +    GetBitContext *gb = &c->gb;
> +    int w = c->avctx->width;
> +    int h = c->avctx->height;
> +    int flags, ret = 0;
> +
> +    memset(c->prev_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_mv));
> +
> +    for (int y = start; y < end; y += 32) {
> +        unsigned y_cbp_intra = 0, u_cbp_intra = 0, v_cbp_intra = 0, a_cbp_intra = 0;
> +        unsigned y_cbp_inter = 0, u_cbp_inter = 0, v_cbp_inter = 0, a_cbp_inter = 0;
> +        int y_intra_q = 8, u_intra_q = 8, v_intra_q = 8, a_intra_q = 8;
> +        int y_inter_q = 8, u_inter_q = 8, v_inter_q = 8, a_inter_q = 8;
> +
> +        memset(c->current_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_mv));
> +
> +        for (int x = 0; x < c->avctx->width; x += 32) {
> +            MVectors mv = { 0 };
> +            int type = is_kf ? INTRA_BLOCK : get_bits(gb, 2);
> +
> +            c->mb_pos = x / 32;
> +            c->current_dc[c->mb_pos].block_type = type;
> +            flags = 0;
> +            if (y == start)
> +                flags |= 0x80;
> +            if (!x)
> +                flags |= 0x20;
> +            if (x == 32)
> +                flags |= 0x200;
> +            if (x + 32 >= c->avctx->width)
> +                flags |= 0x40;
> +
> +            switch (type) {
> +            case INTRA_BLOCK:
> +                if (!(flags & 0xA0) && c->prev_dc[c->mb_pos - 1].block_type != INTRA_BLOCK) {
> +                    bink2f_average_luma  (c, x  -32, -32, dst[0], stride[0], c->prev_dc[c->mb_pos - 1].dc[0]);

> +            case MOTION_BLOCK:
> +                bink2f_decode_mv(c, gb, x, y, flags, &mv);
> +                bink2f_predict_mv(c, x, y, flags, mv);
> +                c->comp = 0;
> +                ret = bink2f_mcompensate_luma(c, x, y,
> +                                              dst[0], stride[0],
> +                                              src[0], sstride[0],
> +                                              w, h);
> +                if (ret < 0)
> +                    goto fail;
> +                c->comp = 1;
> +                ret = bink2f_mcompensate_chroma(c, x/2, y/2,
> +                                                dst[2], stride[2],
> +                                                src[2], sstride[2],
> +                                                w/2, h/2);
> +                if (ret < 0)
> +                    goto fail;
> +                c->comp = 2;
> +                ret = bink2f_mcompensate_chroma(c, x/2, y/2,
> +                                                dst[1], stride[1],
> +                                                src[1], sstride[1],
> +                                                w/2, h/2);

c->comp required for MOTION_BLOCK?


> +            default:
> +                return AVERROR_INVALIDDATA;

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

> +            }
> +        }
> +
> +        dst[0] += stride[0] * 32;
> +        dst[1] += stride[1] * 16;
> +        dst[2] += stride[2] * 16;
> +        dst[3] += stride[3] * 32;
> +
> +        FFSWAP(MVPredict *, c->current_mv, c->prev_mv);
> +        FFSWAP(DCPredict *, c->current_dc, c->prev_dc);
> +    }
> +fail:
> +    emms_c();
> +
> +    return ret;
> +}


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

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

see bink2f_predict_dc comments

> +static void bink2g_decode_dc(Bink2Context *c, GetBitContext *gb, int *dc,
> +                             int is_luma, int q, int mindc, int maxdc,
> +                             int flags)
> +{
> +    const int num_dc = is_luma ? 16 : 4;
> +    int tdc[16];
> +    int pat;
> +
> +    q = FFMAX(q, 8);
> +    pat = bink2g_dc_pat[q];
> +
> +    memset(tdc, 0, sizeof(tdc));

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

> +    if (get_bits1(gb)) {
> +        for (int i = 0; i < num_dc; i++) {
> +            int cnt = get_unary(gb, 0, 12);
> +
> +            if (cnt > 3)
> +                cnt = (1 << (cnt - 3)) + get_bits(gb, cnt - 3) + 2;
> +            if (cnt && get_bits1(gb))
> +                cnt = -cnt;
> +            tdc[i] = (cnt * pat + 0x200) >> 10;
> +        }
> +    }
> +
> +    bink2g_predict_dc(c, is_luma, mindc, maxdc, flags, tdc);
> +}
> +
> +static int bink2g_decode_ac(GetBitContext *gb, const uint8_t scan[64],
> +                            int16_t block[4][64], unsigned cbp,
> +                            int q, const uint16_t qmat[4][64])
> +{
> +    int idx, next, val, skip;
> +    VLC *skip_vlc;
> +
> +    for (int i = 0; i < 4; i++)
> +        memset(block[i], 0, sizeof(int16_t) * 64);

sizeof(**block)

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

can fold memset into loop below

> +    skip_vlc = &bink2g_ac_skip0_vlc;
> +    if (cbp & 0xffff0000)
> +        skip_vlc = &bink2g_ac_skip1_vlc;
> +
> +    for (int i = 0; i < 4; i++, cbp >>= 1) {
> +        if (!(cbp & 1))
> +            continue;
> +

> +static int bink2g_decode_slice(Bink2Context *c,
> +                               uint8_t *dst[4], int stride[4],
> +                               uint8_t *src[4], int sstride[4],
> +                               int is_kf, int start, int end)
> +{
> +    GetBitContext *gb = &c->gb;
> +    int w = c->avctx->width;
> +    int h = c->avctx->height;
> +    int ret = 0, dq, flags;
> +
> +    memset(c->prev_q, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_q));
> +    memset(c->prev_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->prev_mv));
> +
> +    for (int y = start; y < end; y += 32) {
> +        int types_lru[4] = { MOTION_BLOCK, RESIDUE_BLOCK, SKIP_BLOCK, INTRA_BLOCK };
> +        unsigned y_cbp_intra = 0, u_cbp_intra = 0, v_cbp_intra = 0, a_cbp_intra = 0;
> +        unsigned y_cbp_inter = 0, u_cbp_inter = 0, v_cbp_inter = 0, a_cbp_inter = 0;
> +
> +        memset(c->current_q, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_q));
> +        memset(c->current_mv, 0, ((c->avctx->width + 31) / 32) * sizeof(*c->current_mv));
> +
> +        for (int x = 0; x < c->avctx->width; x += 32) {
> +            int type = is_kf ? INTRA_BLOCK : bink2g_get_type(gb, types_lru);
> +            int8_t *intra_q = &c->current_q[x / 32].intra_q;
> +            int8_t *inter_q = &c->current_q[x / 32].inter_q;
> +            MVectors mv = { 0 };
> +
> +            c->mb_pos = x / 32;
> +            c->current_idc[c->mb_pos].block_type = type;
> +            flags = 0;
> +            if (y == start)
> +                flags |= 0x80;
> +            if (!x)
> +                flags |= 0x20;
> +            if (x == 32)
> +                flags |= 0x200;
> +            if (x + 32 >= c->avctx->width)
> +                flags |= 0x40;
> +            switch (type) {
> +            case INTRA_BLOCK:
> +                if (!(flags & 0xA0) && c->prev_idc[c->mb_pos - 1].block_type != INTRA_BLOCK) {
> +                    bink2g_average_luma  (c, x  -32, -32, dst[0], stride[0], c->prev_idc[c->mb_pos - 1].dc[0]);
> +                    bink2g_average_chroma(c, x/2-16, -16, dst[2], stride[2], c->prev_idc[c->mb_pos - 1].dc[1]);

> +            default:
> +                return AVERROR_INVALIDDATA;

goto fail

> +            }
> +        }
> +
> +        dst[0] += stride[0] * 32;
> +        dst[1] += stride[1] * 16;
> +        dst[2] += stride[2] * 16;
> +        dst[3] += stride[3] * 32;
> +
> +        FFSWAP(MVPredict *, c->current_mv, c->prev_mv);
> +        FFSWAP(QuantPredict *, c->current_q, c->prev_q);
> +        FFSWAP(DCIPredict *, c->current_idc, c->prev_idc);
> +    }
> +fail:
> +    emms_c();
> +
> +    return ret;
> +}

-- Peter
(A907 E02F A6E5 0CD2 34CD 20D2 6760 79C5 AC40 DD6B)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20200322/0837639a/attachment.sig>


More information about the ffmpeg-devel mailing list