* [FFmpeg-devel] [PATCH 01/13] avcodec/huffman: Switch to ff_vlc_init_from_lengths()
@ 2025-04-21 11:28 Andreas Rheinhardt
2025-04-25 10:39 ` Andreas Rheinhardt
0 siblings, 1 reply; 2+ messages in thread
From: Andreas Rheinhardt @ 2025-04-21 11:28 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1: Type: text/plain, Size: 29 bytes --]
Patches attached.
- Andreas
[-- Attachment #2: 0001-avcodec-huffman-Switch-to-ff_vlc_init_from_lengths.patch --]
[-- Type: text/x-patch, Size: 2822 bytes --]
From 89a16c8e6efe441bf745ff1cf59296a2b97daf71 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 17 Apr 2025 15:43:31 +0200
Subject: [PATCH 01/13] avcodec/huffman: Switch to ff_vlc_init_from_lengths()
Avoids having to create the codes ourselves.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/huffman.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/libavcodec/huffman.c b/libavcodec/huffman.c
index d47fe10087..0de3097a82 100644
--- a/libavcodec/huffman.c
+++ b/libavcodec/huffman.c
@@ -115,40 +115,36 @@ end:
return ret;
}
-static void get_tree_codes(uint32_t *bits, int16_t *lens, uint8_t *xlat,
- Node *nodes, int node,
- uint32_t pfx, int pl, int *pos, int no_zero_count)
+static void get_tree_codes(int8_t *lens, uint8_t *xlat,
+ Node *nodes, int node, int pl, int *pos, int no_zero_count)
{
int s;
s = nodes[node].sym;
if (s != HNODE || (no_zero_count && !nodes[node].count)) {
- bits[*pos] = pfx;
lens[*pos] = pl;
xlat[*pos] = s;
(*pos)++;
} else {
- pfx <<= 1;
pl++;
- get_tree_codes(bits, lens, xlat, nodes, nodes[node].n0, pfx, pl,
+ get_tree_codes(lens, xlat, nodes, nodes[node].n0, pl,
pos, no_zero_count);
- pfx |= 1;
- get_tree_codes(bits, lens, xlat, nodes, nodes[node].n0 + 1, pfx, pl,
+ get_tree_codes(lens, xlat, nodes, nodes[node].n0 + 1, pl,
pos, no_zero_count);
}
}
-static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags, int nb_bits)
+static int build_huff_tree(VLC *vlc, Node *nodes, int head, int flags, int nb_bits, void *logctx)
{
int no_zero_count = !(flags & FF_HUFFMAN_FLAG_ZERO_COUNT);
- uint32_t bits[256];
- int16_t lens[256];
+ int8_t lens[256];
uint8_t xlat[256];
int pos = 0;
- get_tree_codes(bits, lens, xlat, nodes, head, 0, 0,
+ get_tree_codes(lens, xlat, nodes, head, 0,
&pos, no_zero_count);
- return ff_vlc_init_sparse(vlc, nb_bits, pos, lens, 2, 2, bits, 4, 4, xlat, 1, 1, 0);
+ return ff_vlc_init_from_lengths(vlc, nb_bits, pos, lens, 1,
+ xlat, 1, 1, 0, 0, logctx);
}
@@ -194,7 +190,7 @@ int ff_huff_build_tree(void *logctx, VLC *vlc, int nb_codes, int nb_bits,
nodes[j].n0 = i;
cur_node++;
}
- if (build_huff_tree(vlc, nodes, nb_codes * 2 - 2, flags, nb_bits) < 0) {
+ if (build_huff_tree(vlc, nodes, nb_codes * 2 - 2, flags, nb_bits, logctx) < 0) {
av_log(logctx, AV_LOG_ERROR, "Error building tree\n");
return -1;
}
--
2.45.2
[-- Attachment #3: 0002-avcodec-vp6-Don-t-initialize-unused-VLC-tables.patch --]
[-- Type: text/x-patch, Size: 2177 bytes --]
From be900261219c54b9d7e07a2382b096c2859592b5 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 17 Apr 2025 19:41:05 +0200
Subject: [PATCH 02/13] avcodec/vp6: Don't initialize unused VLC tables
There are only 2*3*4 VLC trees for decoding Huffman encoded
AC coefficients; see section 13.3.2 of the spec.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/vp56.h | 2 +-
libavcodec/vp6.c | 10 ++++------
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/libavcodec/vp56.h b/libavcodec/vp56.h
index 87b7e06e0b..e922a13c5e 100644
--- a/libavcodec/vp56.h
+++ b/libavcodec/vp56.h
@@ -203,7 +203,7 @@ struct vp56_context {
GetBitContext gb;
VLC dccv_vlc[2];
VLC runv_vlc[2];
- VLC ract_vlc[2][3][6];
+ VLC ract_vlc[2][3][4];
unsigned int nb_null[2][2]; /* number of consecutive NULL DC/AC */
int have_undamaged_frame;
diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c
index 73d117c871..926694ae11 100644
--- a/libavcodec/vp6.c
+++ b/libavcodec/vp6.c
@@ -339,7 +339,7 @@ static int vp6_parse_coeff_models(VP56Context *s)
vp6_huff_run_map, 9, &s->runv_vlc[pt]))
return -1;
for (ct=0; ct<3; ct++)
- for (cg = 0; cg < 6; cg++)
+ for (int cg = 0; cg < 4; cg++)
if (vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg],
vp6_huff_coeff_map, 12,
&s->ract_vlc[pt][ct][cg]))
@@ -704,15 +704,13 @@ static av_cold int vp6_decode_free(AVCodecContext *avctx)
static av_cold void vp6_decode_free_context(VP56Context *s)
{
- int pt, ct, cg;
-
ff_vp56_free_context(s);
- for (pt=0; pt<2; pt++) {
+ for (int pt = 0; pt < 2; ++pt) {
ff_vlc_free(&s->dccv_vlc[pt]);
ff_vlc_free(&s->runv_vlc[pt]);
- for (ct=0; ct<3; ct++)
- for (cg=0; cg<6; cg++)
+ for (int ct = 0; ct < 3; ++ct)
+ for (int cg = 0; cg < 4; ++cg)
ff_vlc_free(&s->ract_vlc[pt][ct][cg]);
}
}
--
2.45.2
[-- Attachment #4: 0003-avcodec-vp6-Don-t-reload-unnecessarily-often-in-get_.patch --]
[-- Type: text/x-patch, Size: 1969 bytes --]
From fde92954b4c0778aa61d40342db9da91af1a60d4 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 17 Apr 2025 19:48:05 +0200
Subject: [PATCH 03/13] avcodec/vp6: Don't reload unnecessarily often in
get_vlc2()
The VLC trees used here have very few different codes
and are therefore guaranteed to not be very deep: The AC/DC
VLCs have 12 elements and therefore a depth <= 11 whereas
the run VLCs have only nine elements and therefore a depth <= 8.
This allows to reduce the worst-case number of reloads for
reading a VLC code.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/vp6.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c
index 926694ae11..de60ae93bb 100644
--- a/libavcodec/vp6.c
+++ b/libavcodec/vp6.c
@@ -415,7 +415,7 @@ static int vp6_parse_coeff_huffman(VP56Context *s)
VP56Model *model = s->modelp;
uint8_t *permute = s->idct_scantable;
VLC *vlc_coeff;
- int coeff, sign, coeff_idx;
+ int sign, coeff_idx;
int b, cg, idx;
int pt = 0; /* plane type (0 for Y, 1 for U or V) */
@@ -433,11 +433,11 @@ static int vp6_parse_coeff_huffman(VP56Context *s)
} else {
if (get_bits_left(&s->gb) <= 0)
return AVERROR_INVALIDDATA;
- coeff = get_vlc2(&s->gb, vlc_coeff->table, FF_HUFFMAN_BITS, 3);
+ int coeff = get_vlc2(&s->gb, vlc_coeff->table, FF_HUFFMAN_BITS, 2);
if (coeff == 0) {
if (coeff_idx) {
int pt = (coeff_idx >= 6);
- run += get_vlc2(&s->gb, s->runv_vlc[pt].table, FF_HUFFMAN_BITS, 3);
+ run += get_vlc2(&s->gb, s->runv_vlc[pt].table, FF_HUFFMAN_BITS, 1);
if (run >= 9)
run += get_bits(&s->gb, 6);
} else
--
2.45.2
[-- Attachment #5: 0004-avcodec-vp6-Use-fewer-number-of-bits-in-run-VLCs.patch --]
[-- Type: text/x-patch, Size: 4196 bytes --]
From 10e53754d4bb14fd3188baab185494cdf387ad70 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 17 Apr 2025 20:13:56 +0200
Subject: [PATCH 04/13] avcodec/vp6: Use fewer number of bits in run VLCs
Given that these trees have only nine elements and are complete,
their depth is <= eight.
Also remove the now unused FF_HUFFMAN_BITS constant.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/huffman.h | 1 -
libavcodec/vp6.c | 18 ++++++++++++------
2 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/libavcodec/huffman.h b/libavcodec/huffman.h
index 1d5e140e81..dcf1f4ba78 100644
--- a/libavcodec/huffman.h
+++ b/libavcodec/huffman.h
@@ -38,7 +38,6 @@ typedef struct Node {
#define FF_HUFFMAN_FLAG_HNODE_FIRST 0x01
#define FF_HUFFMAN_FLAG_ZERO_COUNT 0x02
-#define FF_HUFFMAN_BITS 10
typedef int (*HuffCmp)(const void *va, const void *vb);
int ff_huff_build_tree(void *logctx, VLC *vlc, int nb_codes, int nb_bits,
diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c
index de60ae93bb..69cfc5fa8b 100644
--- a/libavcodec/vp6.c
+++ b/libavcodec/vp6.c
@@ -41,6 +41,8 @@
#include "vpx_rac.h"
#define VP6_MAX_HUFF_SIZE 12
+#define AC_DC_HUFF_BITS 10
+#define RUN_HUFF_BITS 8
static int vp6_parse_coeff(VP56Context *s);
static int vp6_parse_coeff_huffman(VP56Context *s);
@@ -266,7 +268,8 @@ static int vp6_huff_cmp(const void *va, const void *vb)
}
static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[],
- const uint8_t *map, unsigned size, VLC *vlc)
+ const uint8_t *map, unsigned size,
+ int nb_bits, VLC *vlc)
{
Node nodes[2*VP6_MAX_HUFF_SIZE], *tmp = &nodes[size];
int a, b, i;
@@ -282,7 +285,7 @@ static int vp6_build_huff_tree(VP56Context *s, uint8_t coeff_model[],
ff_vlc_free(vlc);
/* then build the huffman tree according to probabilities */
- return ff_huff_build_tree(s->avctx, vlc, size, FF_HUFFMAN_BITS,
+ return ff_huff_build_tree(s->avctx, vlc, size, nb_bits,
nodes, vp6_huff_cmp,
FF_HUFFMAN_FLAG_HNODE_FIRST);
}
@@ -333,15 +336,18 @@ static int vp6_parse_coeff_models(VP56Context *s)
if (s->use_huffman) {
for (pt=0; pt<2; pt++) {
if (vp6_build_huff_tree(s, model->coeff_dccv[pt],
- vp6_huff_coeff_map, 12, &s->dccv_vlc[pt]))
+ vp6_huff_coeff_map, 12, AC_DC_HUFF_BITS,
+ &s->dccv_vlc[pt]))
return -1;
if (vp6_build_huff_tree(s, model->coeff_runv[pt],
- vp6_huff_run_map, 9, &s->runv_vlc[pt]))
+ vp6_huff_run_map, 9, RUN_HUFF_BITS,
+ &s->runv_vlc[pt]))
return -1;
for (ct=0; ct<3; ct++)
for (int cg = 0; cg < 4; cg++)
if (vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg],
vp6_huff_coeff_map, 12,
+ AC_DC_HUFF_BITS,
&s->ract_vlc[pt][ct][cg]))
return -1;
}
@@ -433,11 +439,11 @@ static int vp6_parse_coeff_huffman(VP56Context *s)
} else {
if (get_bits_left(&s->gb) <= 0)
return AVERROR_INVALIDDATA;
- int coeff = get_vlc2(&s->gb, vlc_coeff->table, FF_HUFFMAN_BITS, 2);
+ int coeff = get_vlc2(&s->gb, vlc_coeff->table, AC_DC_HUFF_BITS, 2);
if (coeff == 0) {
if (coeff_idx) {
int pt = (coeff_idx >= 6);
- run += get_vlc2(&s->gb, s->runv_vlc[pt].table, FF_HUFFMAN_BITS, 1);
+ run += get_vlc2(&s->gb, s->runv_vlc[pt].table, RUN_HUFF_BITS, 1);
if (run >= 9)
run += get_bits(&s->gb, 6);
} else
--
2.45.2
[-- Attachment #6: 0005-avcodec-vp6-Forward-error-codes.patch --]
[-- Type: text/x-patch, Size: 2800 bytes --]
From faaa8ac870814de2d120849149f308ae8daaf751 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Thu, 17 Apr 2025 20:26:01 +0200
Subject: [PATCH 05/13] avcodec/vp6: Forward error codes
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/vp6.c | 33 +++++++++++++++++++--------------
1 file changed, 19 insertions(+), 14 deletions(-)
diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c
index 69cfc5fa8b..48ff9da818 100644
--- a/libavcodec/vp6.c
+++ b/libavcodec/vp6.c
@@ -298,6 +298,7 @@ static int vp6_parse_coeff_models(VP56Context *s)
int node, cg, ctx, pos;
int ct; /* code type */
int pt; /* plane type (0 for Y, 1 for U or V) */
+ int ret;
memset(def_prob, 0x80, sizeof(def_prob));
@@ -335,21 +336,25 @@ static int vp6_parse_coeff_models(VP56Context *s)
if (s->use_huffman) {
for (pt=0; pt<2; pt++) {
- if (vp6_build_huff_tree(s, model->coeff_dccv[pt],
- vp6_huff_coeff_map, 12, AC_DC_HUFF_BITS,
- &s->dccv_vlc[pt]))
- return -1;
- if (vp6_build_huff_tree(s, model->coeff_runv[pt],
- vp6_huff_run_map, 9, RUN_HUFF_BITS,
- &s->runv_vlc[pt]))
- return -1;
+ ret = vp6_build_huff_tree(s, model->coeff_dccv[pt],
+ vp6_huff_coeff_map, 12, AC_DC_HUFF_BITS,
+ &s->dccv_vlc[pt]);
+ if (ret < 0)
+ return ret;
+ ret = vp6_build_huff_tree(s, model->coeff_runv[pt],
+ vp6_huff_run_map, 9, RUN_HUFF_BITS,
+ &s->runv_vlc[pt]);
+ if (ret < 0)
+ return ret;
for (ct=0; ct<3; ct++)
- for (int cg = 0; cg < 4; cg++)
- if (vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg],
- vp6_huff_coeff_map, 12,
- AC_DC_HUFF_BITS,
- &s->ract_vlc[pt][ct][cg]))
- return -1;
+ for (int cg = 0; cg < 4; cg++) {
+ ret = vp6_build_huff_tree(s, model->coeff_ract[pt][ct][cg],
+ vp6_huff_coeff_map, 12,
+ AC_DC_HUFF_BITS,
+ &s->ract_vlc[pt][ct][cg]);
+ if (ret < 0)
+ return ret;
+ }
}
memset(s->nb_null, 0, sizeof(s->nb_null));
} else {
--
2.45.2
[-- Attachment #7: 0006-avcodec-cbs-Use-put_bits63.patch --]
[-- Type: text/x-patch, Size: 1470 bytes --]
From 709443e00fb342aaf2263c78e755dfde3c90f22d Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Fri, 18 Apr 2025 13:02:47 +0200
Subject: [PATCH 06/13] avcodec/cbs: Use put_bits63()
It is better when BUF_BITS == 64 (i.e. on x64), because
the underlying put_bits can then handle 0..63 bits naturally.
It does not worsen the code when BUF_BITS != 64, because
the compiler can optimize this to the same code as now
(due to the assert).
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/cbs.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index ba1034a72e..398d286a92 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -674,10 +674,7 @@ int CBS_FUNC(write_unsigned)(CodedBitstreamContext *ctx, PutBitContext *pbc,
if (put_bits_left(pbc) < width)
return AVERROR(ENOSPC);
- if (width < 32)
- put_bits(pbc, width, value);
- else
- put_bits32(pbc, value);
+ put_bits63(pbc, width, value);
CBS_TRACE_WRITE_END();
@@ -746,10 +743,7 @@ int CBS_FUNC(write_signed)(CodedBitstreamContext *ctx, PutBitContext *pbc,
if (put_bits_left(pbc) < width)
return AVERROR(ENOSPC);
- if (width < 32)
- put_sbits(pbc, width, value);
- else
- put_bits32(pbc, value);
+ put_bits63(pbc, width, zero_extend(value, width));
CBS_TRACE_WRITE_END();
--
2.45.2
[-- Attachment #8: 0007-avcodec-webp-Check-more-directly-for-invalid-codes.patch --]
[-- Type: text/x-patch, Size: 2095 bytes --]
From fd6140eba2ffd09fba80bd2ffc0232cc93197d12 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Fri, 18 Apr 2025 18:50:59 +0200
Subject: [PATCH 07/13] avcodec/webp: Check more directly for invalid codes
Don't rely on invalid codes leading to get_vlc2() returning
-1, which then gets converted to an uint8_t, i.e. to 255
and runs afoul of a length check later. After all, get_vlc2()
could be changed to return something else which may
be valid when cast to uint8_t.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/webp.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 9f83b518ad..46b20a1ab6 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -278,7 +278,7 @@ static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_length
for (sym = 0; sym < alphabet_size; sym++)
max_code_length = FFMAX(max_code_length, code_lengths[sym]);
- if (max_code_length == 0 || max_code_length > MAX_HUFFMAN_CODE_LENGTH)
+ if (max_code_length == 0)
return AVERROR(EINVAL);
codes = av_malloc_array(alphabet_size, sizeof(*codes));
@@ -375,7 +375,7 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
if (!max_symbol--)
break;
code_len = huff_reader_get_symbol(&code_len_hc, &s->gb);
- if (code_len < 16) {
+ if (code_len < 16U) {
/* Code length code [0..15] indicates literal code lengths. */
code_lengths[symbol++] = code_len;
if (code_len)
@@ -383,6 +383,9 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
} else {
int repeat = 0, length = 0;
switch (code_len) {
+ default:
+ ret = AVERROR_INVALIDDATA;
+ goto finish;
case 16:
/* Code 16 repeats the previous non-zero value [3..6] times,
* i.e., 3 + ReadBits(2) times. If code 16 is used before a
--
2.45.2
[-- Attachment #9: 0008-avcodec-webp-Switch-to-ff_vlc_init_from_lengths.patch --]
[-- Type: text/x-patch, Size: 7040 bytes --]
From bb09b7d7d7f0136c352c4e2a760e2ed9b18e1042 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Fri, 18 Apr 2025 19:29:41 +0200
Subject: [PATCH 08/13] 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@outlook.com>
---
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);
--
2.45.2
[-- Attachment #10: 0009-avcodec-webp-Check-before-allocations.patch --]
[-- Type: text/x-patch, Size: 1960 bytes --]
From 6d81b0862963d5e527ea1b976a61829f086a1913 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 20 Apr 2025 20:32:20 +0200
Subject: [PATCH 09/13] avcodec/webp: Check before allocations
Avoids freeing lateron.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/webp.c | 25 ++++++++++++-------------
1 file changed, 12 insertions(+), 13 deletions(-)
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 2c918eac33..2843b953bd 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -341,30 +341,29 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
len_counts[len]++;
}
- 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_malloc(alphabet_size);
- if (!code_lengths) {
- ret = AVERROR(ENOMEM);
- goto finish;
- }
-
if (get_bits1(&s->gb)) {
int bits = 2 + 2 * get_bits(&s->gb, 3);
max_symbol = 2 + get_bits(&s->gb, bits);
if (max_symbol > alphabet_size) {
av_log(s->avctx, AV_LOG_ERROR, "max symbol %d > alphabet size %d\n",
max_symbol, alphabet_size);
- ret = AVERROR_INVALIDDATA;
- goto finish;
+ return AVERROR_INVALIDDATA;
}
} else {
max_symbol = alphabet_size;
}
+ 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_malloc(alphabet_size);
+ if (!code_lengths) {
+ ret = AVERROR(ENOMEM);
+ goto finish;
+ }
+
prev_code_len = 8;
symbol = 0;
memset(len_counts, 0, sizeof(len_counts));
--
2.45.2
[-- Attachment #11: 0010-avcodec-webp-Combine-allocations.patch --]
[-- Type: text/x-patch, Size: 3451 bytes --]
From 765bbe86f0fe005ff187f24443d7c2fb04b4903a Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 20 Apr 2025 20:51:59 +0200
Subject: [PATCH 10/13] avcodec/webp: Combine allocations
Or avoid them altogether for the small stage-one VLC.
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/webp.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index 2843b953bd..e26bf01c6a 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -254,10 +254,9 @@ static int huff_reader_get_symbol(HuffReader *r, GetBitContext *gb)
static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_lengths,
uint16_t len_counts[MAX_HUFFMAN_CODE_LENGTH + 1],
+ uint8_t lens[], uint16_t syms[],
int alphabet_size, void *logctx)
{
- uint16_t *syms;
- uint8_t *lens;
unsigned nb_codes = 0;
int ret;
@@ -285,11 +284,6 @@ static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_length
return AVERROR_INVALIDDATA;
}
- syms = av_malloc_array(nb_codes, sizeof(*syms) + sizeof(*lens));
- if (!syms)
- return AVERROR(ENOMEM);
- lens = (uint8_t*)(syms + nb_codes);
-
for (int sym = 0; sym < alphabet_size; ++sym) {
if (code_lengths[sym]) {
unsigned idx = len_counts[code_lengths[sym]]++;
@@ -300,7 +294,6 @@ static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_length
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;
@@ -329,6 +322,8 @@ 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 };
+ uint8_t reordered_code_length_code_lengths[NUM_CODE_LENGTH_CODES];
+ uint16_t reordered_code_length_syms[NUM_CODE_LENGTH_CODES];
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);
@@ -354,11 +349,13 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
}
ret = huff_reader_build_canonical(&code_len_hc, code_length_code_lengths, len_counts,
+ reordered_code_length_code_lengths,
+ reordered_code_length_syms,
NUM_CODE_LENGTH_CODES, s->avctx);
if (ret < 0)
return ret;
- code_lengths = av_malloc(alphabet_size);
+ code_lengths = av_malloc_array(alphabet_size, 2 * sizeof(uint8_t) + sizeof(uint16_t));
if (!code_lengths) {
ret = AVERROR(ENOMEM);
goto finish;
@@ -417,6 +414,8 @@ static int read_huffman_code_normal(WebPContext *s, HuffReader *hc,
}
ret = huff_reader_build_canonical(hc, code_lengths, len_counts,
+ code_lengths + symbol,
+ (uint16_t*)(code_lengths + 2 * symbol),
symbol, s->avctx);
finish:
--
2.45.2
[-- Attachment #12: 0011-avcodec-webp-Avoid-loop.patch --]
[-- Type: text/x-patch, Size: 1924 bytes --]
From e7c96c9061addc2c41ce76973f040a24e07be5d9 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Sun, 20 Apr 2025 21:29:47 +0200
Subject: [PATCH 11/13] avcodec/webp: Avoid loop
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/webp.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/libavcodec/webp.c b/libavcodec/webp.c
index e26bf01c6a..7d77d64524 100644
--- a/libavcodec/webp.c
+++ b/libavcodec/webp.c
@@ -267,31 +267,24 @@ static int huff_reader_build_canonical(HuffReader *r, const uint8_t *code_length
len_counts[len] = nb_codes;
nb_codes += cnt;
}
+
+ 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];
+ }
+ }
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;
- }
- }
+ r->simple_symbols[0] = syms[0];
}
// No symbols
return AVERROR_INVALIDDATA;
}
-
- 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];
- }
- }
-
ret = ff_vlc_init_from_lengths(&r->vlc, 8, nb_codes, lens, 1,
syms, 2, 2, 0, VLC_INIT_OUTPUT_LE, logctx);
if (ret < 0)
--
2.45.2
[-- Attachment #13: 0012-avcodec-magicyuv-Set-properties-via-AVPixFmtDescript.patch --]
[-- Type: text/x-patch, Size: 3608 bytes --]
From 3ff308b055ba3b8a6a501e7b1bf56a9a3ddef1a9 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Mon, 21 Apr 2025 12:20:01 +0200
Subject: [PATCH 12/13] avcodec/magicyuv: Set properties via AVPixFmtDescriptor
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/magicyuv.c | 43 ++++++-------------------------------------
1 file changed, 6 insertions(+), 37 deletions(-)
diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c
index b85505c428..4a5c0be9e0 100644
--- a/libavcodec/magicyuv.c
+++ b/libavcodec/magicyuv.c
@@ -462,37 +462,22 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
return AVERROR_PATCHWELCOME;
}
- s->hshift[1] =
- s->vshift[1] =
- s->hshift[2] =
- s->vshift[2] = 0;
- s->decorrelate = 0;
- s->bps = 8;
-
format = bytestream2_get_byteu(&gb);
switch (format) {
case 0x65:
avctx->pix_fmt = AV_PIX_FMT_GBRP;
- s->decorrelate = 1;
break;
case 0x66:
avctx->pix_fmt = AV_PIX_FMT_GBRAP;
- s->decorrelate = 1;
break;
case 0x67:
avctx->pix_fmt = AV_PIX_FMT_YUV444P;
break;
case 0x68:
avctx->pix_fmt = AV_PIX_FMT_YUV422P;
- s->hshift[1] =
- s->hshift[2] = 1;
break;
case 0x69:
avctx->pix_fmt = AV_PIX_FMT_YUV420P;
- s->hshift[1] =
- s->vshift[1] =
- s->hshift[2] =
- s->vshift[2] = 1;
break;
case 0x6a:
avctx->pix_fmt = AV_PIX_FMT_YUVA444P;
@@ -502,60 +487,44 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
break;
case 0x6c:
avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
- s->hshift[1] =
- s->hshift[2] = 1;
- s->bps = 10;
break;
case 0x76:
avctx->pix_fmt = AV_PIX_FMT_YUV444P10;
- s->bps = 10;
break;
case 0x6d:
avctx->pix_fmt = AV_PIX_FMT_GBRP10;
- s->decorrelate = 1;
- s->bps = 10;
break;
case 0x6e:
avctx->pix_fmt = AV_PIX_FMT_GBRAP10;
- s->decorrelate = 1;
- s->bps = 10;
break;
case 0x6f:
avctx->pix_fmt = AV_PIX_FMT_GBRP12;
- s->decorrelate = 1;
- s->bps = 12;
break;
case 0x70:
avctx->pix_fmt = AV_PIX_FMT_GBRAP12;
- s->decorrelate = 1;
- s->bps = 12;
break;
case 0x71:
avctx->pix_fmt = AV_PIX_FMT_GBRP14;
- s->decorrelate = 1;
- s->bps = 14;
break;
case 0x72:
avctx->pix_fmt = AV_PIX_FMT_GBRAP14;
- s->decorrelate = 1;
- s->bps = 14;
break;
case 0x73:
avctx->pix_fmt = AV_PIX_FMT_GRAY10;
- s->bps = 10;
break;
case 0x7b:
avctx->pix_fmt = AV_PIX_FMT_YUV420P10;
- s->hshift[1] =
- s->vshift[1] =
- s->hshift[2] =
- s->vshift[2] = 1;
- s->bps = 10;
break;
default:
avpriv_request_sample(avctx, "Format 0x%X", format);
return AVERROR_PATCHWELCOME;
}
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+ av_assert1(desc);
+ s->decorrelate = !!(desc->flags & AV_PIX_FMT_FLAG_RGB);
+ s->hshift[1] = s->hshift[2] = desc->log2_chroma_w;
+ s->vshift[1] = s->vshift[2] = desc->log2_chroma_h;
+ s->bps = desc->comp[0].depth;
s->max = 1 << s->bps;
s->magy_decode_slice = s->bps == 8 ? magy_decode_slice : magy_decode_slice10;
s->planes = av_pix_fmt_count_planes(avctx->pix_fmt);
--
2.45.2
[-- Attachment #14: 0013-avcodec-magicyuv-Simplify-check-for-RGB.patch --]
[-- Type: text/x-patch, Size: 1727 bytes --]
From 3071d662a403760b4d0ff210d76415f5c23647a6 Mon Sep 17 00:00:00 2001
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
Date: Mon, 21 Apr 2025 12:35:42 +0200
Subject: [PATCH 13/13] avcodec/magicyuv: Simplify check for RGB
Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
libavcodec/magicyuv.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c
index 4a5c0be9e0..e106228757 100644
--- a/libavcodec/magicyuv.c
+++ b/libavcodec/magicyuv.c
@@ -521,7 +521,7 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
}
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
av_assert1(desc);
- s->decorrelate = !!(desc->flags & AV_PIX_FMT_FLAG_RGB);
+ int is_rgb = s->decorrelate = !!(desc->flags & AV_PIX_FMT_FLAG_RGB);
s->hshift[1] = s->hshift[2] = desc->log2_chroma_w;
s->vshift[1] = s->vshift[2] = desc->log2_chroma_h;
s->bps = desc->comp[0].depth;
@@ -628,14 +628,7 @@ static int magy_decode_frame(AVCodecContext *avctx, AVFrame *p,
s->p = p;
avctx->execute2(avctx, s->magy_decode_slice, NULL, NULL, s->nb_slices);
- if (avctx->pix_fmt == AV_PIX_FMT_GBRP ||
- avctx->pix_fmt == AV_PIX_FMT_GBRAP ||
- avctx->pix_fmt == AV_PIX_FMT_GBRP10 ||
- avctx->pix_fmt == AV_PIX_FMT_GBRAP10||
- avctx->pix_fmt == AV_PIX_FMT_GBRAP12||
- avctx->pix_fmt == AV_PIX_FMT_GBRAP14||
- avctx->pix_fmt == AV_PIX_FMT_GBRP12||
- avctx->pix_fmt == AV_PIX_FMT_GBRP14) {
+ if (is_rgb) {
FFSWAP(uint8_t*, p->data[0], p->data[1]);
FFSWAP(int, p->linesize[0], p->linesize[1]);
} else {
--
2.45.2
[-- Attachment #15: Type: text/plain, Size: 251 bytes --]
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [FFmpeg-devel] [PATCH 01/13] avcodec/huffman: Switch to ff_vlc_init_from_lengths()
2025-04-21 11:28 [FFmpeg-devel] [PATCH 01/13] avcodec/huffman: Switch to ff_vlc_init_from_lengths() Andreas Rheinhardt
@ 2025-04-25 10:39 ` Andreas Rheinhardt
0 siblings, 0 replies; 2+ messages in thread
From: Andreas Rheinhardt @ 2025-04-25 10:39 UTC (permalink / raw)
To: ffmpeg-devel
Andreas Rheinhardt:
> Patches attached.
>
> - Andreas
>
>
Will apply this patchset tonight unless there are objections.
- Andreas
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2025-04-25 10:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-21 11:28 [FFmpeg-devel] [PATCH 01/13] avcodec/huffman: Switch to ff_vlc_init_from_lengths() Andreas Rheinhardt
2025-04-25 10:39 ` Andreas Rheinhardt
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git