mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 22:28:22 +01:00
Merge "Some cleanup in VP8LCreateHuffmanTree() (and related functions CompareHuffmanTrees() and SetBitDepths()): - Move 'tree_size' initialization and malloc for 'tree + tree_pool' outside the loop. - Some renames/tweaks for readability."
This commit is contained in:
commit
de2fe20290
@ -12,7 +12,7 @@
|
|||||||
#ifdef USE_LOSSLESS_ENCODER
|
#ifdef USE_LOSSLESS_ENCODER
|
||||||
|
|
||||||
#include "./huffman_encode.h"
|
#include "./huffman_encode.h"
|
||||||
|
#include <assert.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -24,34 +24,34 @@ typedef struct {
|
|||||||
int pool_index_right_;
|
int pool_index_right_;
|
||||||
} HuffmanTree;
|
} HuffmanTree;
|
||||||
|
|
||||||
// Sort the root nodes, most popular first.
|
// A comparer function for two Huffman trees: sorts first by 'total count'
|
||||||
static int CompHuffmanTree(const void* vp0, const void* vp1) {
|
// (more comes first), and then by 'value' (more comes first).
|
||||||
const HuffmanTree* v0 = (const HuffmanTree*)vp0;
|
static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) {
|
||||||
const HuffmanTree* v1 = (const HuffmanTree*)vp1;
|
const HuffmanTree* const t1 = (const HuffmanTree*)ptr1;
|
||||||
if (v0->total_count_ > v1->total_count_) {
|
const HuffmanTree* const t2 = (const HuffmanTree*)ptr2;
|
||||||
|
if (t1->total_count_ > t2->total_count_) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (v0->total_count_ < v1->total_count_) {
|
} else if (t1->total_count_ < t2->total_count_) {
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
if (v0->value_ < v1->value_) {
|
if (t1->value_ < t2->value_) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (v0->value_ > v1->value_) {
|
if (t1->value_ > t2->value_) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetDepth(const HuffmanTree* p,
|
static void SetBitDepths(const HuffmanTree* const tree,
|
||||||
HuffmanTree* pool,
|
const HuffmanTree* const pool,
|
||||||
uint8_t* depth,
|
uint8_t* const bit_depths, int level) {
|
||||||
const int level) {
|
if (tree->pool_index_left_ >= 0) {
|
||||||
if (p->pool_index_left_ >= 0) {
|
SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1);
|
||||||
SetDepth(&pool[p->pool_index_left_], pool, depth, level + 1);
|
SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1);
|
||||||
SetDepth(&pool[p->pool_index_right_], pool, depth, level + 1);
|
|
||||||
} else {
|
} else {
|
||||||
depth[p->value_] = level;
|
bit_depths[tree->value_] = level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,64 +71,66 @@ static void SetDepth(const HuffmanTree* p,
|
|||||||
//
|
//
|
||||||
// See http://en.wikipedia.org/wiki/Huffman_coding
|
// See http://en.wikipedia.org/wiki/Huffman_coding
|
||||||
int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
|
int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
|
||||||
int tree_depth_limit,
|
int tree_depth_limit, uint8_t* const bit_depths) {
|
||||||
uint8_t* const bit_depths) {
|
int count_min;
|
||||||
HuffmanTree* tree;
|
|
||||||
HuffmanTree* tree_pool;
|
HuffmanTree* tree_pool;
|
||||||
int tree_pool_size;
|
HuffmanTree* tree;
|
||||||
// For block sizes with less than 64k symbols we never need to do a
|
int tree_size_orig = 0;
|
||||||
// second iteration of this loop.
|
|
||||||
// If we actually start running inside this loop a lot, we would perhaps
|
|
||||||
// be better off with the Katajainen algorithm.
|
|
||||||
int count_limit;
|
|
||||||
for (count_limit = 1; ; count_limit *= 2) {
|
|
||||||
int tree_size = 0;
|
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < histogram_size; ++i) {
|
for (i = 0; i < histogram_size; ++i) {
|
||||||
if (histogram[i]) {
|
if (histogram[i] != 0) {
|
||||||
++tree_size;
|
++tree_size_orig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 3 * tree_size is enough to cover all the nodes representing a
|
// 3 * tree_size is enough to cover all the nodes representing a
|
||||||
// population and all the inserted nodes combining two existing nodes.
|
// population and all the inserted nodes combining two existing nodes.
|
||||||
// The tree pool needs 2 * (tree_size - 1) entities, and the
|
// The tree pool needs 2 * (tree_size_orig - 1) entities, and the
|
||||||
// tree needs exactly tree_size entities.
|
// tree needs exactly tree_size_orig entities.
|
||||||
tree = (HuffmanTree*)malloc(3 * tree_size * sizeof(*tree));
|
tree = (HuffmanTree*)malloc(3 * tree_size_orig * sizeof(*tree));
|
||||||
if (tree == NULL) {
|
if (tree == NULL) return 0;
|
||||||
return 0;
|
tree_pool = tree + tree_size_orig;
|
||||||
}
|
|
||||||
|
|
||||||
|
// For block sizes with less than 64k symbols we never need to do a
|
||||||
|
// second iteration of this loop.
|
||||||
|
// If we actually start running inside this loop a lot, we would perhaps
|
||||||
|
// be better off with the Katajainen algorithm.
|
||||||
|
assert(tree_size_orig <= (1 << (tree_depth_limit - 1)));
|
||||||
|
for (count_min = 1; ; count_min *= 2) {
|
||||||
|
int tree_size = tree_size_orig;
|
||||||
{
|
{
|
||||||
int j = 0;
|
// We need to pack the Huffman tree in tree_depth_limit bits.
|
||||||
int i;
|
// So, we try by faking histogram entries to be at least 'count_min'.
|
||||||
for (i = 0; i < histogram_size; ++i) {
|
int idx = 0;
|
||||||
if (histogram[i]) {
|
int j;
|
||||||
|
for (j = 0; j < histogram_size; ++j) {
|
||||||
|
if (histogram[j] != 0) {
|
||||||
const int count =
|
const int count =
|
||||||
(histogram[i] < count_limit) ? count_limit : histogram[i];
|
(histogram[j] < count_min) ? count_min : histogram[j];
|
||||||
tree[j].total_count_ = count;
|
tree[idx].total_count_ = count;
|
||||||
tree[j].value_ = i;
|
tree[idx].value_ = j;
|
||||||
tree[j].pool_index_left_ = -1;
|
tree[idx].pool_index_left_ = -1;
|
||||||
tree[j].pool_index_right_ = -1;
|
tree[idx].pool_index_right_ = -1;
|
||||||
++j;
|
++idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qsort((void*)tree, tree_size, sizeof(*tree), CompHuffmanTree);
|
|
||||||
tree_pool = tree + tree_size;
|
// Build the Huffman tree.
|
||||||
tree_pool_size = 0;
|
qsort((void*)tree, tree_size, sizeof(*tree), CompareHuffmanTrees);
|
||||||
if (tree_size >= 2) {
|
|
||||||
while (tree_size >= 2) { // Finish when we have only one root.
|
if (tree_size > 1) { // Normal case.
|
||||||
|
int tree_pool_size = 0;
|
||||||
|
while (tree_size > 1) { // Finish when we have only one root.
|
||||||
int count;
|
int count;
|
||||||
tree_pool[tree_pool_size] = tree[tree_size - 1];
|
tree_pool[tree_pool_size++] = tree[tree_size - 1];
|
||||||
++tree_pool_size;
|
tree_pool[tree_pool_size++] = tree[tree_size - 2];
|
||||||
tree_pool[tree_pool_size] = tree[tree_size - 2];
|
count = tree_pool[tree_pool_size - 1].total_count_ +
|
||||||
++tree_pool_size;
|
|
||||||
count =
|
|
||||||
tree_pool[tree_pool_size - 1].total_count_ +
|
|
||||||
tree_pool[tree_pool_size - 2].total_count_;
|
tree_pool[tree_pool_size - 2].total_count_;
|
||||||
tree_size -= 2;
|
tree_size -= 2;
|
||||||
{
|
{
|
||||||
int k = 0;
|
|
||||||
// Search for the insertion point.
|
// Search for the insertion point.
|
||||||
|
int k;
|
||||||
for (k = 0; k < tree_size; ++k) {
|
for (k = 0; k < tree_size; ++k) {
|
||||||
if (tree[k].total_count_ <= count) {
|
if (tree[k].total_count_ <= count) {
|
||||||
break;
|
break;
|
||||||
@ -143,18 +145,13 @@ int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
|
|||||||
tree_size = tree_size + 1;
|
tree_size = tree_size + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetDepth(&tree[0], tree_pool, bit_depths, 0);
|
SetBitDepths(&tree[0], tree_pool, bit_depths, 0);
|
||||||
} else {
|
} else if (tree_size == 1) { // Trivial case: only one element.
|
||||||
if (tree_size == 1) {
|
|
||||||
// Only one element.
|
|
||||||
bit_depths[tree[0].value_] = 1;
|
bit_depths[tree[0].value_] = 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
free(tree);
|
|
||||||
// We need to pack the Huffman tree in tree_depth_limit bits.
|
|
||||||
// If this was not successful, add fake entities to the lowest values
|
|
||||||
// and retry.
|
|
||||||
{
|
{
|
||||||
|
// Test if this Huffman tree satisfies our 'tree_depth_limit' criteria.
|
||||||
int max_depth = bit_depths[0];
|
int max_depth = bit_depths[0];
|
||||||
int j;
|
int j;
|
||||||
for (j = 1; j < histogram_size; ++j) {
|
for (j = 1; j < histogram_size; ++j) {
|
||||||
@ -167,6 +164,7 @@ int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(tree);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,17 +22,14 @@ extern "C" {
|
|||||||
|
|
||||||
// This function will create a Huffman tree.
|
// This function will create a Huffman tree.
|
||||||
//
|
//
|
||||||
// The (data,length) contains the population counts.
|
// 'histogram' contains the population counts.
|
||||||
// The tree_limit is the maximum bit depth of the Huffman codes.
|
// 'tree_depth_limit' is the maximum bit depth of the Huffman codes.
|
||||||
//
|
// The created tree is returned as 'bit_depths', which stores how many bits are
|
||||||
// The depth contains the tree, i.e., how many bits are used for
|
// used for each symbol.
|
||||||
// the symbol.
|
|
||||||
//
|
|
||||||
// See http://en.wikipedia.org/wiki/Huffman_coding
|
// See http://en.wikipedia.org/wiki/Huffman_coding
|
||||||
//
|
// Returns 0 on memory error.
|
||||||
// Returns 0 when an error has occured.
|
int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
|
||||||
int VP8LCreateHuffmanTree(const int* data, const int length,
|
int tree_depth_limit, uint8_t* const bit_depths);
|
||||||
const int tree_limit, uint8_t* depth);
|
|
||||||
|
|
||||||
// Write a huffman tree from bit depths. The generated Huffman tree is
|
// Write a huffman tree from bit depths. The generated Huffman tree is
|
||||||
// compressed once more using a Huffman tree.
|
// compressed once more using a Huffman tree.
|
||||||
|
Loading…
Reference in New Issue
Block a user