[FFmpeg-cvslog] avcodec/mpeg4videoenc: Simplify creating LUT

Andreas Rheinhardt git at videolan.org
Mon May 26 06:24:57 EEST 2025


ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at outlook.com> | Sun May 18 08:35:23 2025 +0200| [d75a398d00c255ad5a6b646b8ee1d5350fd9680e] | committer: Andreas Rheinhardt

avcodec/mpeg4videoenc: Simplify creating LUT

There four cases for the LUT entry: An ordinary entry
or one of three escaping methods. Three of these methods
are only rarely possible --they correspond to the 102
codes of the underlying VLC and so only 102 of 16384 entries
are possible.

The earlier code would nevertheless try them all for every
LUT entry and use the best one; the new code meanwhile only
uses one method (the fallback one (i.e. the worst)) for them all
and only processes the 102 valid entries afterwards.

The implementation used also means that index_run, max_level
and max_run of the RLTable are no longer needed; the earlier
code would initialize said static tables although they are only
used for a short time to initialize something else.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=d75a398d00c255ad5a6b646b8ee1d5350fd9680e
---

 libavcodec/mpeg4videoenc.c | 161 ++++++++++++++++++++-------------------------
 1 file changed, 71 insertions(+), 90 deletions(-)

diff --git a/libavcodec/mpeg4videoenc.c b/libavcodec/mpeg4videoenc.c
index cf4a1dfa63..4d574b029f 100644
--- a/libavcodec/mpeg4videoenc.c
+++ b/libavcodec/mpeg4videoenc.c
@@ -1184,95 +1184,78 @@ static av_cold void init_uni_dc_tab(void)
 static av_cold void init_uni_mpeg4_rl_tab(RLTable *rl, uint32_t *bits_tab,
                                           uint8_t *len_tab)
 {
-    int slevel, run, last;
-
-    av_assert0(MAX_LEVEL >= 64);
-    av_assert0(MAX_RUN >= 63);
-
-    for (slevel = -64; slevel < 64; slevel++) {
-        if (slevel == 0)
-            continue;
-        for (run = 0; run < 64; run++) {
-            for (last = 0; last <= 1; last++) {
-                const int index = UNI_MPEG4_ENC_INDEX(last, run, slevel + 64);
-                int level       = slevel < 0 ? -slevel : slevel;
-                int sign        = slevel < 0 ? 1 : 0;
-                int bits, len, code;
-                int level1, run1;
-
-                len_tab[index] = 100;
-
-                /* ESC0 */
-                code = get_rl_index(rl, last, run, level);
-                bits = rl->table_vlc[code][0];
-                len  = rl->table_vlc[code][1];
-                bits = bits * 2 + sign;
-                len++;
-
-                if (code != rl->n && len < len_tab[index]) {
-                    bits_tab[index] = bits;
-                    len_tab[index]  = len;
-                }
-                /* ESC1 */
-                bits = rl->table_vlc[rl->n][0];
-                len  = rl->table_vlc[rl->n][1];
-                bits = bits * 2;
-                len++;                 // esc1
-                level1 = level - rl->max_level[last][run];
-                if (level1 > 0) {
-                    code   = get_rl_index(rl, last, run, level1);
-                    bits <<= rl->table_vlc[code][1];
-                    len   += rl->table_vlc[code][1];
-                    bits  += rl->table_vlc[code][0];
-                    bits   = bits * 2 + sign;
-                    len++;
-
-                    if (code != rl->n && len < len_tab[index]) {
-                        bits_tab[index] = bits;
-                        len_tab[index]  = len;
-                    }
-                }
-                /* ESC2 */
-                bits = rl->table_vlc[rl->n][0];
-                len  = rl->table_vlc[rl->n][1];
-                bits = bits * 4 + 2;
-                len += 2;                 // esc2
-                run1 = run - rl->max_run[last][level] - 1;
-                if (run1 >= 0) {
-                    code   = get_rl_index(rl, last, run1, level);
-                    bits <<= rl->table_vlc[code][1];
-                    len   += rl->table_vlc[code][1];
-                    bits  += rl->table_vlc[code][0];
-                    bits   = bits * 2 + sign;
-                    len++;
-
-                    if (code != rl->n && len < len_tab[index]) {
-                        bits_tab[index] = bits;
-                        len_tab[index]  = len;
-                    }
-                }
-                /* ESC3 */
-                bits = rl->table_vlc[rl->n][0];
-                len  = rl->table_vlc[rl->n][1];
-                bits = bits * 4 + 3;
-                len += 2;                 // esc3
-                bits = bits * 2 + last;
-                len++;
-                bits = bits * 64 + run;
-                len += 6;
-                bits = bits * 2 + 1;
-                len++;                    // marker
-                bits = bits * 4096 + (slevel & 0xfff);
-                len += 12;
-                bits = bits * 2 + 1;
-                len++;                    // marker
-
-                if (len < len_tab[index]) {
-                    bits_tab[index] = bits;
-                    len_tab[index]  = len;
-                }
-            }
+    // Type 3 escape method. The escape code is the same for both VLCs
+    // (0x3, seven bits), so it is hardcoded.
+    memset(len_tab, 30, 2 * 2 * 64 * 64);
+    len_tab  += 64;
+    bits_tab += 64;
+    for (int run = 0; run < 64; ++run) {
+        for (int level = 1;; ++level) {
+                       //  Escape code   type 3     not last    run (6 bits)   marker   marker
+            unsigned code = (3 << 23) | (3 << 21) | (0 << 20) | (run << 14) | (1 << 13) | 1;
+            // first the negative levels
+            bits_tab[UNI_MPEG4_ENC_INDEX(0, run, -level)] = code | (-level & 0xfff) << 1;
+            bits_tab[UNI_MPEG4_ENC_INDEX(1, run, -level)] =
+                bits_tab[UNI_MPEG4_ENC_INDEX(0, run, -level)] | (1 << 20) /* last */;
+
+            if (level == 64) // positive levels have a range of 1..63
+                break;
+            bits_tab[UNI_MPEG4_ENC_INDEX(0, run, level)] = code | level << 1;
+            bits_tab[UNI_MPEG4_ENC_INDEX(1, run, level)] =
+                bits_tab[UNI_MPEG4_ENC_INDEX(0, run, level)] | (1 << 20) /* last */;
+        }
+        // Is this needed at all?
+        len_tab[UNI_MPEG4_ENC_INDEX(0, run, 0)] =
+        len_tab[UNI_MPEG4_ENC_INDEX(1, run, 0)] = 0;
+    }
+
+    uint8_t max_run[2][32] = { 0 };
+
+#define VLC_NUM_CODES 102 // excluding the escape
+    av_assert2(rl->n == VLC_NUM_CODES);
+    for (int i = VLC_NUM_CODES - 1, max_level, cur_run = 0; i >= 0; --i) {
+        int run = rl->table_run[i], level = rl->table_level[i];
+        int last = i >= rl->last;
+        unsigned code = rl->table_vlc[i][0] << 1;
+        int len = rl->table_vlc[i][1] + 1;
+
+        bits_tab[UNI_MPEG4_ENC_INDEX(last, run,  level)] = code;
+        len_tab [UNI_MPEG4_ENC_INDEX(last, run,  level)] = len;
+        bits_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = code | 1;
+        len_tab [UNI_MPEG4_ENC_INDEX(last, run, -level)] = len;
+
+        if (!max_run[last][level])
+            max_run[last][level] = run + 1;
+        av_assert2(run + 1 <= max_run[last][level]);
+
+        int run3 = run + max_run[last][level];
+        int len3 = len + 7 + 2;
+
+        if (run3 < 64 && len3 < len_tab[UNI_MPEG4_ENC_INDEX(last, run3, level)]) {
+            unsigned code3 = code | (0x3 << 2 | 0x2) << len;
+            bits_tab[UNI_MPEG4_ENC_INDEX(last, run3,  level)] = code3;
+            len_tab [UNI_MPEG4_ENC_INDEX(last, run3,  level)] = len3;
+            bits_tab[UNI_MPEG4_ENC_INDEX(last, run3, -level)] = code3 | 1;
+            len_tab [UNI_MPEG4_ENC_INDEX(last, run3, -level)] = len3;
         }
+        // table_run and table_level are ordered so that all the entries
+        // with the same last and run are consecutive and level is ascending
+        // among these entries. By traversing downwards we therefore automatically
+        // encounter max_level of a given run first, needed for escape method 1.
+        if (run != cur_run) {
+            max_level = level;
+            cur_run   = run;
+        } else
+            av_assert2(max_level > level);
+
+        code  |= 0x3 << (len + 1);
+        len   += 7 + 1;
+        level += max_level;
+        av_assert2(len_tab [UNI_MPEG4_ENC_INDEX(last, run,  level)] >= len);
+        bits_tab[UNI_MPEG4_ENC_INDEX(last, run,  level)] = code;
+        len_tab [UNI_MPEG4_ENC_INDEX(last, run,  level)] = len;
+        bits_tab[UNI_MPEG4_ENC_INDEX(last, run, -level)] = code | 1;
+        len_tab [UNI_MPEG4_ENC_INDEX(last, run, -level)] = len;
     }
 }
 
@@ -1280,8 +1263,6 @@ static av_cold void mpeg4_encode_init_static(void)
 {
     init_uni_dc_tab();
 
-    ff_mpeg4_init_rl_intra();
-
     init_uni_mpeg4_rl_tab(&ff_mpeg4_rl_intra, uni_mpeg4_intra_rl_bits, uni_mpeg4_intra_rl_len);
     init_uni_mpeg4_rl_tab(&ff_h263_rl_inter,  uni_mpeg4_inter_rl_bits, uni_mpeg4_inter_rl_len);
 



More information about the ffmpeg-cvslog mailing list