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