OLD | NEW |
1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
2 // | 2 // |
3 // Use of this source code is governed by a BSD-style license | 3 // Use of this source code is governed by a BSD-style license |
4 // that can be found in the COPYING file in the root of the source | 4 // that can be found in the COPYING file in the root of the source |
5 // tree. An additional intellectual property rights grant can be found | 5 // tree. An additional intellectual property rights grant can be found |
6 // in the file PATENTS. All contributing project authors may | 6 // in the file PATENTS. All contributing project authors may |
7 // be found in the AUTHORS file in the root of the source tree. | 7 // be found in the AUTHORS file in the root of the source tree. |
8 // ----------------------------------------------------------------------------- | 8 // ----------------------------------------------------------------------------- |
9 // | 9 // |
10 // Utilities for building and looking up Huffman trees. | 10 // Utilities for building and looking up Huffman trees. |
11 // | 11 // |
12 // Author: Urvang Joshi (urvang@google.com) | 12 // Author: Urvang Joshi (urvang@google.com) |
13 | 13 |
14 #include <assert.h> | 14 #include <assert.h> |
15 #include <stdlib.h> | 15 #include <stdlib.h> |
| 16 #include <string.h> |
16 #include "./huffman.h" | 17 #include "./huffman.h" |
17 #include "../utils/utils.h" | 18 #include "../utils/utils.h" |
18 #include "../webp/format_constants.h" | 19 #include "../webp/format_constants.h" |
19 | 20 |
20 #if defined(__cplusplus) || defined(c_plusplus) | 21 // Uncomment the following to use look-up table for ReverseBits() |
21 extern "C" { | 22 // (might be faster on some platform) |
22 #endif | 23 // #define USE_LUT_REVERSE_BITS |
23 | 24 |
24 #define NON_EXISTENT_SYMBOL (-1) | 25 #define NON_EXISTENT_SYMBOL (-1) |
25 | 26 |
26 static void TreeNodeInit(HuffmanTreeNode* const node) { | 27 static void TreeNodeInit(HuffmanTreeNode* const node) { |
27 node->children_ = -1; // means: 'unassigned so far' | 28 node->children_ = -1; // means: 'unassigned so far' |
28 } | 29 } |
29 | 30 |
30 static int NodeIsEmpty(const HuffmanTreeNode* const node) { | 31 static int NodeIsEmpty(const HuffmanTreeNode* const node) { |
31 return (node->children_ < 0); | 32 return (node->children_ < 0); |
32 } | 33 } |
(...skipping 12 matching lines...) Expand all Loading... |
45 TreeNodeInit(children + 1); | 46 TreeNodeInit(children + 1); |
46 } | 47 } |
47 | 48 |
48 static int TreeInit(HuffmanTree* const tree, int num_leaves) { | 49 static int TreeInit(HuffmanTree* const tree, int num_leaves) { |
49 assert(tree != NULL); | 50 assert(tree != NULL); |
50 if (num_leaves == 0) return 0; | 51 if (num_leaves == 0) return 0; |
51 // We allocate maximum possible nodes in the tree at once. | 52 // We allocate maximum possible nodes in the tree at once. |
52 // Note that a Huffman tree is a full binary tree; and in a full binary tree | 53 // Note that a Huffman tree is a full binary tree; and in a full binary tree |
53 // with L leaves, the total number of nodes N = 2 * L - 1. | 54 // with L leaves, the total number of nodes N = 2 * L - 1. |
54 tree->max_nodes_ = 2 * num_leaves - 1; | 55 tree->max_nodes_ = 2 * num_leaves - 1; |
| 56 assert(tree->max_nodes_ < (1 << 16)); // limit for the lut_jump_ table |
55 tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_, | 57 tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_, |
56 sizeof(*tree->root_)); | 58 sizeof(*tree->root_)); |
57 if (tree->root_ == NULL) return 0; | 59 if (tree->root_ == NULL) return 0; |
58 TreeNodeInit(tree->root_); // Initialize root. | 60 TreeNodeInit(tree->root_); // Initialize root. |
59 tree->num_nodes_ = 1; | 61 tree->num_nodes_ = 1; |
| 62 memset(tree->lut_bits_, 255, sizeof(tree->lut_bits_)); |
| 63 memset(tree->lut_jump_, 0, sizeof(tree->lut_jump_)); |
60 return 1; | 64 return 1; |
61 } | 65 } |
62 | 66 |
63 void HuffmanTreeRelease(HuffmanTree* const tree) { | 67 void HuffmanTreeRelease(HuffmanTree* const tree) { |
64 if (tree != NULL) { | 68 if (tree != NULL) { |
65 free(tree->root_); | 69 free(tree->root_); |
66 tree->root_ = NULL; | 70 tree->root_ = NULL; |
67 tree->max_nodes_ = 0; | 71 tree->max_nodes_ = 0; |
68 tree->num_nodes_ = 0; | 72 tree->num_nodes_ = 0; |
69 } | 73 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 for (symbol = 0; symbol < code_lengths_size; ++symbol) { | 114 for (symbol = 0; symbol < code_lengths_size; ++symbol) { |
111 if (code_lengths[symbol] > 0) { | 115 if (code_lengths[symbol] > 0) { |
112 huff_codes[symbol] = next_codes[code_lengths[symbol]]++; | 116 huff_codes[symbol] = next_codes[code_lengths[symbol]]++; |
113 } else { | 117 } else { |
114 huff_codes[symbol] = NON_EXISTENT_SYMBOL; | 118 huff_codes[symbol] = NON_EXISTENT_SYMBOL; |
115 } | 119 } |
116 } | 120 } |
117 return 1; | 121 return 1; |
118 } | 122 } |
119 | 123 |
| 124 #ifndef USE_LUT_REVERSE_BITS |
| 125 |
| 126 static int ReverseBitsShort(int bits, int num_bits) { |
| 127 int retval = 0; |
| 128 int i; |
| 129 assert(num_bits <= 8); // Not a hard requirement, just for coherency. |
| 130 for (i = 0; i < num_bits; ++i) { |
| 131 retval <<= 1; |
| 132 retval |= bits & 1; |
| 133 bits >>= 1; |
| 134 } |
| 135 return retval; |
| 136 } |
| 137 |
| 138 #else |
| 139 |
| 140 static const uint8_t kReversedBits[16] = { // Pre-reversed 4-bit values. |
| 141 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, |
| 142 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf |
| 143 }; |
| 144 |
| 145 static int ReverseBitsShort(int bits, int num_bits) { |
| 146 const uint8_t v = (kReversedBits[bits & 0xf] << 4) | kReversedBits[bits >> 4]; |
| 147 assert(num_bits <= 8); |
| 148 return v >> (8 - num_bits); |
| 149 } |
| 150 |
| 151 #endif |
| 152 |
120 static int TreeAddSymbol(HuffmanTree* const tree, | 153 static int TreeAddSymbol(HuffmanTree* const tree, |
121 int symbol, int code, int code_length) { | 154 int symbol, int code, int code_length) { |
| 155 int step = HUFF_LUT_BITS; |
| 156 int base_code; |
122 HuffmanTreeNode* node = tree->root_; | 157 HuffmanTreeNode* node = tree->root_; |
123 const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_; | 158 const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_; |
| 159 assert(symbol == (int16_t)symbol); |
| 160 if (code_length <= HUFF_LUT_BITS) { |
| 161 int i; |
| 162 base_code = ReverseBitsShort(code, code_length); |
| 163 for (i = 0; i < (1 << (HUFF_LUT_BITS - code_length)); ++i) { |
| 164 const int idx = base_code | (i << code_length); |
| 165 tree->lut_symbol_[idx] = (int16_t)symbol; |
| 166 tree->lut_bits_[idx] = code_length; |
| 167 } |
| 168 } else { |
| 169 base_code = ReverseBitsShort((code >> (code_length - HUFF_LUT_BITS)), |
| 170 HUFF_LUT_BITS); |
| 171 } |
124 while (code_length-- > 0) { | 172 while (code_length-- > 0) { |
125 if (node >= max_node) { | 173 if (node >= max_node) { |
126 return 0; | 174 return 0; |
127 } | 175 } |
128 if (NodeIsEmpty(node)) { | 176 if (NodeIsEmpty(node)) { |
129 if (IsFull(tree)) return 0; // error: too many symbols. | 177 if (IsFull(tree)) return 0; // error: too many symbols. |
130 AssignChildren(tree, node); | 178 AssignChildren(tree, node); |
131 } else if (HuffmanTreeNodeIsLeaf(node)) { | 179 } else if (!HuffmanTreeNodeIsNotLeaf(node)) { |
132 return 0; // leaf is already occupied. | 180 return 0; // leaf is already occupied. |
133 } | 181 } |
134 node += node->children_ + ((code >> code_length) & 1); | 182 node += node->children_ + ((code >> code_length) & 1); |
| 183 if (--step == 0) { |
| 184 tree->lut_jump_[base_code] = (int16_t)(node - tree->root_); |
| 185 } |
135 } | 186 } |
136 if (NodeIsEmpty(node)) { | 187 if (NodeIsEmpty(node)) { |
137 node->children_ = 0; // turn newly created node into a leaf. | 188 node->children_ = 0; // turn newly created node into a leaf. |
138 } else if (!HuffmanTreeNodeIsLeaf(node)) { | 189 } else if (HuffmanTreeNodeIsNotLeaf(node)) { |
139 return 0; // trying to assign a symbol to already used code. | 190 return 0; // trying to assign a symbol to already used code. |
140 } | 191 } |
141 node->symbol_ = symbol; // Add symbol in this node. | 192 node->symbol_ = symbol; // Add symbol in this node. |
142 return 1; | 193 return 1; |
143 } | 194 } |
144 | 195 |
145 int HuffmanTreeBuildImplicit(HuffmanTree* const tree, | 196 int HuffmanTreeBuildImplicit(HuffmanTree* const tree, |
146 const int* const code_lengths, | 197 const int* const code_lengths, |
147 int code_lengths_size) { | 198 int code_lengths_size) { |
148 int symbol; | 199 int symbol; |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 } | 279 } |
229 } | 280 } |
230 } | 281 } |
231 ok = 1; | 282 ok = 1; |
232 End: | 283 End: |
233 ok = ok && IsFull(tree); | 284 ok = ok && IsFull(tree); |
234 if (!ok) HuffmanTreeRelease(tree); | 285 if (!ok) HuffmanTreeRelease(tree); |
235 return ok; | 286 return ok; |
236 } | 287 } |
237 | 288 |
238 #if defined(__cplusplus) || defined(c_plusplus) | |
239 } // extern "C" | |
240 #endif | |
OLD | NEW |