mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-28 14:38:21 +01:00
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:
parent
888e63edc9
commit
9383afd5c7
@ -187,9 +187,10 @@ static int ReadHuffmanCodeLengths(
|
|||||||
int max_symbol;
|
int max_symbol;
|
||||||
int prev_code_len = DEFAULT_CODE_LENGTH;
|
int prev_code_len = DEFAULT_CODE_LENGTH;
|
||||||
HuffmanTree tree;
|
HuffmanTree tree;
|
||||||
|
int huff_codes[NUM_CODE_LENGTH_CODES] = { 0 };
|
||||||
|
|
||||||
if (!HuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
|
if (!VP8LHuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
|
||||||
NUM_CODE_LENGTH_CODES)) {
|
huff_codes, NUM_CODE_LENGTH_CODES)) {
|
||||||
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
|
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -232,11 +233,14 @@ static int ReadHuffmanCodeLengths(
|
|||||||
ok = 1;
|
ok = 1;
|
||||||
|
|
||||||
End:
|
End:
|
||||||
HuffmanTreeRelease(&tree);
|
VP8LHuffmanTreeFree(&tree);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
|
||||||
|
// tree.
|
||||||
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
||||||
|
int* const code_lengths, int* const huff_codes,
|
||||||
HuffmanTree* const tree) {
|
HuffmanTree* const tree) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
VP8LBitReader* const br = &dec->br_;
|
VP8LBitReader* const br = &dec->br_;
|
||||||
@ -245,7 +249,6 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
|||||||
if (simple_code) { // Read symbols, codes & code lengths directly.
|
if (simple_code) { // Read symbols, codes & code lengths directly.
|
||||||
int symbols[2];
|
int symbols[2];
|
||||||
int codes[2];
|
int codes[2];
|
||||||
int code_lengths[2];
|
|
||||||
const int num_symbols = VP8LReadBits(br, 1) + 1;
|
const int num_symbols = VP8LReadBits(br, 1) + 1;
|
||||||
const int first_symbol_len_code = VP8LReadBits(br, 1);
|
const int first_symbol_len_code = VP8LReadBits(br, 1);
|
||||||
// The first code is either 1 bit or 8 bit code.
|
// The first code is either 1 bit or 8 bit code.
|
||||||
@ -258,10 +261,9 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
|||||||
codes[1] = 1;
|
codes[1] = 1;
|
||||||
code_lengths[1] = num_symbols - 1;
|
code_lengths[1] = num_symbols - 1;
|
||||||
}
|
}
|
||||||
ok = HuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols,
|
ok = VP8LHuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols,
|
||||||
alphabet_size, num_symbols);
|
alphabet_size, num_symbols);
|
||||||
} else { // Decode Huffman-coded code lengths.
|
} else { // Decode Huffman-coded code lengths.
|
||||||
int* code_lengths = NULL;
|
|
||||||
int i;
|
int i;
|
||||||
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
|
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
|
||||||
const int num_codes = VP8LReadBits(br, 4) + 4;
|
const int num_codes = VP8LReadBits(br, 4) + 4;
|
||||||
@ -270,22 +272,15 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
code_lengths =
|
memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths));
|
||||||
(int*)WebPSafeCalloc((uint64_t)alphabet_size, sizeof(*code_lengths));
|
|
||||||
if (code_lengths == NULL) {
|
|
||||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < num_codes; ++i) {
|
for (i = 0; i < num_codes; ++i) {
|
||||||
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
|
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
|
||||||
}
|
}
|
||||||
ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
|
ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
|
||||||
code_lengths);
|
code_lengths);
|
||||||
if (ok) {
|
ok = ok && VP8LHuffmanTreeBuildImplicit(tree, code_lengths, huff_codes,
|
||||||
ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
|
alphabet_size);
|
||||||
}
|
|
||||||
WebPSafeFree(code_lengths);
|
|
||||||
}
|
}
|
||||||
ok = ok && !br->error_;
|
ok = ok && !br->error_;
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@ -295,19 +290,6 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DeleteHtreeGroups(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) {
|
|
||||||
HuffmanTreeRelease(&htrees[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WebPSafeFree(htree_groups);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
||||||
int color_cache_bits, int allow_recursion) {
|
int color_cache_bits, int allow_recursion) {
|
||||||
int i, j;
|
int i, j;
|
||||||
@ -316,6 +298,9 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
uint32_t* huffman_image = NULL;
|
uint32_t* huffman_image = NULL;
|
||||||
HTreeGroup* htree_groups = NULL;
|
HTreeGroup* htree_groups = NULL;
|
||||||
int num_htree_groups = 1;
|
int num_htree_groups = 1;
|
||||||
|
int max_alphabet_size = 0;
|
||||||
|
int* code_lengths = NULL;
|
||||||
|
int* huff_codes = NULL;
|
||||||
|
|
||||||
if (allow_recursion && VP8LReadBits(br, 1)) {
|
if (allow_recursion && VP8LReadBits(br, 1)) {
|
||||||
// use meta Huffman codes.
|
// use meta Huffman codes.
|
||||||
@ -341,11 +326,24 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
|
|
||||||
if (br->error_) goto Error;
|
if (br->error_) goto Error;
|
||||||
|
|
||||||
assert(num_htree_groups <= 0x10000);
|
// Find maximum alphabet size for the htree group.
|
||||||
htree_groups =
|
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||||
(HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups,
|
int alphabet_size = kAlphabetSize[j];
|
||||||
sizeof(*htree_groups));
|
if (j == 0 && color_cache_bits > 0) {
|
||||||
if (htree_groups == NULL) {
|
alphabet_size += 1 << color_cache_bits;
|
||||||
|
}
|
||||||
|
if (max_alphabet_size < alphabet_size) {
|
||||||
|
max_alphabet_size = alphabet_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
|
||||||
|
code_lengths =
|
||||||
|
(int*)WebPSafeCalloc((uint64_t)max_alphabet_size, sizeof(*code_lengths));
|
||||||
|
huff_codes =
|
||||||
|
(int*)WebPSafeMalloc((uint64_t)max_alphabet_size, sizeof(*huff_codes));
|
||||||
|
|
||||||
|
if (htree_groups == NULL || code_lengths == NULL || huff_codes == NULL) {
|
||||||
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
@ -354,12 +352,18 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
HuffmanTree* const htrees = htree_groups[i].htrees_;
|
HuffmanTree* const htrees = htree_groups[i].htrees_;
|
||||||
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
|
||||||
int alphabet_size = kAlphabetSize[j];
|
int alphabet_size = kAlphabetSize[j];
|
||||||
|
HuffmanTree* const htree = htrees + j;
|
||||||
if (j == 0 && color_cache_bits > 0) {
|
if (j == 0 && color_cache_bits > 0) {
|
||||||
alphabet_size += 1 << color_cache_bits;
|
alphabet_size += 1 << color_cache_bits;
|
||||||
}
|
}
|
||||||
if (!ReadHuffmanCode(alphabet_size, dec, htrees + j)) goto Error;
|
if (!ReadHuffmanCode(alphabet_size, dec, code_lengths, huff_codes,
|
||||||
|
htree)) {
|
||||||
|
goto Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
WebPSafeFree(huff_codes);
|
||||||
|
WebPSafeFree(code_lengths);
|
||||||
|
|
||||||
// All OK. Finalize pointers and return.
|
// All OK. Finalize pointers and return.
|
||||||
hdr->huffman_image_ = huffman_image;
|
hdr->huffman_image_ = huffman_image;
|
||||||
@ -368,8 +372,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
Error:
|
Error:
|
||||||
|
WebPSafeFree(huff_codes);
|
||||||
|
WebPSafeFree(code_lengths);
|
||||||
WebPSafeFree(huffman_image);
|
WebPSafeFree(huffman_image);
|
||||||
DeleteHtreeGroups(htree_groups, num_htree_groups);
|
VP8LHtreeGroupsFree(htree_groups, num_htree_groups);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1028,7 +1034,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
|
|||||||
assert(hdr);
|
assert(hdr);
|
||||||
|
|
||||||
WebPSafeFree(hdr->huffman_image_);
|
WebPSafeFree(hdr->huffman_image_);
|
||||||
DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_);
|
VP8LHtreeGroupsFree(hdr->htree_groups_, hdr->num_htree_groups_);
|
||||||
VP8LColorCacheClear(&hdr->color_cache_);
|
VP8LColorCacheClear(&hdr->color_cache_);
|
||||||
InitMetadata(hdr);
|
InitMetadata(hdr);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "../utils/bit_reader.h"
|
#include "../utils/bit_reader.h"
|
||||||
#include "../utils/color_cache.h"
|
#include "../utils/color_cache.h"
|
||||||
#include "../utils/huffman.h"
|
#include "../utils/huffman.h"
|
||||||
#include "../webp/format_constants.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -41,10 +40,6 @@ struct VP8LTransform {
|
|||||||
uint32_t *data_; // transform data.
|
uint32_t *data_; // transform data.
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
|
|
||||||
} HTreeGroup;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int color_cache_size_;
|
int color_cache_size_;
|
||||||
VP8LColorCache color_cache_;
|
VP8LColorCache color_cache_;
|
||||||
|
@ -22,6 +22,9 @@
|
|||||||
// (might be faster on some platform)
|
// (might be faster on some platform)
|
||||||
// #define USE_LUT_REVERSE_BITS
|
// #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)
|
#define NON_EXISTENT_SYMBOL (-1)
|
||||||
|
|
||||||
static void TreeNodeInit(HuffmanTreeNode* const node) {
|
static void TreeNodeInit(HuffmanTreeNode* const node) {
|
||||||
@ -46,17 +49,25 @@ static void AssignChildren(HuffmanTree* const tree,
|
|||||||
TreeNodeInit(children + 1);
|
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) {
|
static int TreeInit(HuffmanTree* const tree, int num_leaves) {
|
||||||
assert(tree != NULL);
|
assert(tree != NULL);
|
||||||
if (num_leaves == 0) return 0;
|
if (num_leaves == 0) return 0;
|
||||||
// We allocate maximum possible nodes in the tree at once.
|
tree->max_nodes_ = HuffmanTreeMaxNodes(num_leaves);
|
||||||
// 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;
|
|
||||||
assert(tree->max_nodes_ < (1 << 16)); // limit for the lut_jump_ table
|
assert(tree->max_nodes_ < (1 << 16)); // limit for the lut_jump_ table
|
||||||
tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_,
|
if (!HuffmanTreeAllocate(tree, tree->max_nodes_)) return 0;
|
||||||
sizeof(*tree->root_));
|
|
||||||
if (tree->root_ == NULL) return 0;
|
|
||||||
TreeNodeInit(tree->root_); // Initialize root.
|
TreeNodeInit(tree->root_); // Initialize root.
|
||||||
tree->num_nodes_ = 1;
|
tree->num_nodes_ = 1;
|
||||||
memset(tree->lut_bits_, 255, sizeof(tree->lut_bits_));
|
memset(tree->lut_bits_, 255, sizeof(tree->lut_bits_));
|
||||||
@ -64,7 +75,7 @@ static int TreeInit(HuffmanTree* const tree, int num_leaves) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HuffmanTreeRelease(HuffmanTree* const tree) {
|
void VP8LHuffmanTreeFree(HuffmanTree* const tree) {
|
||||||
if (tree != NULL) {
|
if (tree != NULL) {
|
||||||
WebPSafeFree(tree->root_);
|
WebPSafeFree(tree->root_);
|
||||||
tree->root_ = NULL;
|
tree->root_ = NULL;
|
||||||
@ -73,8 +84,32 @@ void HuffmanTreeRelease(HuffmanTree* const tree) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int HuffmanCodeLengthsToCodes(const int* const code_lengths,
|
HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups) {
|
||||||
int code_lengths_size, int* const huff_codes) {
|
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 symbol;
|
||||||
int code_len;
|
int code_len;
|
||||||
int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
|
int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
|
||||||
@ -193,8 +228,9 @@ static int TreeAddSymbol(HuffmanTree* const tree,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
|
int VP8LHuffmanTreeBuildImplicit(HuffmanTree* const tree,
|
||||||
const int* const code_lengths,
|
const int* const code_lengths,
|
||||||
|
int* const codes,
|
||||||
int code_lengths_size) {
|
int code_lengths_size) {
|
||||||
int symbol;
|
int symbol;
|
||||||
int num_symbols = 0;
|
int num_symbols = 0;
|
||||||
@ -219,47 +255,43 @@ int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
|
|||||||
if (num_symbols == 1) { // Trivial case.
|
if (num_symbols == 1) { // Trivial case.
|
||||||
const int max_symbol = code_lengths_size;
|
const int max_symbol = code_lengths_size;
|
||||||
if (root_symbol < 0 || root_symbol >= max_symbol) {
|
if (root_symbol < 0 || root_symbol >= max_symbol) {
|
||||||
HuffmanTreeRelease(tree);
|
VP8LHuffmanTreeFree(tree);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return TreeAddSymbol(tree, root_symbol, 0, 0);
|
return TreeAddSymbol(tree, root_symbol, 0, 0);
|
||||||
} else { // Normal case.
|
} else { // Normal case.
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
|
memset(codes, 0, code_lengths_size * sizeof(*codes));
|
||||||
|
|
||||||
// Get Huffman codes from the code lengths.
|
if (!VP8LHuffmanCodeLengthsToCodes(code_lengths, code_lengths_size,
|
||||||
int* const codes =
|
codes)) {
|
||||||
(int*)WebPSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes));
|
|
||||||
if (codes == NULL) goto End;
|
|
||||||
|
|
||||||
if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) {
|
|
||||||
goto End;
|
goto End;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add symbols one-by-one.
|
// Add symbols one-by-one.
|
||||||
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
|
||||||
if (code_lengths[symbol] > 0) {
|
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;
|
goto End;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ok = 1;
|
ok = 1;
|
||||||
End:
|
End:
|
||||||
WebPSafeFree(codes);
|
|
||||||
ok = ok && IsFull(tree);
|
ok = ok && IsFull(tree);
|
||||||
if (!ok) HuffmanTreeRelease(tree);
|
if (!ok) VP8LHuffmanTreeFree(tree);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
|
int VP8LHuffmanTreeBuildExplicit(HuffmanTree* const tree,
|
||||||
const int* const code_lengths,
|
const int* const code_lengths,
|
||||||
const int* const codes,
|
const int* const codes,
|
||||||
const int* const symbols, int max_symbol,
|
const int* const symbols, int max_symbol,
|
||||||
int num_symbols) {
|
int num_symbols) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(tree != NULL);
|
assert(tree != NULL);
|
||||||
assert(code_lengths != NULL);
|
assert(code_lengths != NULL);
|
||||||
assert(codes != NULL);
|
assert(codes != NULL);
|
||||||
@ -282,7 +314,6 @@ int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
|
|||||||
ok = 1;
|
ok = 1;
|
||||||
End:
|
End:
|
||||||
ok = ok && IsFull(tree);
|
ok = ok && IsFull(tree);
|
||||||
if (!ok) HuffmanTreeRelease(tree);
|
if (!ok) VP8LHuffmanTreeFree(tree);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define WEBP_UTILS_HUFFMAN_H_
|
#define WEBP_UTILS_HUFFMAN_H_
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include "../webp/format_constants.h"
|
||||||
#include "../webp/types.h"
|
#include "../webp/types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -42,6 +43,12 @@ struct HuffmanTree {
|
|||||||
int num_nodes_; // number of currently occupied nodes
|
int num_nodes_; // number of currently occupied nodes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Huffman Tree group.
|
||||||
|
typedef struct HTreeGroup HTreeGroup;
|
||||||
|
struct HTreeGroup {
|
||||||
|
HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
|
||||||
|
};
|
||||||
|
|
||||||
// Returns true if the given node is not a leaf of the Huffman tree.
|
// Returns true if the given node is not a leaf of the Huffman tree.
|
||||||
static WEBP_INLINE int HuffmanTreeNodeIsNotLeaf(
|
static WEBP_INLINE int HuffmanTreeNodeIsNotLeaf(
|
||||||
const HuffmanTreeNode* const node) {
|
const HuffmanTreeNode* const node) {
|
||||||
@ -56,18 +63,27 @@ static WEBP_INLINE const HuffmanTreeNode* HuffmanTreeNextNode(
|
|||||||
|
|
||||||
// Releases the nodes of the Huffman tree.
|
// Releases the nodes of the Huffman tree.
|
||||||
// Note: It does NOT free 'tree' itself.
|
// Note: It does NOT free 'tree' itself.
|
||||||
void HuffmanTreeRelease(HuffmanTree* const tree);
|
void VP8LHuffmanTreeFree(HuffmanTree* const tree);
|
||||||
|
|
||||||
|
// Creates the instance of HTreeGroup with specified number of tree-groups.
|
||||||
|
HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
|
||||||
|
|
||||||
|
// Releases the memory allocated for HTreeGroup.
|
||||||
|
void VP8LHtreeGroupsFree(HTreeGroup* htree_groups, int num_htree_groups);
|
||||||
|
|
||||||
// Builds Huffman tree assuming code lengths are implicitly in symbol order.
|
// Builds Huffman tree assuming code lengths are implicitly in symbol order.
|
||||||
|
// The 'huff_codes' and 'code_lengths' are pre-allocated temporary memory
|
||||||
|
// buffers, used for creating the huffman tree.
|
||||||
// Returns false in case of error (invalid tree or memory error).
|
// Returns false in case of error (invalid tree or memory error).
|
||||||
int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
|
int VP8LHuffmanTreeBuildImplicit(HuffmanTree* const tree,
|
||||||
const int* const code_lengths,
|
const int* const code_lengths,
|
||||||
|
int* const huff_codes,
|
||||||
int code_lengths_size);
|
int code_lengths_size);
|
||||||
|
|
||||||
// Build a Huffman tree with explicitly given lists of code lengths, codes
|
// Build a Huffman tree with explicitly given lists of code lengths, codes
|
||||||
// and symbols. Verifies that all symbols added are smaller than max_symbol.
|
// and symbols. Verifies that all symbols added are smaller than max_symbol.
|
||||||
// Returns false in case of an invalid symbol, invalid tree or memory error.
|
// Returns false in case of an invalid symbol, invalid tree or memory error.
|
||||||
int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
|
int VP8LHuffmanTreeBuildExplicit(HuffmanTree* const tree,
|
||||||
const int* const code_lengths,
|
const int* const code_lengths,
|
||||||
const int* const codes,
|
const int* const codes,
|
||||||
const int* const symbols, int max_symbol,
|
const int* const symbols, int max_symbol,
|
||||||
@ -76,10 +92,9 @@ int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
|
|||||||
// Utility: converts Huffman code lengths to corresponding Huffman codes.
|
// Utility: converts Huffman code lengths to corresponding Huffman codes.
|
||||||
// 'huff_codes' should be pre-allocated.
|
// 'huff_codes' should be pre-allocated.
|
||||||
// Returns false in case of error (memory allocation, invalid codes).
|
// Returns false in case of error (memory allocation, invalid codes).
|
||||||
int HuffmanCodeLengthsToCodes(const int* const code_lengths,
|
int VP8LHuffmanCodeLengthsToCodes(const int* const code_lengths,
|
||||||
int code_lengths_size, int* const huff_codes);
|
int code_lengths_size, int* const huff_codes);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user