/src/libjxl/lib/jxl/enc_huffman_tree.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #include "lib/jxl/enc_huffman_tree.h" |
7 | | |
8 | | // Suppress any -Wdeprecated-declarations warning that might be emitted by |
9 | | // GCC or Clang by std::stable_sort in C++17 or later mode |
10 | | #ifdef __clang__ |
11 | | #pragma clang diagnostic push |
12 | | #pragma clang diagnostic ignored "-Wdeprecated-declarations" |
13 | | #elif defined(__GNUC__) |
14 | | #pragma GCC push_options |
15 | | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
16 | | #endif |
17 | | |
18 | | #include <algorithm> |
19 | | |
20 | | #ifdef __clang__ |
21 | | #pragma clang diagnostic pop |
22 | | #elif defined(__GNUC__) |
23 | | #pragma GCC pop_options |
24 | | #endif |
25 | | |
26 | | #include <limits> |
27 | | #include <vector> |
28 | | |
29 | | #include "lib/jxl/base/status.h" |
30 | | |
31 | | namespace jxl { |
32 | | |
33 | | void SetDepth(const HuffmanTree& p, HuffmanTree* pool, uint8_t* depth, |
34 | 0 | uint8_t level) { |
35 | 0 | if (p.index_left >= 0) { |
36 | 0 | ++level; |
37 | 0 | SetDepth(pool[p.index_left], pool, depth, level); |
38 | 0 | SetDepth(pool[p.index_right_or_value], pool, depth, level); |
39 | 0 | } else { |
40 | 0 | depth[p.index_right_or_value] = level; |
41 | 0 | } |
42 | 0 | } |
43 | | |
44 | | // Sort the root nodes, least popular first. |
45 | 0 | static JXL_INLINE bool Compare(const HuffmanTree& v0, const HuffmanTree& v1) { |
46 | 0 | return v0.total_count < v1.total_count; |
47 | 0 | } |
48 | | |
49 | | // This function will create a Huffman tree. |
50 | | // |
51 | | // The catch here is that the tree cannot be arbitrarily deep. |
52 | | // Brotli specifies a maximum depth of 15 bits for "code trees" |
53 | | // and 7 bits for "code length code trees." |
54 | | // |
55 | | // count_limit is the value that is to be faked as the minimum value |
56 | | // and this minimum value is raised until the tree matches the |
57 | | // maximum length requirement. |
58 | | // |
59 | | // This algorithm is not of excellent performance for very long data blocks, |
60 | | // especially when population counts are longer than 2**tree_limit, but |
61 | | // we are not planning to use this with extremely long blocks. |
62 | | // |
63 | | // See http://en.wikipedia.org/wiki/Huffman_coding |
64 | | void CreateHuffmanTree(const uint32_t* data, const size_t length, |
65 | 0 | const int tree_limit, uint8_t* depth) { |
66 | | // For block sizes below 64 kB, we never need to do a second iteration |
67 | | // of this loop. Probably all of our block sizes will be smaller than |
68 | | // that, so this loop is mostly of academic interest. If we actually |
69 | | // would need this, we would be better off with the Katajainen algorithm. |
70 | 0 | for (uint32_t count_limit = 1;; count_limit *= 2) { |
71 | 0 | std::vector<HuffmanTree> tree; |
72 | 0 | tree.reserve(2 * length + 1); |
73 | |
|
74 | 0 | for (size_t i = length; i != 0;) { |
75 | 0 | --i; |
76 | 0 | if (data[i]) { |
77 | 0 | const uint32_t count = std::max(data[i], count_limit - 1); |
78 | 0 | tree.emplace_back(count, -1, static_cast<int16_t>(i)); |
79 | 0 | } |
80 | 0 | } |
81 | |
|
82 | 0 | const size_t n = tree.size(); |
83 | 0 | if (n == 1) { |
84 | | // Fake value; will be fixed on upper level. |
85 | 0 | depth[tree[0].index_right_or_value] = 1; |
86 | 0 | break; |
87 | 0 | } |
88 | | |
89 | 0 | std::stable_sort(tree.begin(), tree.end(), Compare); |
90 | | |
91 | | // The nodes are: |
92 | | // [0, n): the sorted leaf nodes that we start with. |
93 | | // [n]: we add a sentinel here. |
94 | | // [n + 1, 2n): new parent nodes are added here, starting from |
95 | | // (n+1). These are naturally in ascending order. |
96 | | // [2n]: we add a sentinel at the end as well. |
97 | | // There will be (2n+1) elements at the end. |
98 | 0 | const HuffmanTree sentinel(std::numeric_limits<uint32_t>::max(), -1, -1); |
99 | 0 | tree.push_back(sentinel); |
100 | 0 | tree.push_back(sentinel); |
101 | |
|
102 | 0 | size_t i = 0; // Points to the next leaf node. |
103 | 0 | size_t j = n + 1; // Points to the next non-leaf node. |
104 | 0 | for (size_t k = n - 1; k != 0; --k) { |
105 | 0 | size_t left; |
106 | 0 | size_t right; |
107 | 0 | if (tree[i].total_count <= tree[j].total_count) { |
108 | 0 | left = i; |
109 | 0 | ++i; |
110 | 0 | } else { |
111 | 0 | left = j; |
112 | 0 | ++j; |
113 | 0 | } |
114 | 0 | if (tree[i].total_count <= tree[j].total_count) { |
115 | 0 | right = i; |
116 | 0 | ++i; |
117 | 0 | } else { |
118 | 0 | right = j; |
119 | 0 | ++j; |
120 | 0 | } |
121 | | |
122 | | // The sentinel node becomes the parent node. |
123 | 0 | size_t j_end = tree.size() - 1; |
124 | 0 | tree[j_end].total_count = |
125 | 0 | tree[left].total_count + tree[right].total_count; |
126 | 0 | tree[j_end].index_left = static_cast<int16_t>(left); |
127 | 0 | tree[j_end].index_right_or_value = static_cast<int16_t>(right); |
128 | | |
129 | | // Add back the last sentinel node. |
130 | 0 | tree.push_back(sentinel); |
131 | 0 | } |
132 | 0 | JXL_DASSERT(tree.size() == 2 * n + 1); |
133 | 0 | SetDepth(tree[2 * n - 1], tree.data(), depth, 0); |
134 | | |
135 | | // We need to pack the Huffman tree in tree_limit bits. |
136 | | // If this was not successful, add fake entities to the lowest values |
137 | | // and retry. |
138 | 0 | if (*std::max_element(&depth[0], &depth[length]) <= tree_limit) { |
139 | 0 | break; |
140 | 0 | } |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | 0 | void Reverse(uint8_t* v, size_t start, size_t end) { |
145 | 0 | --end; |
146 | 0 | while (start < end) { |
147 | 0 | uint8_t tmp = v[start]; |
148 | 0 | v[start] = v[end]; |
149 | 0 | v[end] = tmp; |
150 | 0 | ++start; |
151 | 0 | --end; |
152 | 0 | } |
153 | 0 | } |
154 | | |
155 | | void WriteHuffmanTreeRepetitions(const uint8_t previous_value, |
156 | | const uint8_t value, size_t repetitions, |
157 | | size_t* tree_size, uint8_t* tree, |
158 | 0 | uint8_t* extra_bits_data) { |
159 | 0 | JXL_DASSERT(repetitions > 0); |
160 | 0 | if (previous_value != value) { |
161 | 0 | tree[*tree_size] = value; |
162 | 0 | extra_bits_data[*tree_size] = 0; |
163 | 0 | ++(*tree_size); |
164 | 0 | --repetitions; |
165 | 0 | } |
166 | 0 | if (repetitions == 7) { |
167 | 0 | tree[*tree_size] = value; |
168 | 0 | extra_bits_data[*tree_size] = 0; |
169 | 0 | ++(*tree_size); |
170 | 0 | --repetitions; |
171 | 0 | } |
172 | 0 | if (repetitions < 3) { |
173 | 0 | for (size_t i = 0; i < repetitions; ++i) { |
174 | 0 | tree[*tree_size] = value; |
175 | 0 | extra_bits_data[*tree_size] = 0; |
176 | 0 | ++(*tree_size); |
177 | 0 | } |
178 | 0 | } else { |
179 | 0 | repetitions -= 3; |
180 | 0 | size_t start = *tree_size; |
181 | 0 | while (true) { |
182 | 0 | tree[*tree_size] = 16; |
183 | 0 | extra_bits_data[*tree_size] = repetitions & 0x3; |
184 | 0 | ++(*tree_size); |
185 | 0 | repetitions >>= 2; |
186 | 0 | if (repetitions == 0) { |
187 | 0 | break; |
188 | 0 | } |
189 | 0 | --repetitions; |
190 | 0 | } |
191 | 0 | Reverse(tree, start, *tree_size); |
192 | 0 | Reverse(extra_bits_data, start, *tree_size); |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | | void WriteHuffmanTreeRepetitionsZeros(size_t repetitions, size_t* tree_size, |
197 | 0 | uint8_t* tree, uint8_t* extra_bits_data) { |
198 | 0 | if (repetitions == 11) { |
199 | 0 | tree[*tree_size] = 0; |
200 | 0 | extra_bits_data[*tree_size] = 0; |
201 | 0 | ++(*tree_size); |
202 | 0 | --repetitions; |
203 | 0 | } |
204 | 0 | if (repetitions < 3) { |
205 | 0 | for (size_t i = 0; i < repetitions; ++i) { |
206 | 0 | tree[*tree_size] = 0; |
207 | 0 | extra_bits_data[*tree_size] = 0; |
208 | 0 | ++(*tree_size); |
209 | 0 | } |
210 | 0 | } else { |
211 | 0 | repetitions -= 3; |
212 | 0 | size_t start = *tree_size; |
213 | 0 | while (true) { |
214 | 0 | tree[*tree_size] = 17; |
215 | 0 | extra_bits_data[*tree_size] = repetitions & 0x7; |
216 | 0 | ++(*tree_size); |
217 | 0 | repetitions >>= 3; |
218 | 0 | if (repetitions == 0) { |
219 | 0 | break; |
220 | 0 | } |
221 | 0 | --repetitions; |
222 | 0 | } |
223 | 0 | Reverse(tree, start, *tree_size); |
224 | 0 | Reverse(extra_bits_data, start, *tree_size); |
225 | 0 | } |
226 | 0 | } |
227 | | |
228 | | static void DecideOverRleUse(const uint8_t* depth, const size_t length, |
229 | | bool* use_rle_for_non_zero, |
230 | 0 | bool* use_rle_for_zero) { |
231 | 0 | size_t total_reps_zero = 0; |
232 | 0 | size_t total_reps_non_zero = 0; |
233 | 0 | size_t count_reps_zero = 1; |
234 | 0 | size_t count_reps_non_zero = 1; |
235 | 0 | for (size_t i = 0; i < length;) { |
236 | 0 | const uint8_t value = depth[i]; |
237 | 0 | size_t reps = 1; |
238 | 0 | for (size_t k = i + 1; k < length && depth[k] == value; ++k) { |
239 | 0 | ++reps; |
240 | 0 | } |
241 | 0 | if (reps >= 3 && value == 0) { |
242 | 0 | total_reps_zero += reps; |
243 | 0 | ++count_reps_zero; |
244 | 0 | } |
245 | 0 | if (reps >= 4 && value != 0) { |
246 | 0 | total_reps_non_zero += reps; |
247 | 0 | ++count_reps_non_zero; |
248 | 0 | } |
249 | 0 | i += reps; |
250 | 0 | } |
251 | 0 | *use_rle_for_non_zero = total_reps_non_zero > count_reps_non_zero * 2; |
252 | 0 | *use_rle_for_zero = total_reps_zero > count_reps_zero * 2; |
253 | 0 | } |
254 | | |
255 | | void WriteHuffmanTree(const uint8_t* depth, size_t length, size_t* tree_size, |
256 | 0 | uint8_t* tree, uint8_t* extra_bits_data) { |
257 | 0 | uint8_t previous_value = 8; |
258 | | |
259 | | // Throw away trailing zeros. |
260 | 0 | size_t new_length = length; |
261 | 0 | for (size_t i = 0; i < length; ++i) { |
262 | 0 | if (depth[length - i - 1] == 0) { |
263 | 0 | --new_length; |
264 | 0 | } else { |
265 | 0 | break; |
266 | 0 | } |
267 | 0 | } |
268 | | |
269 | | // First gather statistics on if it is a good idea to do rle. |
270 | 0 | bool use_rle_for_non_zero = false; |
271 | 0 | bool use_rle_for_zero = false; |
272 | 0 | if (length > 50) { |
273 | | // Find rle coding for longer codes. |
274 | | // Shorter codes seem not to benefit from rle. |
275 | 0 | DecideOverRleUse(depth, new_length, &use_rle_for_non_zero, |
276 | 0 | &use_rle_for_zero); |
277 | 0 | } |
278 | | |
279 | | // Actual rle coding. |
280 | 0 | for (size_t i = 0; i < new_length;) { |
281 | 0 | const uint8_t value = depth[i]; |
282 | 0 | size_t reps = 1; |
283 | 0 | if ((value != 0 && use_rle_for_non_zero) || |
284 | 0 | (value == 0 && use_rle_for_zero)) { |
285 | 0 | for (size_t k = i + 1; k < new_length && depth[k] == value; ++k) { |
286 | 0 | ++reps; |
287 | 0 | } |
288 | 0 | } |
289 | 0 | if (value == 0) { |
290 | 0 | WriteHuffmanTreeRepetitionsZeros(reps, tree_size, tree, extra_bits_data); |
291 | 0 | } else { |
292 | 0 | WriteHuffmanTreeRepetitions(previous_value, value, reps, tree_size, tree, |
293 | 0 | extra_bits_data); |
294 | 0 | previous_value = value; |
295 | 0 | } |
296 | 0 | i += reps; |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | | namespace { |
301 | | |
302 | 0 | uint16_t ReverseBits(int num_bits, uint16_t bits) { |
303 | 0 | static const size_t kLut[16] = {// Pre-reversed 4-bit values. |
304 | 0 | 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, |
305 | 0 | 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf}; |
306 | 0 | size_t retval = kLut[bits & 0xf]; |
307 | 0 | for (int i = 4; i < num_bits; i += 4) { |
308 | 0 | retval <<= 4; |
309 | 0 | bits = static_cast<uint16_t>(bits >> 4); |
310 | 0 | retval |= kLut[bits & 0xf]; |
311 | 0 | } |
312 | 0 | retval >>= (-num_bits & 0x3); |
313 | 0 | return static_cast<uint16_t>(retval); |
314 | 0 | } |
315 | | |
316 | | } // namespace |
317 | | |
318 | | void ConvertBitDepthsToSymbols(const uint8_t* depth, size_t len, |
319 | 0 | uint16_t* bits) { |
320 | | // In Brotli, all bit depths are [1..15] |
321 | | // 0 bit depth means that the symbol does not exist. |
322 | 0 | const int kMaxBits = 16; // 0..15 are values for bits |
323 | 0 | uint16_t bl_count[kMaxBits] = {0}; |
324 | 0 | { |
325 | 0 | for (size_t i = 0; i < len; ++i) { |
326 | 0 | ++bl_count[depth[i]]; |
327 | 0 | } |
328 | 0 | bl_count[0] = 0; |
329 | 0 | } |
330 | 0 | uint16_t next_code[kMaxBits]; |
331 | 0 | next_code[0] = 0; |
332 | 0 | { |
333 | 0 | int code = 0; |
334 | 0 | for (size_t i = 1; i < kMaxBits; ++i) { |
335 | 0 | code = (code + bl_count[i - 1]) << 1; |
336 | 0 | next_code[i] = static_cast<uint16_t>(code); |
337 | 0 | } |
338 | 0 | } |
339 | 0 | for (size_t i = 0; i < len; ++i) { |
340 | 0 | if (depth[i]) { |
341 | 0 | bits[i] = ReverseBits(depth[i], next_code[depth[i]]++); |
342 | 0 | } |
343 | 0 | } |
344 | 0 | } |
345 | | |
346 | | } // namespace jxl |