/src/brunsli/c/dec/histogram_decode.cc
Line | Count | Source |
1 | | // Copyright (c) Google LLC 2019 |
2 | | // |
3 | | // Use of this source code is governed by an MIT-style |
4 | | // license that can be found in the LICENSE file or at |
5 | | // https://opensource.org/licenses/MIT. |
6 | | |
7 | | #include "./histogram_decode.h" |
8 | | |
9 | | #include "../common/ans_params.h" |
10 | | #include "../common/histogram.h" |
11 | | #include "../common/platform.h" |
12 | | #include <brunsli/types.h> |
13 | | #include "./bit_reader.h" |
14 | | |
15 | | namespace brunsli { |
16 | | |
17 | | namespace { |
18 | | |
19 | | // Binary trees; positive - offset to child nodes; other - minus leaf value. |
20 | | // 3-8 bits encoding value 3..18. |
21 | | const int8_t kLengthTree[] = {1, 2, 3, 4, 5, 6, 7, -10, -11, -12, -13, |
22 | | -14, -15, 2, 3, -9, -16, 2, 3, -8, -17, 2, 3, -5, -6, -7, 1, -18, 1, -3, -4}; |
23 | | // 2..6 bits encoding value 0..10. |
24 | | const int8_t kLogCountTree[] = {1, 2, 3, -6, 3, 4, 5, -4, -5, -7, -8, 2, |
25 | | 3, -1, -2, -3, 1, 0, 1, -9, -10}; |
26 | | |
27 | 51.2k | size_t ReadShortHuffmanCode(BrunsliBitReader* br, const int8_t* tree) { |
28 | 51.2k | size_t pos = 0; |
29 | 51.2k | int8_t delta = 1; |
30 | 200k | while (delta > 0) { |
31 | 149k | pos += delta + BrunsliBitReaderRead(br, 1); |
32 | 149k | delta = tree[pos]; |
33 | 149k | } |
34 | 51.2k | return static_cast<size_t>(-delta); |
35 | 51.2k | } |
36 | | |
37 | | } // namespace |
38 | | |
39 | | bool ReadHistogram(uint32_t precision_bits, std::vector<uint32_t>* counts, |
40 | 23.5k | BrunsliBitReader* br) { |
41 | 23.5k | BRUNSLI_DCHECK(!counts->empty()); |
42 | 23.5k | uint32_t space = 1u << precision_bits; |
43 | 23.5k | const size_t length = counts->size(); |
44 | 23.5k | std::fill(counts->begin(), counts->end(), 0); |
45 | 23.5k | uint32_t* histogram = counts->data(); |
46 | 23.5k | int simple_code = BrunsliBitReaderRead(br, 1); |
47 | 23.5k | if (simple_code == 1) { |
48 | 19.4k | size_t max_bits_counter = length - 1; |
49 | 19.4k | uint32_t max_bits = 0; |
50 | 19.4k | int symbols[2] = {0}; |
51 | 19.4k | const size_t num_symbols = BrunsliBitReaderRead(br, 1) + 1u; |
52 | 116k | while (max_bits_counter) { |
53 | 97.1k | max_bits_counter >>= 1; |
54 | 97.1k | ++max_bits; |
55 | 97.1k | } |
56 | 45.0k | for (size_t i = 0; i < num_symbols; ++i) { |
57 | 25.6k | symbols[i] = BrunsliBitReaderRead(br, max_bits) % length; |
58 | 25.6k | } |
59 | 19.4k | if (num_symbols == 1) { |
60 | 13.2k | histogram[symbols[0]] = space; |
61 | 13.2k | } else { |
62 | 6.20k | if (symbols[0] == symbols[1]) { // corrupt data |
63 | 20 | return false; |
64 | 20 | } |
65 | 6.18k | uint32_t value = BrunsliBitReaderRead(br, precision_bits); |
66 | 6.18k | histogram[symbols[0]] = value; |
67 | 6.18k | histogram[symbols[1]] = space - value; |
68 | 6.18k | } |
69 | 19.4k | } else { |
70 | 4.14k | size_t real_length = ReadShortHuffmanCode(br, kLengthTree); |
71 | 4.14k | uint32_t total_count = 0; |
72 | 4.14k | uint32_t log_counts[BRUNSLI_ANS_MAX_SYMBOLS]; |
73 | 4.14k | size_t omit_pos = 0; |
74 | 4.14k | BRUNSLI_DCHECK(real_length > 2); |
75 | 51.2k | for (size_t i = 0; i < real_length; ++i) { |
76 | 47.1k | log_counts[i] = |
77 | 47.1k | static_cast<uint32_t>(ReadShortHuffmanCode(br, kLogCountTree)); |
78 | 47.1k | if (log_counts[i] > log_counts[omit_pos]) omit_pos = i; |
79 | 47.1k | } |
80 | 4.14k | BRUNSLI_DCHECK(omit_pos >= 0); |
81 | 51.2k | for (size_t i = 0; i < real_length; ++i) { |
82 | 47.1k | uint32_t code = log_counts[i]; |
83 | 47.1k | if (i == omit_pos) { |
84 | 4.14k | continue; |
85 | 43.0k | } else if (code == 0) { |
86 | 1.58k | continue; |
87 | 41.4k | } else if (code == 1) { |
88 | 2.96k | histogram[i] = 1; |
89 | 38.4k | } else { |
90 | 38.4k | uint32_t bit_count = GetPopulationCountPrecision(code - 1); |
91 | 38.4k | histogram[i] = (1u << (code - 1)) + (BrunsliBitReaderRead(br, bit_count) |
92 | 38.4k | << (code - 1 - bit_count)); |
93 | 38.4k | } |
94 | 41.4k | total_count += histogram[i]; |
95 | 41.4k | } |
96 | 4.14k | if (total_count >= space) { |
97 | | // The histogram we've read sums to more than total_count (including at |
98 | | // least 1 for the omitted value). |
99 | 25 | return false; |
100 | 25 | } |
101 | 4.12k | histogram[omit_pos] = space - total_count; |
102 | 4.12k | } |
103 | 23.5k | return BrunsliBitReaderIsHealthy(br); |
104 | 23.5k | } |
105 | | |
106 | | } // namespace brunsli |