mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 13:48:21 +01:00
Speedups for unused Huffman groups.
If we know a Huffman group is unused, do not build it: just check that it is valid. Change-Id: Ie8223fe1afa1e769085a23ab92e730edd9060176
This commit is contained in:
parent
01ac46bae6
commit
067031eaed
@ -362,12 +362,8 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
VP8LMetadata* const hdr = &dec->hdr_;
|
VP8LMetadata* const hdr = &dec->hdr_;
|
||||||
uint32_t* huffman_image = NULL;
|
uint32_t* huffman_image = NULL;
|
||||||
HTreeGroup* htree_groups = NULL;
|
HTreeGroup* htree_groups = NULL;
|
||||||
// When reading htrees, some might be unused, as the format allows it.
|
|
||||||
// We will still read them but put them in this htree_group_bogus.
|
|
||||||
HTreeGroup htree_group_bogus;
|
|
||||||
HuffmanCode* huffman_tables = NULL;
|
HuffmanCode* huffman_tables = NULL;
|
||||||
HuffmanCode* huffman_tables_bogus = NULL;
|
HuffmanCode* huffman_table = NULL;
|
||||||
HuffmanCode* next = NULL;
|
|
||||||
int num_htree_groups = 1;
|
int num_htree_groups = 1;
|
||||||
int num_htree_groups_max = 1;
|
int num_htree_groups_max = 1;
|
||||||
int max_alphabet_size = 0;
|
int max_alphabet_size = 0;
|
||||||
@ -418,12 +414,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
if (*mapped_group == -1) *mapped_group = num_htree_groups++;
|
if (*mapped_group == -1) *mapped_group = num_htree_groups++;
|
||||||
huffman_image[i] = *mapped_group;
|
huffman_image[i] = *mapped_group;
|
||||||
}
|
}
|
||||||
huffman_tables_bogus = (HuffmanCode*)WebPSafeMalloc(
|
|
||||||
table_size, sizeof(*huffman_tables_bogus));
|
|
||||||
if (huffman_tables_bogus == NULL) {
|
|
||||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
num_htree_groups = num_htree_groups_max;
|
num_htree_groups = num_htree_groups_max;
|
||||||
}
|
}
|
||||||
@ -453,63 +443,71 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
next = huffman_tables;
|
huffman_table = huffman_tables;
|
||||||
for (i = 0; i < num_htree_groups_max; ++i) {
|
for (i = 0; i < num_htree_groups_max; ++i) {
|
||||||
// If the index "i" is unused in the Huffman image, read the coefficients
|
// If the index "i" is unused in the Huffman image, just make sure the
|
||||||
// but store them to a bogus htree_group.
|
// coefficients are valid but do not store them.
|
||||||
const int is_bogus = (mapping != NULL && mapping[i] == -1);
|
if (mapping != NULL && mapping[i] == -1) {
|
||||||
HTreeGroup* const htree_group =
|
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||||
is_bogus ? &htree_group_bogus :
|
int alphabet_size = kAlphabetSize[j];
|
||||||
&htree_groups[(mapping == NULL) ? i : mapping[i]];
|
if (j == 0 && color_cache_bits > 0) {
|
||||||
HuffmanCode** const htrees = htree_group->htrees;
|
alphabet_size += (1 << color_cache_bits);
|
||||||
HuffmanCode* huffman_tables_i = is_bogus ? huffman_tables_bogus : next;
|
}
|
||||||
int size;
|
// Passing in NULL so that nothing gets filled.
|
||||||
int total_size = 0;
|
if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, NULL)) {
|
||||||
int is_trivial_literal = 1;
|
goto Error;
|
||||||
int max_bits = 0;
|
|
||||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
|
||||||
int alphabet_size = kAlphabetSize[j];
|
|
||||||
htrees[j] = huffman_tables_i;
|
|
||||||
if (j == 0 && color_cache_bits > 0) {
|
|
||||||
alphabet_size += 1 << color_cache_bits;
|
|
||||||
}
|
|
||||||
size =
|
|
||||||
ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables_i);
|
|
||||||
if (size == 0) {
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
|
||||||
is_trivial_literal = (huffman_tables_i->bits == 0);
|
|
||||||
}
|
|
||||||
total_size += huffman_tables_i->bits;
|
|
||||||
huffman_tables_i += size;
|
|
||||||
if (j <= ALPHA) {
|
|
||||||
int local_max_bits = code_lengths[0];
|
|
||||||
int k;
|
|
||||||
for (k = 1; k < alphabet_size; ++k) {
|
|
||||||
if (code_lengths[k] > local_max_bits) {
|
|
||||||
local_max_bits = code_lengths[k];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
max_bits += local_max_bits;
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if (!is_bogus) next = huffman_tables_i;
|
HTreeGroup* const htree_group =
|
||||||
htree_group->is_trivial_literal = is_trivial_literal;
|
&htree_groups[(mapping == NULL) ? i : mapping[i]];
|
||||||
htree_group->is_trivial_code = 0;
|
HuffmanCode** const htrees = htree_group->htrees;
|
||||||
if (is_trivial_literal) {
|
int size;
|
||||||
const int red = htrees[RED][0].value;
|
int total_size = 0;
|
||||||
const int blue = htrees[BLUE][0].value;
|
int is_trivial_literal = 1;
|
||||||
const int alpha = htrees[ALPHA][0].value;
|
int max_bits = 0;
|
||||||
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
|
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||||
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
|
int alphabet_size = kAlphabetSize[j];
|
||||||
htree_group->is_trivial_code = 1;
|
htrees[j] = huffman_table;
|
||||||
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
|
if (j == 0 && color_cache_bits > 0) {
|
||||||
|
alphabet_size += (1 << color_cache_bits);
|
||||||
|
}
|
||||||
|
size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
|
||||||
|
if (size == 0) {
|
||||||
|
goto Error;
|
||||||
|
}
|
||||||
|
if (is_trivial_literal && kLiteralMap[j] == 1) {
|
||||||
|
is_trivial_literal = (huffman_table->bits == 0);
|
||||||
|
}
|
||||||
|
total_size += huffman_table->bits;
|
||||||
|
huffman_table += size;
|
||||||
|
if (j <= ALPHA) {
|
||||||
|
int local_max_bits = code_lengths[0];
|
||||||
|
int k;
|
||||||
|
for (k = 1; k < alphabet_size; ++k) {
|
||||||
|
if (code_lengths[k] > local_max_bits) {
|
||||||
|
local_max_bits = code_lengths[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
max_bits += local_max_bits;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
htree_group->is_trivial_literal = is_trivial_literal;
|
||||||
|
htree_group->is_trivial_code = 0;
|
||||||
|
if (is_trivial_literal) {
|
||||||
|
const int red = htrees[RED][0].value;
|
||||||
|
const int blue = htrees[BLUE][0].value;
|
||||||
|
const int alpha = htrees[ALPHA][0].value;
|
||||||
|
htree_group->literal_arb = ((uint32_t)alpha << 24) | (red << 16) | blue;
|
||||||
|
if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
|
||||||
|
htree_group->is_trivial_code = 1;
|
||||||
|
htree_group->literal_arb |= htrees[GREEN][0].value << 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
htree_group->use_packed_table =
|
||||||
|
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
|
||||||
|
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
|
||||||
}
|
}
|
||||||
htree_group->use_packed_table =
|
|
||||||
!htree_group->is_trivial_code && (max_bits < HUFFMAN_PACKED_BITS);
|
|
||||||
if (htree_group->use_packed_table) BuildPackedTable(htree_group);
|
|
||||||
}
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
@ -521,7 +519,6 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
|
|
||||||
Error:
|
Error:
|
||||||
WebPSafeFree(code_lengths);
|
WebPSafeFree(code_lengths);
|
||||||
WebPSafeFree(huffman_tables_bogus);
|
|
||||||
WebPSafeFree(mapping);
|
WebPSafeFree(mapping);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
WebPSafeFree(huffman_image);
|
WebPSafeFree(huffman_image);
|
||||||
|
@ -91,7 +91,8 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
|||||||
|
|
||||||
assert(code_lengths_size != 0);
|
assert(code_lengths_size != 0);
|
||||||
assert(code_lengths != NULL);
|
assert(code_lengths != NULL);
|
||||||
assert(root_table != NULL);
|
assert((root_table != NULL && sorted != NULL) ||
|
||||||
|
(root_table == NULL && sorted == NULL));
|
||||||
assert(root_bits > 0);
|
assert(root_bits > 0);
|
||||||
|
|
||||||
// Build histogram of code lengths.
|
// Build histogram of code lengths.
|
||||||
@ -120,16 +121,22 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
|||||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||||
const int symbol_code_length = code_lengths[symbol];
|
const int symbol_code_length = code_lengths[symbol];
|
||||||
if (code_lengths[symbol] > 0) {
|
if (code_lengths[symbol] > 0) {
|
||||||
sorted[offset[symbol_code_length]++] = symbol;
|
if (sorted != NULL) {
|
||||||
|
sorted[offset[symbol_code_length]++] = symbol;
|
||||||
|
} else {
|
||||||
|
offset[symbol_code_length]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case code with only one value.
|
// Special case code with only one value.
|
||||||
if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
|
if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
|
||||||
HuffmanCode code;
|
if (sorted != NULL) {
|
||||||
code.bits = 0;
|
HuffmanCode code;
|
||||||
code.value = (uint16_t)sorted[0];
|
code.bits = 0;
|
||||||
ReplicateValue(table, 1, total_size, code);
|
code.value = (uint16_t)sorted[0];
|
||||||
|
ReplicateValue(table, 1, total_size, code);
|
||||||
|
}
|
||||||
return total_size;
|
return total_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +158,7 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
|||||||
if (num_open < 0) {
|
if (num_open < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (root_table == NULL) continue;
|
||||||
for (; count[len] > 0; --count[len]) {
|
for (; count[len] > 0; --count[len]) {
|
||||||
HuffmanCode code;
|
HuffmanCode code;
|
||||||
code.bits = (uint8_t)len;
|
code.bits = (uint8_t)len;
|
||||||
@ -169,6 +177,7 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
|||||||
if (num_open < 0) {
|
if (num_open < 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (root_table == NULL) continue;
|
||||||
for (; count[len] > 0; --count[len]) {
|
for (; count[len] > 0; --count[len]) {
|
||||||
HuffmanCode code;
|
HuffmanCode code;
|
||||||
if ((key & mask) != low) {
|
if ((key & mask) != low) {
|
||||||
@ -206,7 +215,10 @@ int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
|||||||
const int code_lengths[], int code_lengths_size) {
|
const int code_lengths[], int code_lengths_size) {
|
||||||
int total_size;
|
int total_size;
|
||||||
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
|
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
|
||||||
if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
if (root_table == NULL) {
|
||||||
|
total_size = BuildHuffmanTable(NULL, root_bits,
|
||||||
|
code_lengths, code_lengths_size, NULL);
|
||||||
|
} else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
|
||||||
// use local stack-allocated array.
|
// use local stack-allocated array.
|
||||||
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
uint16_t sorted[SORTED_SIZE_CUTOFF];
|
||||||
total_size = BuildHuffmanTable(root_table, root_bits,
|
total_size = BuildHuffmanTable(root_table, root_bits,
|
||||||
|
@ -78,6 +78,8 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
|
|||||||
// the huffman table.
|
// the huffman table.
|
||||||
// Returns built table size or 0 in case of error (invalid tree or
|
// Returns built table size or 0 in case of error (invalid tree or
|
||||||
// memory error).
|
// memory error).
|
||||||
|
// If root_table is NULL, it returns 0 if a lookup cannot be built, something
|
||||||
|
// > 0 otherwise (but not the table size).
|
||||||
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
|
||||||
const int code_lengths[], int code_lengths_size);
|
const int code_lengths[], int code_lengths_size);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user