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 #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;
} }

View File

@ -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.