Reduce number of memory allocations while decoding lossless.

This change reduces the number of calls to WebPSafeMalloc from 200 to
100. The overall memory consumption is down 3% for Lenna image.

Change-Id: I1b351a1f61abf2634c035ef1ccb34050b7876bdd
This commit is contained in:
Vikas Arora
2014-04-30 21:41:32 +00:00
committed by James Zern
parent 888e63edc9
commit 9383afd5c7
4 changed files with 133 additions and 86 deletions

View File

@ -22,6 +22,9 @@
// (might be faster on some platform)
// #define USE_LUT_REVERSE_BITS
// Huffman data read via DecodeImageStream is represented in two (red and green)
// bytes.
#define MAX_HTREE_GROUPS 0x10000
#define NON_EXISTENT_SYMBOL (-1)
static void TreeNodeInit(HuffmanTreeNode* const node) {
@ -46,17 +49,25 @@ static void AssignChildren(HuffmanTree* const tree,
TreeNodeInit(children + 1);
}
// A Huffman tree is a full binary tree; and in a full binary tree with L
// leaves, the total number of nodes N = 2 * L - 1.
static int HuffmanTreeMaxNodes(int num_leaves) {
return (2 * num_leaves - 1);
}
static int HuffmanTreeAllocate(HuffmanTree* const tree, int num_nodes) {
assert(tree != NULL);
tree->root_ =
(HuffmanTreeNode*)WebPSafeMalloc(num_nodes, sizeof(*tree->root_));
return (tree->root_ != NULL);
}
static int TreeInit(HuffmanTree* const tree, int num_leaves) {
assert(tree != NULL);
if (num_leaves == 0) return 0;
// We allocate maximum possible nodes in the tree at once.
// Note that a Huffman tree is a full binary tree; and in a full binary tree
// with L leaves, the total number of nodes N = 2 * L - 1.
tree->max_nodes_ = 2 * num_leaves - 1;
tree->max_nodes_ = HuffmanTreeMaxNodes(num_leaves);
assert(tree->max_nodes_ < (1 << 16)); // limit for the lut_jump_ table
tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_,
sizeof(*tree->root_));
if (tree->root_ == NULL) return 0;
if (!HuffmanTreeAllocate(tree, tree->max_nodes_)) return 0;
TreeNodeInit(tree->root_); // Initialize root.
tree->num_nodes_ = 1;
memset(tree->lut_bits_, 255, sizeof(tree->lut_bits_));
@ -64,7 +75,7 @@ static int TreeInit(HuffmanTree* const tree, int num_leaves) {
return 1;
}
void HuffmanTreeRelease(HuffmanTree* const tree) {
void VP8LHuffmanTreeFree(HuffmanTree* const tree) {
if (tree != NULL) {
WebPSafeFree(tree->root_);
tree->root_ = NULL;
@ -73,8 +84,32 @@ void HuffmanTreeRelease(HuffmanTree* const tree) {
}
}
int HuffmanCodeLengthsToCodes(const int* const code_lengths,
int code_lengths_size, int* const huff_codes) {
HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups) {
HTreeGroup* const htree_groups =
(HTreeGroup*)WebPSafeCalloc(num_htree_groups, sizeof(*htree_groups));
assert(num_htree_groups <= MAX_HTREE_GROUPS);
if (htree_groups == NULL) {
return NULL;
}
return htree_groups;
}
void VP8LHtreeGroupsFree(HTreeGroup* htree_groups, int num_htree_groups) {
if (htree_groups != NULL) {
int i, j;
for (i = 0; i < num_htree_groups; ++i) {
HuffmanTree* const htrees = htree_groups[i].htrees_;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
VP8LHuffmanTreeFree(&htrees[j]);
}
}
WebPSafeFree(htree_groups);
}
}
int VP8LHuffmanCodeLengthsToCodes(
const int* const code_lengths, int code_lengths_size,
int* const huff_codes) {
int symbol;
int code_len;
int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
@ -193,9 +228,10 @@ static int TreeAddSymbol(HuffmanTree* const tree,
return 1;
}
int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
const int* const code_lengths,
int code_lengths_size) {
int VP8LHuffmanTreeBuildImplicit(HuffmanTree* const tree,
const int* const code_lengths,
int* const codes,
int code_lengths_size) {
int symbol;
int num_symbols = 0;
int root_symbol = 0;
@ -219,47 +255,43 @@ int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
if (num_symbols == 1) { // Trivial case.
const int max_symbol = code_lengths_size;
if (root_symbol < 0 || root_symbol >= max_symbol) {
HuffmanTreeRelease(tree);
VP8LHuffmanTreeFree(tree);
return 0;
}
return TreeAddSymbol(tree, root_symbol, 0, 0);
} else { // Normal case.
int ok = 0;
memset(codes, 0, code_lengths_size * sizeof(*codes));
// Get Huffman codes from the code lengths.
int* const codes =
(int*)WebPSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes));
if (codes == NULL) goto End;
if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) {
if (!VP8LHuffmanCodeLengthsToCodes(code_lengths, code_lengths_size,
codes)) {
goto End;
}
// Add symbols one-by-one.
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
if (code_lengths[symbol] > 0) {
if (!TreeAddSymbol(tree, symbol, codes[symbol], code_lengths[symbol])) {
if (!TreeAddSymbol(tree, symbol, codes[symbol],
code_lengths[symbol])) {
goto End;
}
}
}
ok = 1;
End:
WebPSafeFree(codes);
ok = ok && IsFull(tree);
if (!ok) HuffmanTreeRelease(tree);
if (!ok) VP8LHuffmanTreeFree(tree);
return ok;
}
}
int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
const int* const code_lengths,
const int* const codes,
const int* const symbols, int max_symbol,
int num_symbols) {
int VP8LHuffmanTreeBuildExplicit(HuffmanTree* const tree,
const int* const code_lengths,
const int* const codes,
const int* const symbols, int max_symbol,
int num_symbols) {
int ok = 0;
int i;
assert(tree != NULL);
assert(code_lengths != NULL);
assert(codes != NULL);
@ -282,7 +314,6 @@ int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
ok = 1;
End:
ok = ok && IsFull(tree);
if (!ok) HuffmanTreeRelease(tree);
if (!ok) VP8LHuffmanTreeFree(tree);
return ok;
}