mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-01-27 17:53:13 +00:00
avcodec/smacker: Improve creating Huffman VLC tables
The Smacker Huffman tables are already stored in a tree-like structure; in particular, they are naturally ordered from left to right in the tree and are therefore suitable to be initialized by ff_init_vlc_from_lengths() which avoids traversing the data twice in order to sort only the codes that are so long that they need into a subtable. This improves performance (and reduces codesize): For the sample from ticket #2425 the number of decicycles for parsing and creating the VLCs in smka_decode_frame() decreased from 412322 to 359152 (tested with 10 runs each looping 20 times over the file). Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@gmail.com>
This commit is contained in:
parent
09062eece2
commit
fefe2cbbf2
@ -62,14 +62,17 @@ typedef struct SmackVContext {
|
|||||||
int mmap_last[3], mclr_last[3], full_last[3], type_last[3];
|
int mmap_last[3], mclr_last[3], full_last[3], type_last[3];
|
||||||
} SmackVContext;
|
} SmackVContext;
|
||||||
|
|
||||||
|
typedef struct HuffEntry {
|
||||||
|
uint8_t value;
|
||||||
|
uint8_t length;
|
||||||
|
} HuffEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context used for code reconstructing
|
* Context used for code reconstructing
|
||||||
*/
|
*/
|
||||||
typedef struct HuffContext {
|
typedef struct HuffContext {
|
||||||
int current;
|
int current;
|
||||||
uint32_t bits[256];
|
HuffEntry entries[256];
|
||||||
uint8_t lengths[256];
|
|
||||||
uint8_t values[256];
|
|
||||||
} HuffContext;
|
} HuffContext;
|
||||||
|
|
||||||
/* common parameters used for decode_bigtree */
|
/* common parameters used for decode_bigtree */
|
||||||
@ -105,7 +108,7 @@ enum SmkBlockTypes {
|
|||||||
* Can read SMKTREE_DECODE_MAX_RECURSION before the first check;
|
* Can read SMKTREE_DECODE_MAX_RECURSION before the first check;
|
||||||
* does not overread gb on success.
|
* does not overread gb on success.
|
||||||
*/
|
*/
|
||||||
static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length)
|
static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, int length)
|
||||||
{
|
{
|
||||||
if (length > SMKTREE_DECODE_MAX_RECURSION || length > 3 * SMKTREE_BITS) {
|
if (length > SMKTREE_DECODE_MAX_RECURSION || length > 3 * SMKTREE_BITS) {
|
||||||
av_log(NULL, AV_LOG_ERROR, "Maximum tree recursion level exceeded.\n");
|
av_log(NULL, AV_LOG_ERROR, "Maximum tree recursion level exceeded.\n");
|
||||||
@ -119,18 +122,15 @@ static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t pref
|
|||||||
}
|
}
|
||||||
if (get_bits_left(gb) < 8)
|
if (get_bits_left(gb) < 8)
|
||||||
return AVERROR_INVALIDDATA;
|
return AVERROR_INVALIDDATA;
|
||||||
hc->bits[hc->current] = prefix;
|
hc->entries[hc->current++] = (HuffEntry){ get_bits(gb, 8), length };
|
||||||
hc->lengths[hc->current] = length;
|
|
||||||
hc->values[hc->current] = get_bits(gb, 8);
|
|
||||||
hc->current++;
|
|
||||||
return 0;
|
return 0;
|
||||||
} else { //Node
|
} else { //Node
|
||||||
int r;
|
int r;
|
||||||
length++;
|
length++;
|
||||||
r = smacker_decode_tree(gb, hc, prefix, length);
|
r = smacker_decode_tree(gb, hc, length);
|
||||||
if(r)
|
if(r)
|
||||||
return r;
|
return r;
|
||||||
return smacker_decode_tree(gb, hc, prefix | (1U << (length - 1)), length);
|
return smacker_decode_tree(gb, hc, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,22 +216,21 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int
|
|||||||
i ? "high" : "low");
|
i ? "high" : "low");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
err = smacker_decode_tree(gb, &h, 0, 0);
|
err = smacker_decode_tree(gb, &h, 0);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
skip_bits1(gb);
|
skip_bits1(gb);
|
||||||
if (h.current > 1) {
|
if (h.current > 1) {
|
||||||
err = ff_init_vlc_sparse(&vlc[i], SMKTREE_BITS, h.current,
|
err = ff_init_vlc_from_lengths(&vlc[i], SMKTREE_BITS, h.current,
|
||||||
h.lengths, sizeof(*h.lengths), sizeof(*h.lengths),
|
&h.entries[0].length, sizeof(*h.entries),
|
||||||
h.bits, sizeof(*h.bits), sizeof(*h.bits),
|
&h.entries[0].value, sizeof(*h.entries), 1,
|
||||||
h.values, sizeof(*h.values), sizeof(*h.values),
|
0, INIT_VLC_OUTPUT_LE, smk->avctx);
|
||||||
INIT_VLC_LE);
|
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
|
av_log(smk->avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
ctx.vals[i] = h.values[0];
|
ctx.vals[i] = h.entries[0].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
escapes[0] = get_bits(gb, 16);
|
escapes[0] = get_bits(gb, 16);
|
||||||
@ -650,21 +649,20 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data,
|
|||||||
HuffContext h;
|
HuffContext h;
|
||||||
h.current = 0;
|
h.current = 0;
|
||||||
skip_bits1(&gb);
|
skip_bits1(&gb);
|
||||||
if ((ret = smacker_decode_tree(&gb, &h, 0, 0)) < 0)
|
if ((ret = smacker_decode_tree(&gb, &h, 0)) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
skip_bits1(&gb);
|
skip_bits1(&gb);
|
||||||
if (h.current > 1) {
|
if (h.current > 1) {
|
||||||
ret = ff_init_vlc_sparse(&vlc[i], SMKTREE_BITS, h.current,
|
ret = ff_init_vlc_from_lengths(&vlc[i], SMKTREE_BITS, h.current,
|
||||||
h.lengths, sizeof(*h.lengths), sizeof(*h.lengths),
|
&h.entries[0].length, sizeof(*h.entries),
|
||||||
h.bits, sizeof(*h.bits), sizeof(*h.bits),
|
&h.entries[0].value, sizeof(*h.entries), 1,
|
||||||
h.values, sizeof(*h.values), sizeof(*h.values),
|
0, INIT_VLC_OUTPUT_LE, avctx);
|
||||||
INIT_VLC_LE);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
av_log(avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
|
av_log(avctx, AV_LOG_ERROR, "Cannot build VLC table\n");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
values[i] = h.values[0];
|
values[i] = h.entries[0].value;
|
||||||
}
|
}
|
||||||
/* this codec relies on wraparound instead of clipping audio */
|
/* this codec relies on wraparound instead of clipping audio */
|
||||||
if(bits) { //decode 16-bit data
|
if(bits) { //decode 16-bit data
|
||||||
|
Loading…
Reference in New Issue
Block a user