cog/Frameworks/MPCDec/Files/src/huffman-bcl.c

281 lines
7.8 KiB
C
Executable File

/*************************************************************************
* Huffman codes generation, part of the code from the Basic Compression
* Library ( http://bcl.sourceforge.net )
*
* Modified by Nicolas BOTTI rududu at laposte.net
*
*-------------------------------------------------------------------------
* Copyright (c) 2003-2006 Marcus Geelnard
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would
* be appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
* Marcus Geelnard
* marcus.geelnard at home.se
*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int Symbol;
unsigned int Count;
unsigned int Code;
unsigned int Bits;
} huff_sym_t;
typedef struct huff_node huff_node_t;
struct huff_node {
huff_node_t * ChildA;
union {
huff_node_t * ChildB;
huff_sym_t * Symbol;
};
int Count;
};
static void _Huffman_StoreTree( huff_node_t *node, unsigned int bits )
{
/* Is this a leaf node? */
if( node->ChildA == 0 ) {
/* Store code info in symbol array */
node->Symbol->Bits = bits;
return;
}
/* Branch A */
_Huffman_StoreTree( node->ChildA, bits+1 );
/* Branch B */
_Huffman_StoreTree( node->ChildB, bits+1 );
}
/**
* Compare 2 symbols to sort as canonical huffman (more bits first)
* @param sym1
* @param sym2
* @return
*/
static int _Huffman_CompBits(const huff_sym_t * sym1, const huff_sym_t * sym2)
{
if (sym1->Bits == sym2->Bits){
if (sym1->Symbol == sym2->Symbol)
return 0;
else
return ((sym1->Symbol > sym2->Symbol) << 1) - 1;
} else
return ((sym1->Bits < sym2->Bits) << 1) - 1;
}
/**
* Compare 2 symbols to sort in symbol order
* @param sym1
* @param sym2
* @return
*/
static int _Huffman_CompSym(const huff_sym_t * sym1, const huff_sym_t * sym2)
{
return ((sym1->Symbol > sym2->Symbol) << 1) - 1;
}
/**
* Generate canonical huffman codes from symbols and bit lengths
* @param sym
* @param num_symbols
*/
static void _Huffman_MakeCodes(huff_sym_t * sym, unsigned int num_symbols)
{
unsigned int code = 0, i;
int bits;
qsort(sym, num_symbols, sizeof(huff_sym_t),
(int (*)(const void *, const void *)) _Huffman_CompBits);
bits = sym[0].Bits;
sym[0].Code = 0;
for( i = 1; i < num_symbols; i++){
code >>= bits - sym[i].Bits;
bits = sym[i].Bits;
code++;
sym[i].Code = code;
}
}
/**
* Make a canonical huffman tree from symbols and counts
* @param sym
* @param num_symbols
*/
void _Huffman_MakeTree( huff_sym_t * sym, unsigned int num_symbols)
{
huff_node_t * nodes, * node_1, * node_2, * root;
unsigned int k, nodes_left, next_idx;
nodes = malloc(sizeof(huff_node_t) * (num_symbols * 2 - 1));
/* Initialize all leaf nodes */
for( k = 0; k < num_symbols; ++ k ) {
nodes[k].Symbol = & sym[k];
nodes[k].Count = sym[k].Count;
nodes[k].ChildA = (huff_node_t *) 0;
}
/* Build tree by joining the lightest nodes until there is only
one node left (the root node). */
root = (huff_node_t *) 0;
nodes_left = num_symbols;
next_idx = num_symbols;
while( nodes_left > 1 ) {
/* Find the two lightest nodes */
node_1 = (huff_node_t *) 0;
node_2 = (huff_node_t *) 0;
for( k = 0; k < next_idx; ++ k ) {
if( nodes[k].Count >= 0 ) {
if( !node_1 || (nodes[k].Count <= node_1->Count) ) {
node_2 = node_1;
node_1 = &nodes[k];
} else if( !node_2 || (nodes[k].Count <= node_2->Count) )
node_2 = &nodes[k];
}
}
/* Join the two nodes into a new parent node */
root = &nodes[next_idx];
root->ChildA = node_1;
root->ChildB = node_2;
root->Count = node_1->Count + node_2->Count;
node_1->Count = -1;
node_2->Count = -1;
++ next_idx;
-- nodes_left;
}
/* Store the tree in the output stream, and in the sym[] array (the
latter is used as a look-up-table for faster encoding) */
if( root ) {
_Huffman_StoreTree( root, 0 );
} else {
/* Special case: only one symbol => no binary tree */
root = &nodes[0];
_Huffman_StoreTree( root, 1 );
}
free(nodes);
_Huffman_MakeCodes(sym, num_symbols);
}
#ifdef __GNUC__
/**
* Print the huffman tables
* print_type = 0 => print the coding table
* print_type = 1 => print the decoding table
* print_type = 2 => print the full codes in symbols order
* print_type = 3 => print the full codes in codes order
* @param sym
* @param num_symbols
* @param print_type
* @param offset
*/
void _Huffman_PrintCodes(huff_sym_t * sym, unsigned int num_symbols, int print_type, int offset)
{
unsigned int total_cnt = 0, total_size = 0, optim_size = 0, i;
int packs[4];
switch( print_type ) {
case 0 :
qsort(sym, num_symbols, sizeof(huff_sym_t),
(int (*)(const void *, const void *)) _Huffman_CompSym);
printf("{\n ");
for( i = 0; i < num_symbols; i++) {
if (i != 0)
printf(", ");
printf("{%u, %u}", sym[i].Code, sym[i].Bits);
}
printf("\n}\n");
break;
case 1:
qsort(sym, num_symbols, sizeof(huff_sym_t),
(int (*)(const void *, const void *)) _Huffman_CompBits);
printf("{\n ");
for( i = num_symbols - 1; i != ~0; i--) {
printf("{0x%.8x, %u, %i}", sym[i].Code << (32 - sym[i].Bits), sym[i].Bits, sym[i].Symbol - offset);
if (i != 0)
printf(", ");
}
printf("\n}\n");
break;
case 4:
qsort(sym, num_symbols, sizeof(huff_sym_t),
(int (*)(const void *, const void *)) _Huffman_CompBits);
printf("{\n ");
for( i = num_symbols - 1; i != ~0; i--) {
int symbol = sym[i].Symbol;
packs[3] = symbol / (offset * offset * offset);
packs[2] = (symbol - packs[3] * offset * offset * offset) / (offset * offset);
packs[1] = (symbol - (packs[3] * offset + packs[2]) * offset * offset) / offset;
packs[0] = symbol - ((packs[3] * offset + packs[2]) * offset + packs[1] * offset);
packs[0] -= offset >> 1;
packs[1] -= offset >> 1;
packs[2] -= offset >> 1;
packs[3] -= offset >> 1;
symbol = ((packs[3] & 15) << 12) | ((packs[2] & 15) << 8) | ((packs[1] & 15) << 4) | (packs[0] & 15);
printf("{0x%.8x, %u, %i}", sym[i].Code << (32 - sym[i].Bits), sym[i].Bits, symbol);
if (i != 0)
printf(", ");
}
printf("\n}\n");
break;
default:
if (print_type == 2)
qsort(sym, num_symbols, sizeof(huff_sym_t),
(int (*)(const void *, const void *)) _Huffman_CompSym);
else
qsort(sym, num_symbols, sizeof(huff_sym_t),
(int (*)(const void *, const void *)) _Huffman_CompBits);
printf("Symbol Count Lenth Code\n");
for( i = 0; i < num_symbols; i++) {
int k = sym[i].Bits - 1;
printf("%-10i %-10u %-10u ", sym[i].Symbol - offset, sym[i].Count, sym[i].Bits);
for (; k >= 0 ; k--)
printf("%u", (sym[i].Code >> k) & 1 );
printf("\n");
total_cnt += sym[i].Count;
total_size += sym[i].Count * sym[i].Bits;
if (sym[i].Count != 0)
optim_size += sym[i].Count * __builtin_log2(sym[i].Count);
}
optim_size = total_cnt * __builtin_log2(total_cnt) - optim_size;
printf("\ncount : %u huff : %f bps ", total_cnt, (float)total_size / total_cnt);
printf("opt : %f bps ", (float)optim_size / total_cnt);
printf("loss : %f bps (%f %%)\n", (float)(total_size - optim_size) / total_cnt, (float)(total_size - optim_size) * 100 / optim_size);
break;
}
}
#endif