Browse Source

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 <andreas.rheinhardt@outlook.com>
Andreas Rheinhardt 1 week ago
parent
commit
5df8c86b24
3 changed files with 55 additions and 50 deletions
  1. 4 43
      libavcodec/mpeg4video.h
  2. 43 5
      libavcodec/mpeg4videodec.c
  3. 8 2
      libavcodec/mpeg4videoenc.c

+ 4 - 43
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 */

+ 43 - 5
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;
         }

+ 8 - 2
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);