From d263f1ce20518933fb78f237fa715e78aec04181 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Mon, 14 Apr 2025 14:43:39 +0200
Subject: [PATCH 3/3] avcodec/mjpegenc_huffman: Already build codes

I.e. do what ff_mjpeg_build_huffman_codes() does already
in ff_mjpeg_encode_huffman_close(). This is more natural
and traverses the array of values one less time.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/mjpegenc.c         | 33 ++++++++++++---------------------
 libavcodec/mjpegenc_huffman.c | 24 ++++++++++++------------
 libavcodec/mjpegenc_huffman.h | 17 +++++++++++++++--
 3 files changed, 39 insertions(+), 35 deletions(-)

diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c
index 214e2b0ec1..f05b4f88a5 100644
--- a/libavcodec/mjpegenc.c
+++ b/libavcodec/mjpegenc.c
@@ -196,33 +196,24 @@ static void mjpeg_build_optimal_huffman(MJpegContext *m)
 
     ff_mjpeg_encode_huffman_close(&dc_luminance_ctx,
                                   m->bits_dc_luminance,
-                                  m->val_dc_luminance, 12);
+                                  m->val_dc_luminance, 12,
+                                  m->huff_size_dc_luminance,
+                                  m->huff_code_dc_luminance);
     ff_mjpeg_encode_huffman_close(&dc_chrominance_ctx,
                                   m->bits_dc_chrominance,
-                                  m->val_dc_chrominance, 12);
+                                  m->val_dc_chrominance, 12,
+                                  m->huff_size_dc_chrominance,
+                                  m->huff_code_dc_chrominance);
     ff_mjpeg_encode_huffman_close(&ac_luminance_ctx,
                                   m->bits_ac_luminance,
-                                  m->val_ac_luminance, 256);
+                                  m->val_ac_luminance, 256,
+                                  m->huff_size_ac_luminance,
+                                  m->huff_code_ac_luminance);
     ff_mjpeg_encode_huffman_close(&ac_chrominance_ctx,
                                   m->bits_ac_chrominance,
-                                  m->val_ac_chrominance, 256);
-
-    ff_mjpeg_build_huffman_codes(m->huff_size_dc_luminance,
-                                 m->huff_code_dc_luminance,
-                                 m->bits_dc_luminance,
-                                 m->val_dc_luminance);
-    ff_mjpeg_build_huffman_codes(m->huff_size_dc_chrominance,
-                                 m->huff_code_dc_chrominance,
-                                 m->bits_dc_chrominance,
-                                 m->val_dc_chrominance);
-    ff_mjpeg_build_huffman_codes(m->huff_size_ac_luminance,
-                                 m->huff_code_ac_luminance,
-                                 m->bits_ac_luminance,
-                                 m->val_ac_luminance);
-    ff_mjpeg_build_huffman_codes(m->huff_size_ac_chrominance,
-                                 m->huff_code_ac_chrominance,
-                                 m->bits_ac_chrominance,
-                                 m->val_ac_chrominance);
+                                  m->val_ac_chrominance, 256,
+                                  m->huff_size_ac_chrominance,
+                                  m->huff_code_ac_chrominance);
 }
 #endif
 
diff --git a/libavcodec/mjpegenc_huffman.c b/libavcodec/mjpegenc_huffman.c
index 7fd63a2569..732ae88b39 100644
--- a/libavcodec/mjpegenc_huffman.c
+++ b/libavcodec/mjpegenc_huffman.c
@@ -148,16 +148,9 @@ void ff_mjpeg_encode_huffman_init(MJpegEncHuffmanContext *s)
     memset(s->val_count, 0, sizeof(s->val_count));
 }
 
-/**
- * Produces a Huffman encoding with a given input
- *
- * @param s         input to encode
- * @param bits      output array where the ith character represents how many input values have i length encoding
- * @param val       output array of input values sorted by their encoded length
- * @param max_nval  maximum number of distinct input values
- */
-void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17],
-                                   uint8_t val[], int max_nval)
+void ff_mjpeg_encode_huffman_close(const MJpegEncHuffmanContext *s, uint8_t bits[17],
+                                   uint8_t val[], int max_nval,
+                                   uint8_t huff_len[], uint16_t huff_code[])
 {
     PTable val_counts[257];
 
@@ -181,6 +174,13 @@ void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s, uint8_t bits[17],
     av_assert1(val_counts[0].prob == 0 && val_counts[0].value == 256);
     // The following loop puts the values with higher occurence first,
     // ensuring that they get the shorter codes.
-    for (int i = 0; i < nval; ++i)
-        val[i] = val_counts[nval - i].value;
+    unsigned code = 0;
+    for (int len = 1, i = 0; len <= 16; ++len) {
+        for (const int end = i + bits[len]; i < end; ++i) {
+            unsigned sym = val[i] = val_counts[nval - i].value;
+            huff_len[sym]  = len;
+            huff_code[sym] = code++;
+        }
+        code <<= 1;
+    }
 }
diff --git a/libavcodec/mjpegenc_huffman.h b/libavcodec/mjpegenc_huffman.h
index 8822e468aa..b43f1a6017 100644
--- a/libavcodec/mjpegenc_huffman.h
+++ b/libavcodec/mjpegenc_huffman.h
@@ -40,8 +40,21 @@ static inline void ff_mjpeg_encode_huffman_increment(MJpegEncHuffmanContext *s,
 {
     s->val_count[val]++;
 }
-void ff_mjpeg_encode_huffman_close(MJpegEncHuffmanContext *s,
+
+/**
+ * Produces a Huffman encoding with a given input
+ *
+ * @param s              MJpegEncHuffmanContext with the input to encode
+ * @param bits[out]      array where the ith character represents how many
+ *                       input values have i length encoding
+ * @param val[out]       array of input values sorted by their encoded length
+ * @param max_nval       maximum number of distinct input values
+ * @param huff_len[out]  LUT of code lens as ff_mjpeg_build_huffman_codes() produces them
+ * @param huff_code[out] LUT of codes as ff_mjpeg_build_huffman_codes() produces them
+ */
+void ff_mjpeg_encode_huffman_close(const MJpegEncHuffmanContext *s,
                                    uint8_t bits[17], uint8_t val[],
-                                   int max_nval);
+                                   int max_nval,
+                                   uint8_t huff_len[], uint16_t huff_code[]);
 
 #endif /* AVCODEC_MJPEGENC_HUFFMAN_H */
-- 
2.45.2