[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