• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <string.h>
5 
6 #define WROOT  5         /* fixed width (bits) of root table (MUST also be changed in the decoder C code) */
7 #define WMAX   7         /* max width of sub-table */
8 #define LAMBDA 512       /* Lagrange multiplier for MIPS/bytes trade-off: 1 table jump cost == LAMBDA bytes. Table cost = # of bytes + LAMBDA * # of jumps */
9 #define OPTIMIZE_SIZE 0  /* flag to force LAMBDA==0 (free jumps, table cost == table size) */
10 
11 #define MIN(a, b) ((a) < (b) ? (a) : (b))
12 #define MAX(a, b) ((a) > (b) ? (a) : (b))
13 
14 typedef struct huff_t
15 {
16     struct huff_t *link;
17     struct huff_t *parent;
18     struct huff_t *child[2];
19     int level;
20     unsigned symbol;
21     unsigned code;
22 
23     struct
24     {
25         int best_width, size;
26         float mips;
27     } dp;
28 
29     int backref;
30     int offset;
31 
32     enum { E_PAIR, E_QUAD } symbol_kind;
33 } huff_t;
34 
is_leaf(const huff_t * h)35 static int is_leaf(const huff_t *h)
36 {
37     return !h->child[0] && !h->child[1];
38 }
39 
imax(int a,int b)40 static int imax(int a, int b)
41 {
42     return MAX(a, b);
43 }
44 
BIT_str(unsigned x,int bits)45 static char *BIT_str(unsigned x, int bits)
46 {   // Print x as bitpattern: 01 (LBS bits)
47     static int idx;
48     static char buf[8][33]; // up to 8 simultaneous numbers
49     char *p = buf[++idx & 7];
50     while (bits--)
51     {
52         *p++ = "01"[(x >> bits) & 1];
53     }
54     *p++ = 0;
55     return buf[idx & 7];
56 }
57 
huff_create(huff_t * h,unsigned symbol,unsigned code,int code_len,int level,int symbol_kind)58 huff_t *huff_create(huff_t *h, unsigned symbol, unsigned code, int code_len, int level, int symbol_kind)
59 {
60     if (!h)
61     {
62         h = (huff_t*)calloc(1, sizeof(huff_t));
63         h->level = level;
64         h->symbol = code_len ? ~0 : symbol;
65         h->code = code_len ? ~0 : code;
66         h->dp.size = 1;
67         h->dp.mips = 1.f/(1 << level);
68         h->backref = -1;
69         h->symbol_kind = symbol_kind;
70     }
71     if (h && code_len > 0)
72     {
73         int bit = (code >> --code_len) & 1;
74         h->child[bit] = huff_create(h->child[bit], symbol, code, code_len, level + 1, symbol_kind);
75     }
76     return h;
77 }
78 
huff_free(huff_t * h)79 void huff_free(huff_t *h)
80 {
81     if (h)
82     {
83         huff_free(h->child[0]);
84         huff_free(h->child[1]);
85         free(h);
86     }
87 }
88 
read_codebook(int book)89 huff_t *read_codebook(int book)
90 {
91     FILE *f = fopen("HUFFCODE", "rt");
92     huff_t *tree = NULL;
93     int tab = -1, mx, my, lin;
94     do
95     {
96         if (4 != fscanf(f, "\n.table %d %d %d %d", &tab, &mx, &my, &lin))
97         {
98             fscanf(f, "%*[^\n]");
99         }
100     } while(tab != book && !feof(f));
101     if (tab == book)
102     {
103         int i, j;
104         for (i = 0; i < mx*my; i++)
105         {
106             int x, y, len, icode = 0;
107             char code[30];
108             if (book < 32)
109             {
110                 while (4 != fscanf(f, "\n%d %d %d %s", &x, &y, &len, code))
111                 {
112                     fscanf(f, "%*[^\n]");
113                 }
114             } else
115             {
116                 x = 0;
117                 while (3 != fscanf(f, "\n%d %d %s", &y, &len, code))
118                 {
119                     fscanf(f, "%*[^\n]");
120                 }
121             }
122             for (j = 0; j < len; j++)
123             {
124                 icode <<= 1;
125                 icode |= code[j] - '0';
126             }
127 
128             tree = huff_create(tree, (x << 16) + y, icode, len, 0, book < 32 ? E_PAIR : E_QUAD);
129         }
130     }
131     fclose(f);
132     return tree;
133 }
134 
huff_symbols_count(const huff_t * h)135 int huff_symbols_count(const huff_t *h)
136 {
137     return h ? is_leaf(h) + huff_symbols_count(h->child[0]) + huff_symbols_count(h->child[1]) : 0;
138 }
139 
huff_depth(const huff_t * h)140 int huff_depth(const huff_t *h)
141 {
142     return is_leaf(h) ? 0 : (1 + imax(huff_depth(h->child[0]), huff_depth(h->child[1])));
143 }
144 
huff_size(const huff_t * h,int depth)145 int huff_size(const huff_t *h, int depth)
146 {
147     return is_leaf(h) ? 0 : (--depth < 0) ? h->dp.size : huff_size(h->child[0], depth) + huff_size(h->child[1], depth);
148 }
149 
huff_cost(const huff_t * h,int depth)150 float huff_cost(const huff_t *h, int depth)
151 {
152     return is_leaf(h) ? 0 : (--depth < 0) ? h->dp.mips : huff_cost(h->child[0], depth) + huff_cost(h->child[1], depth);
153 }
154 
huff_decode(const huff_t * h,unsigned code,int code_len)155 const huff_t *huff_decode(const huff_t *h, unsigned code, int code_len)
156 {
157     return (!code_len || is_leaf(h)) ? h : huff_decode(h->child[(code >> (code_len - 1)) & 1], code, code_len - 1);
158 }
159 
huff_optimize_partition(huff_t * h)160 void huff_optimize_partition(huff_t *h)
161 {
162     int i, depth, wmin, wmax;
163     if (h && !is_leaf(h))
164     {
165         // DP call:
166         huff_optimize_partition(h->child[0]);
167         huff_optimize_partition(h->child[1]);
168         depth = huff_depth(h);
169 
170         wmin = h->level ? 1 : WROOT;
171         wmax = wmin > 1 ? wmin : MIN(depth, WMAX);
172 
173         if (h->symbol_kind == E_QUAD && !h->level)
174         {
175             wmax = wmin = 4;
176         }
177 
178         h->dp.size = huff_size(h, h->dp.best_width = wmin) + (1 << wmin);
179         h->dp.mips = huff_cost(h, h->dp.best_width = wmin) + 1.f/(1 << h->level);
180 
181         for (i = wmin + 1; i <= wmax; i++)
182         {
183             int size = huff_size(h, i) + (1 << i);
184             float mips = huff_cost(h, i) + 1.f/(1 << h->level);
185             float cost_i;
186             float cost_have;
187 
188             cost_i = mips*LAMBDA + size;
189             cost_have = h->dp.mips*LAMBDA + h->dp.size;
190 #if OPTIMIZE_SIZE
191             cost_i = (float)size;
192             cost_have = (float)h->dp.size;
193 #endif
194 
195             if (cost_i < cost_have)
196             {
197                 h->dp.best_width = i;
198                 h->dp.size = size;
199                 h->dp.mips = mips;
200             }
201         }
202     }
203 }
204 
huff_print_one(const huff_t * h,FILE * f,int parent_level,int last)205 void huff_print_one(const huff_t *h, FILE *f, int parent_level, int last)
206 {
207     if (h->symbol_kind == E_PAIR)
208     {
209         if (is_leaf(h))
210         {
211             int x = h->symbol << 16 >> 16;
212             int y = h->symbol <<  0 >> 16;
213             fprintf(f, last ? "%d" : "%d,", ((h->level - parent_level)*256 + (x << 4) + (y << 0)));
214         } else
215         {
216             assert(h->offset < (1 << 13));
217             assert(h->offset);
218             fprintf(f, last ? "%d" : "%d,", (-h->offset << 3) | h->dp.best_width);
219         }
220     } else
221     {
222         if (is_leaf(h))
223         {
224             fprintf(f, last ? "%d" : "%d,", (h->symbol*16 + 8 + h->level));
225         } else
226         {
227             fprintf(f, last ? "%d" : "%d,", (h->offset << 3) | h->dp.best_width);
228         }
229     }
230 }
231 
huff_set_links_bfs(huff_t * h,FILE * f)232 void huff_set_links_bfs(huff_t *h, FILE *f)
233 {
234     int print_flag;
235     for (print_flag = 0; print_flag <= 1; print_flag++)
236     {
237         huff_t *q = h;
238         huff_t *queue_head = NULL;
239         huff_t **queue_tail = &queue_head;
240         int offs = 0;
241         while (q)
242         {
243             int i, w = 1 << q->dp.best_width;
244             for (i = 0; i < w; i++)
245             {
246                 huff_t *r = (huff_t *)huff_decode(q, i, q->dp.best_width);
247                 if (print_flag)
248                 {
249                     huff_print_one(r, f, q->level, 0);
250                 }
251 
252                 if (!is_leaf(r))
253                 {
254                     r->backref = offs;// + i;
255                     *queue_tail = r;
256                     queue_tail = &r->link;
257                 }
258             }
259             offs += w;
260             q = queue_head;
261             if (q)
262             {
263                 if ((queue_head = q->link) != NULL)
264                 {
265                     queue_tail = &queue_head;
266                 }
267                 q->offset = offs;// - q->backref;
268             }
269         }
270     }
271 }
272 
huff_set_links_dfs_recursion(huff_t * h,FILE * f,int print_flag,int * off)273 void huff_set_links_dfs_recursion(huff_t *h, FILE *f, int print_flag, int *off)
274 {
275     int i, w = 1 << h->dp.best_width;
276     h->offset = *off;
277     *off += w;
278     for (i = 0; print_flag && i < w; i++)
279     {
280         huff_print_one(huff_decode(h, i, h->dp.best_width), f, h->level, (i + 1) == w);
281     }
282     for (i = 0; i < w; i++)
283     {
284         huff_t *q = (huff_t *)huff_decode(h, i, h->dp.best_width);
285         if (!is_leaf(q))
286         {
287             if (print_flag)
288                 fprintf(f, ",");
289             huff_set_links_dfs_recursion(q, f, print_flag, off);
290         }
291     }
292 }
293 
huff_set_links_dfs(huff_t * h,FILE * f)294 void huff_set_links_dfs(huff_t *h, FILE *f)
295 {
296     int off = 0;
297     huff_set_links_dfs_recursion(h, f, 0, &off);
298     huff_set_links_dfs_recursion(h, f, 1, &off);
299 };
300 
main()301 int main()
302 {
303     int i;
304     const int tabn[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,24,32,33 };
305     int total_size = 0;
306     int entry_bits[32];
307 
308     FILE *dst_file = fopen("Huffman_tree.inl", "wt");
309 
310     for (i = 0; i < sizeof(tabn)/sizeof(tabn[0]); i++)
311     {
312         huff_t *h = read_codebook(tabn[i]);
313         huff_optimize_partition(h);
314 
315         printf("\ntable %2d ", tabn[i]);
316         printf("%3d symbols ", huff_symbols_count(h));
317         printf("%3d items ", h ? h->dp.size : 0);
318         printf("%1d entry ", h ? h->dp.best_width : 0);
319         printf("%f average memory reads ", h ? h->dp.mips : 0);
320         total_size += h ? h->dp.size : 0;
321 
322         fprintf(dst_file, "    static const %s tab%d[] = { ", tabn[i] < 32 ? "int16_t" : "uint8_t", tabn[i]);
323         if (h)
324         {
325             //huff_set_links_bfs(h, dst_file);
326             huff_set_links_dfs(h, dst_file);
327             entry_bits[i] = h->dp.best_width;
328         } else
329         {
330             fprintf(dst_file, "0");
331             entry_bits[i] = 0;
332         }
333         fprintf(dst_file, " };\n");
334         huff_free(h);
335     }
336 #if WROOT > 1
337     fprintf(dst_file, "#define HUFF_ENTRY_BITS %d\n", WROOT);
338 #else
339     fprintf(dst_file, "#define HUFF_ENTRY_BITS 0\n");
340     fprintf(dst_file, "    static const uint8_t g_entry_bits[] = { ");
341     for (i = 0; i < sizeof(tabn)/sizeof(tabn[0]); i++)
342     {
343         fprintf(dst_file, "%d,", entry_bits[i]);
344     }
345     fprintf(dst_file, " };\n", i);
346 #endif
347     fclose(dst_file);
348     printf("\n// Total: %d items\n", total_size);
349 }
350