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:
pascal massimino 2012-05-09 02:15:42 -07:00 committed by Gerrit Code Review
commit de2fe20290
2 changed files with 72 additions and 77 deletions

View File

@ -12,7 +12,7 @@
#ifdef USE_LOSSLESS_ENCODER
#include "./huffman_encode.h"
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@ -24,34 +24,34 @@ typedef struct {
int pool_index_right_;
} HuffmanTree;
// Sort the root nodes, most popular first.
static int CompHuffmanTree(const void* vp0, const void* vp1) {
const HuffmanTree* v0 = (const HuffmanTree*)vp0;
const HuffmanTree* v1 = (const HuffmanTree*)vp1;
if (v0->total_count_ > v1->total_count_) {
// A comparer function for two Huffman trees: sorts first by 'total count'
// (more comes first), and then by 'value' (more comes first).
static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) {
const HuffmanTree* const t1 = (const HuffmanTree*)ptr1;
const HuffmanTree* const t2 = (const HuffmanTree*)ptr2;
if (t1->total_count_ > t2->total_count_) {
return -1;
} else if (v0->total_count_ < v1->total_count_) {
} else if (t1->total_count_ < t2->total_count_) {
return 1;
} else {
if (v0->value_ < v1->value_) {
if (t1->value_ < t2->value_) {
return -1;
}
if (v0->value_ > v1->value_) {
if (t1->value_ > t2->value_) {
return 1;
}
return 0;
}
}
static void SetDepth(const HuffmanTree* p,
HuffmanTree* pool,
uint8_t* depth,
const int level) {
if (p->pool_index_left_ >= 0) {
SetDepth(&pool[p->pool_index_left_], pool, depth, level + 1);
SetDepth(&pool[p->pool_index_right_], pool, depth, level + 1);
static void SetBitDepths(const HuffmanTree* const tree,
const HuffmanTree* const pool,
uint8_t* const bit_depths, int level) {
if (tree->pool_index_left_ >= 0) {
SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1);
SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1);
} 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
int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
int tree_depth_limit,
uint8_t* const bit_depths) {
HuffmanTree* tree;
int tree_depth_limit, uint8_t* const bit_depths) {
int count_min;
HuffmanTree* tree_pool;
int tree_pool_size;
// 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.
int count_limit;
for (count_limit = 1; ; count_limit *= 2) {
int tree_size = 0;
HuffmanTree* tree;
int tree_size_orig = 0;
int i;
for (i = 0; i < histogram_size; ++i) {
if (histogram[i]) {
++tree_size;
if (histogram[i] != 0) {
++tree_size_orig;
}
}
// 3 * tree_size is enough to cover all the nodes representing a
// population and all the inserted nodes combining two existing nodes.
// The tree pool needs 2 * (tree_size - 1) entities, and the
// tree needs exactly tree_size entities.
tree = (HuffmanTree*)malloc(3 * tree_size * sizeof(*tree));
if (tree == NULL) {
return 0;
}
// The tree pool needs 2 * (tree_size_orig - 1) entities, and the
// tree needs exactly tree_size_orig entities.
tree = (HuffmanTree*)malloc(3 * tree_size_orig * sizeof(*tree));
if (tree == NULL) 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;
int i;
for (i = 0; i < histogram_size; ++i) {
if (histogram[i]) {
// We need to pack the Huffman tree in tree_depth_limit bits.
// So, we try by faking histogram entries to be at least 'count_min'.
int idx = 0;
int j;
for (j = 0; j < histogram_size; ++j) {
if (histogram[j] != 0) {
const int count =
(histogram[i] < count_limit) ? count_limit : histogram[i];
tree[j].total_count_ = count;
tree[j].value_ = i;
tree[j].pool_index_left_ = -1;
tree[j].pool_index_right_ = -1;
++j;
(histogram[j] < count_min) ? count_min : histogram[j];
tree[idx].total_count_ = count;
tree[idx].value_ = j;
tree[idx].pool_index_left_ = -1;
tree[idx].pool_index_right_ = -1;
++idx;
}
}
}
qsort((void*)tree, tree_size, sizeof(*tree), CompHuffmanTree);
tree_pool = tree + tree_size;
tree_pool_size = 0;
if (tree_size >= 2) {
while (tree_size >= 2) { // Finish when we have only one root.
// Build the Huffman tree.
qsort((void*)tree, tree_size, sizeof(*tree), CompareHuffmanTrees);
if (tree_size > 1) { // Normal case.
int tree_pool_size = 0;
while (tree_size > 1) { // Finish when we have only one root.
int count;
tree_pool[tree_pool_size] = tree[tree_size - 1];
++tree_pool_size;
tree_pool[tree_pool_size] = tree[tree_size - 2];
++tree_pool_size;
count =
tree_pool[tree_pool_size - 1].total_count_ +
tree_pool[tree_pool_size++] = tree[tree_size - 1];
tree_pool[tree_pool_size++] = tree[tree_size - 2];
count = tree_pool[tree_pool_size - 1].total_count_ +
tree_pool[tree_pool_size - 2].total_count_;
tree_size -= 2;
{
int k = 0;
// Search for the insertion point.
int k;
for (k = 0; k < tree_size; ++k) {
if (tree[k].total_count_ <= count) {
break;
@ -143,18 +145,13 @@ int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
tree_size = tree_size + 1;
}
}
SetDepth(&tree[0], tree_pool, bit_depths, 0);
} else {
if (tree_size == 1) {
// Only one element.
SetBitDepths(&tree[0], tree_pool, bit_depths, 0);
} else if (tree_size == 1) { // Trivial case: only one element.
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 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;
}

View File

@ -22,17 +22,14 @@ extern "C" {
// This function will create a Huffman tree.
//
// The (data,length) contains the population counts.
// The tree_limit is the maximum bit depth of the Huffman codes.
//
// The depth contains the tree, i.e., how many bits are used for
// the symbol.
//
// 'histogram' contains the population counts.
// '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
// used for each symbol.
// See http://en.wikipedia.org/wiki/Huffman_coding
//
// Returns 0 when an error has occured.
int VP8LCreateHuffmanTree(const int* data, const int length,
const int tree_limit, uint8_t* depth);
// Returns 0 on memory error.
int VP8LCreateHuffmanTree(const int* const histogram, int histogram_size,
int tree_depth_limit, uint8_t* const bit_depths);
// Write a huffman tree from bit depths. The generated Huffman tree is
// compressed once more using a Huffman tree.