[FFmpeg-cvslog] avcodec/webp: Switch to ff_vlc_init_from_lengths()
Andreas Rheinhardt
git at videolan.org
Sat Apr 26 01:15:09 EEST 2025
ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at outlook.com> | Fri Apr 18 19:29:41 2025 +0200| [e0df21b8c379f3e3025df9510258f91b0d01d3d8] | committer: Andreas Rheinhardt
avcodec/webp: Switch to ff_vlc_init_from_lengths()
The earlier code would traverse over the code lengths
mutliple times (namely max_length + 1 times - once to get
the maximum length and once for each max_length to assign
codes) before calling ff_vlc_init_sparse() (which may traverse
them twice and sort them). The new code only traverses them once
(+ the one time in ff_vlc_init_from_lengths()).
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=e0df21b8c379f3e3025df9510258f91b0d01d3d8
---
libavcodec/webp.c | 108 +++++++++++++++++++++++++++---------------------------
1 file changed, 55 insertions(+), 53 deletions(-)
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 46b20a1ab6..2c918eac33 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -253,64 +253,58 @@ static int huff_reader_get_symbol(HuffReader *r, GetBitContext *gb)
}
static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_lengths,
- int alphabet_size)
+ uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1],
+ int alphabet_size, void *logctx)
{
- int len = 0, sym, code = 0, ret;
- int max_code_length = 0;
- uint16_t *codes;
-
- /* special-case 1 symbol since the vlc reader cannot handle it */
- for (sym = 0; sym < alphabet_size; sym++) {
- if (code_lengths[sym] > 0) {
- len++;
- code = sym;
- if (len > 1)
- break;
- }
+ uint16_t *syms;
+ uint8_t *lens;
+ unsigned nb_codes = 0;
+ int ret;
+
+ // Count the number of symbols of each length and transform len_counts
+ // into an array of offsets.
+ for (int len = 1; len <= MAX_HUFFMAN_CODE_LENGTH; ++len) {
+ unsigned cnt = len_counts[len];
+ len_counts[len] = nb_codes;
+ nb_codes += cnt;
}
- if (len == 1) {
- r->nb_symbols = 1;
- r->simple_symbols[0] = code;
- r->simple = 1;
- return 0;
+ if (nb_codes <= 1) {
+ if (nb_codes == 1) {
+ /* special-case 1 symbol since the vlc reader cannot handle it */
+ r->nb_symbols = 1;
+ r->simple = 1;
+ for (int sym = 0;; ++sym) {
+ av_assert1(sym < alphabet_size);
+ if (code_lengths[sym]) {
+ r->simple_symbols[0] = sym;
+ return 0;
+ }
+ }
+ }
+ // No symbols
+ return AVERROR_INVALIDDATA;
}
- for (sym = 0; sym < alphabet_size; sym++)
- max_code_length = FFMAX(max_code_length, code_lengths[sym]);
-
- if (max_code_length == 0)
- return AVERROR(EINVAL);
-
- codes = av_malloc_array(alphabet_size, sizeof(*codes));
- if (!codes)
+ syms = av_malloc_array(nb_codes, sizeof(*syms) + sizeof(*lens));
+ if (!syms)
return AVERROR(ENOMEM);
+ lens = (uint8_t*)(syms + nb_codes);
- code = 0;
- r->nb_symbols = 0;
- for (len = 1; len <= max_code_length; len++) {
- for (sym = 0; sym < alphabet_size; sym++) {
- if (code_lengths[sym] != len)
- continue;
- codes[sym] = code++;
- r->nb_symbols++;
+ for (int sym = 0; sym < alphabet_size; ++sym) {
+ if (code_lengths[sym]) {
+ unsigned idx = len_counts[code_lengths[sym]]++;
+ syms[idx] = sym;
+ lens[idx] = code_lengths[sym];
}
- code <<= 1;
- }
- if (!r->nb_symbols) {
- av_free(codes);
- return AVERROR_INVALIDDATA;
}
- ret = vlc_init(&r->vlc, 8, alphabet_size,
- code_lengths, sizeof(*code_lengths), sizeof(*code_lengths),
- codes, sizeof(*codes), sizeof(*codes), VLC_INIT_OUTPUT_LE);
- if (ret < 0) {
- av_free(codes);
+ ret = ff_vlc_init_from_lengths(&r->vlc, 8, nb_codes, lens, 1,
+ syms, 2, 2, 0, VLC_INIT_OUTPUT_LE, logctx);
+ av_free(syms);
+ if (ret < 0)
return ret;
- }
r->simple = 0;
- av_free(codes);
return 0;
}
@@ -335,20 +329,24 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
HuffReader code_len_hc = { { 0 }, 0, 0, { 0 } };
uint8_t *code_lengths;
uint8_t code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
- int i, symbol, max_symbol, prev_code_len, ret;
+ uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1] = { 0 };
+ int symbol, max_symbol, prev_code_len, ret;
int num_codes = 4 + get_bits(&s->gb, 4);
av_assert1(num_codes <= NUM_CODE_LENGTH_CODES);
- for (i = 0; i < num_codes; i++)
- code_length_code_lengths[code_length_code_order[i]] = get_bits(&s->gb, 3);
+ for (int i = 0; i < num_codes; i++) {
+ unsigned len = get_bits(&s->gb, 3);
+ code_length_code_lengths[code_length_code_order[i]] = len;
+ len_counts[len]++;
+ }
- ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths,
- NUM_CODE_LENGTH_CODES);
+ ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths, len_counts,
+ NUM_CODE_LENGTH_CODES, s->avctx);
if (ret < 0)
return ret;
- code_lengths = av_mallocz(alphabet_size);
+ code_lengths = av_malloc(alphabet_size);
if (!code_lengths) {
ret = AVERROR(ENOMEM);
goto finish;
@@ -369,6 +367,7 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
prev_code_len = 8;
symbol = 0;
+ memset(len_counts, 0, sizeof(len_counts));
while (symbol < alphabet_size) {
int code_len;
@@ -378,6 +377,7 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
if (code_len < 16U) {
/* Code length code [0..15] indicates literal code lengths. */
code_lengths[symbol++] = code_len;
+ len_counts[code_len]++;
if (code_len)
prev_code_len = code_len;
} else {
@@ -392,6 +392,7 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
* non-zero value has been emitted, a value of 8 is repeated. */
repeat = 3 + get_bits(&s->gb, 2);
length = prev_code_len;
+ len_counts[length] += repeat;
break;
case 17:
/* Code 17 emits a streak of zeros [3..10], i.e.,
@@ -416,7 +417,8 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
}
}
- ret = huff_reader_build_canonical(hc, code_lengths, alphabet_size);
+ ret = huff_reader_build_canonical(hc, code_lengths, len_counts,
+ symbol, s->avctx);
finish:
ff_vlc_free(&code_len_hc.vlc);
More information about the ffmpeg-cvslog
mailing list