From b8f3a569e7a320cb17d053e6b44db727fa32ff03 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Mon, 3 Mar 2025 00:21:04 +0100 Subject: [PATCH 20/45] avcodec/mpeg4video: Split ff_mpeg4_pred_dc() It currently does two things: a) Get a prediction for the dc and the dc direction and b) process said prediction. Processing the prediction differs for encoding (getting a diff) and decoding (getting the level via diff+prediction). So having a common function performing b) makes no sense. Even worse, there is a decoding mode where the dc coefficient (diff) is not coded specially and therefore unavailable before entering the block decoding loop, so that one can only perform a). Before this commit, the decoder simply called ff_mpeg4_pred_dc() twice; the results of the b) part of the call before the loop were ignored (but the compiler could not elide them because they involved error messages) and a) was also performed twice. This commit changes this by splitting b) out of ff_mpeg4_pred_dc() and moving this code to decoder and encoder. Signed-off-by: Andreas Rheinhardt --- libavcodec/mpeg4video.h | 47 ++++--------------------------------- libavcodec/mpeg4videodec.c | 48 ++++++++++++++++++++++++++++++++++---- libavcodec/mpeg4videoenc.c | 10 ++++++-- 3 files changed, 55 insertions(+), 50 deletions(-) diff --git a/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h index 29b11eb92e..9ac18943a2 100644 --- a/libavcodec/mpeg4video.h +++ b/libavcodec/mpeg4video.h @@ -44,24 +44,15 @@ int ff_mpeg4_set_direct_mv(MpegEncContext *s, int mx, int my); /** * Predict the dc. - * encoding quantized level -> quantized diff - * decoding quantized diff -> quantized level * @param n block index (0-3 are luma, 4-5 are chroma) * @param dir_ptr pointer to an integer where the prediction direction will be stored */ -static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level, - int *dir_ptr, int encoding) +static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int *dir_ptr) { - int a, b, c, wrap, pred, scale, ret; - int16_t *dc_val; + int a, b, c, wrap, pred; + const int16_t *dc_val; /* find prediction */ - if (n < 4) - scale = s->y_dc_scale; - else - scale = s->c_dc_scale; - if (IS_3IV1) - scale = 8; wrap = s->block_wrap[n]; dc_val = s->dc_val[0] + s->block_index[n]; @@ -93,37 +84,7 @@ static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level, pred = a; *dir_ptr = 0; /* left */ } - /* we assume pred is positive */ - pred = FASTDIV((pred + (scale >> 1)), scale); - - if (encoding) { - ret = level - pred; - } else { - level += pred; - ret = level; - } - level *= scale; - if (level & (~2047)) { - if (!s->encoding && (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE))) { - if (level < 0) { - av_log(s->avctx, AV_LOG_ERROR, - "dc<0 at %dx%d\n", s->mb_x, s->mb_y); - return AVERROR_INVALIDDATA; - } - if (level > 2048 + scale) { - av_log(s->avctx, AV_LOG_ERROR, - "dc overflow at %dx%d\n", s->mb_x, s->mb_y); - return AVERROR_INVALIDDATA; - } - } - if (level < 0) - level = 0; - else if (!(s->workaround_bugs & FF_BUG_DC_CLIP)) - level = 2047; - } - dc_val[0] = level; - - return ret; + return pred; } #endif /* AVCODEC_MPEG4VIDEO_H */ diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index 2a340ea682..31d00dd0b9 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -880,6 +880,43 @@ static inline int get_amv(Mpeg4DecContext *ctx, int n) return sum; } +static inline int mpeg4_get_level_dc(MpegEncContext *s, int n, int pred, int level) +{ + int scale = n < 4 ? s->y_dc_scale : s->c_dc_scale; + int ret; + + if (IS_3IV1) + scale = 8; + + /* we assume pred is positive */ + pred = FASTDIV((pred + (scale >> 1)), scale); + + level += pred; + ret = level; + level *= scale; + if (level & (~2047)) { + if (s->avctx->err_recognition & (AV_EF_BITSTREAM | AV_EF_AGGRESSIVE)) { + if (level < 0) { + av_log(s->avctx, AV_LOG_ERROR, + "dc<0 at %dx%d\n", s->mb_x, s->mb_y); + return AVERROR_INVALIDDATA; + } + if (level > 2048 + scale) { + av_log(s->avctx, AV_LOG_ERROR, + "dc overflow at %dx%d\n", s->mb_x, s->mb_y); + return AVERROR_INVALIDDATA; + } + } + if (level < 0) + level = 0; + else if (!(s->workaround_bugs & FF_BUG_DC_CLIP)) + level = 2047; + } + s->dc_val[0][s->block_index[n]] = level; + + return ret; +} + /** * Decode the dc value. * @param n block index (0-3 are luma, 4-5 are chroma) @@ -888,7 +925,7 @@ static inline int get_amv(Mpeg4DecContext *ctx, int n) */ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) { - int level, code; + int level, code, pred; if (n < 4) code = get_vlc2(&s->gb, dc_lum, DC_VLC_BITS, 1); @@ -926,7 +963,8 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) } } - return ff_mpeg4_pred_dc(s, n, level, dir_ptr, 0); + pred = ff_mpeg4_pred_dc(s, n, dir_ptr); + return mpeg4_get_level_dc(s, n, pred, level); } /** @@ -1290,7 +1328,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, int use_intra_dc_vlc, int rvlc) { MpegEncContext *s = &ctx->m; - int level, i, last, run, qmul, qadd; + int level, i, last, run, qmul, qadd, pred; int av_uninit(dc_pred_dir); const RLTable *rl; const RL_VLC_ELEM *rl_vlc; @@ -1317,7 +1355,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, i = 0; } else { i = -1; - ff_mpeg4_pred_dc(s, n, 0, &dc_pred_dir, 0); + pred = ff_mpeg4_pred_dc(s, n, &dc_pred_dir); } if (!coded) goto not_coded; @@ -1540,7 +1578,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, not_coded: if (intra) { if (!use_intra_dc_vlc) { - block[0] = ff_mpeg4_pred_dc(s, n, block[0], &dc_pred_dir, 0); + block[0] = mpeg4_get_level_dc(s, n, pred, block[0]); i -= i >> 31; // if (i == -1) i = 0; } diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c index 64fb96a0cf..26f9b40ff7 100644 --- a/libavcodec/mpeg4videoenc.c +++ b/libavcodec/mpeg4videoenc.c @@ -806,8 +806,14 @@ void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], const uint8_t *scan_table[6]; int i; - for (i = 0; i < 6; i++) - dc_diff[i] = ff_mpeg4_pred_dc(s, i, block[i][0], &dir[i], 1); + for (int i = 0; i < 6; i++) { + int pred = ff_mpeg4_pred_dc(s, i, &dir[i]); + int scale = i < 4 ? s->y_dc_scale : s->c_dc_scale; + + pred = FASTDIV((pred + (scale >> 1)), scale); + dc_diff[i] = block[i][0] - pred; + s->dc_val[0][s->block_index[i]] = av_clip_uintp2(block[i][0] * scale, 11); + } if (s->avctx->flags & AV_CODEC_FLAG_AC_PRED) { s->ac_pred = decide_ac_pred(s, block, dir, scan_table, zigzag_last_index); -- 2.45.2