Coverage Report

Created: 2022-08-24 06:04

/src/libjxl/lib/jxl/enc_huffman.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.h"
7
8
#include <algorithm>
9
#include <memory>
10
11
#include "lib/jxl/huffman_tree.h"
12
13
namespace jxl {
14
15
namespace {
16
17
constexpr int kCodeLengthCodes = 18;
18
19
void StoreHuffmanTreeOfHuffmanTreeToBitMask(const int num_codes,
20
                                            const uint8_t* code_length_bitdepth,
21
368
                                            BitWriter* writer) {
22
368
  static const uint8_t kStorageOrder[kCodeLengthCodes] = {
23
368
      1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15};
24
  // The bit lengths of the Huffman code over the code length alphabet
25
  // are compressed with the following static Huffman code:
26
  //   Symbol   Code
27
  //   ------   ----
28
  //   0          00
29
  //   1        1110
30
  //   2         110
31
  //   3          01
32
  //   4          10
33
  //   5        1111
34
368
  static const uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = {0, 7, 3,
35
368
                                                                 2, 1, 15};
36
368
  static const uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = {2, 4, 3,
37
368
                                                                    2, 2, 4};
38
39
  // Throw away trailing zeros:
40
368
  size_t codes_to_store = kCodeLengthCodes;
41
368
  if (num_codes > 1) {
42
4.87k
    for (; codes_to_store > 0; --codes_to_store) {
43
4.87k
      if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
44
368
        break;
45
368
      }
46
4.87k
    }
47
368
  }
48
368
  size_t skip_some = 0;  // skips none.
49
368
  if (code_length_bitdepth[kStorageOrder[0]] == 0 &&
50
368
      code_length_bitdepth[kStorageOrder[1]] == 0) {
51
0
    skip_some = 2;  // skips two.
52
0
    if (code_length_bitdepth[kStorageOrder[2]] == 0) {
53
0
      skip_some = 3;  // skips three.
54
0
    }
55
0
  }
56
368
  writer->Write(2, skip_some);
57
2.48k
  for (size_t i = skip_some; i < codes_to_store; ++i) {
58
2.11k
    size_t l = code_length_bitdepth[kStorageOrder[i]];
59
2.11k
    writer->Write(kHuffmanBitLengthHuffmanCodeBitLengths[l],
60
2.11k
                  kHuffmanBitLengthHuffmanCodeSymbols[l]);
61
2.11k
  }
62
368
}
63
64
void StoreHuffmanTreeToBitMask(const size_t huffman_tree_size,
65
                               const uint8_t* huffman_tree,
66
                               const uint8_t* huffman_tree_extra_bits,
67
                               const uint8_t* code_length_bitdepth,
68
                               const uint16_t* code_length_bitdepth_symbols,
69
368
                               BitWriter* writer) {
70
3.22k
  for (size_t i = 0; i < huffman_tree_size; ++i) {
71
2.85k
    size_t ix = huffman_tree[i];
72
2.85k
    writer->Write(code_length_bitdepth[ix], code_length_bitdepth_symbols[ix]);
73
    // Extra bits
74
2.85k
    switch (ix) {
75
0
      case 16:
76
0
        writer->Write(2, huffman_tree_extra_bits[i]);
77
0
        break;
78
0
      case 17:
79
0
        writer->Write(3, huffman_tree_extra_bits[i]);
80
0
        break;
81
2.85k
    }
82
2.85k
  }
83
368
}
84
85
void StoreSimpleHuffmanTree(const uint8_t* depths, size_t symbols[4],
86
                            size_t num_symbols, size_t max_bits,
87
92
                            BitWriter* writer) {
88
  // value of 1 indicates a simple Huffman code
89
92
  writer->Write(2, 1);
90
92
  writer->Write(2, num_symbols - 1);  // NSYM - 1
91
92
  // Sort
93
460
  for (size_t i = 0; i < num_symbols; i++) {
94
920
    for (size_t j = i + 1; j < num_symbols; j++) {
95
552
      if (depths[symbols[j]] < depths[symbols[i]]) {
96
0
        std::swap(symbols[j], symbols[i]);
97
0
      }
98
552
    }
99
368
  }
100
101
92
  if (num_symbols == 2) {
102
0
    writer->Write(max_bits, symbols[0]);
103
0
    writer->Write(max_bits, symbols[1]);
104
92
  } else if (num_symbols == 3) {
105
0
    writer->Write(max_bits, symbols[0]);
106
0
    writer->Write(max_bits, symbols[1]);
107
0
    writer->Write(max_bits, symbols[2]);
108
92
  } else {
109
92
    writer->Write(max_bits, symbols[0]);
110
92
    writer->Write(max_bits, symbols[1]);
111
92
    writer->Write(max_bits, symbols[2]);
112
92
    writer->Write(max_bits, symbols[3]);
113
    // tree-select
114
92
    writer->Write(1, depths[symbols[0]] == 1 ? 1 : 0);
115
92
  }
116
92
}
117
118
// num = alphabet size
119
// depths = symbol depths
120
368
void StoreHuffmanTree(const uint8_t* depths, size_t num, BitWriter* writer) {
121
  // Write the Huffman tree into the compact representation.
122
368
  std::unique_ptr<uint8_t[]> arena(new uint8_t[2 * num]);
123
368
  uint8_t* huffman_tree = arena.get();
124
368
  uint8_t* huffman_tree_extra_bits = arena.get() + num;
125
368
  size_t huffman_tree_size = 0;
126
368
  WriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree,
127
368
                   huffman_tree_extra_bits);
128
129
  // Calculate the statistics of the Huffman tree in the compact representation.
130
368
  uint32_t huffman_tree_histogram[kCodeLengthCodes] = {0};
131
3.22k
  for (size_t i = 0; i < huffman_tree_size; ++i) {
132
2.85k
    ++huffman_tree_histogram[huffman_tree[i]];
133
2.85k
  }
134
135
368
  int num_codes = 0;
136
368
  int code = 0;
137
1.10k
  for (int i = 0; i < kCodeLengthCodes; ++i) {
138
1.10k
    if (huffman_tree_histogram[i]) {
139
736
      if (num_codes == 0) {
140
368
        code = i;
141
368
        num_codes = 1;
142
368
      } else if (num_codes == 1) {
143
368
        num_codes = 2;
144
368
        break;
145
368
      }
146
736
    }
147
1.10k
  }
148
149
  // Calculate another Huffman tree to use for compressing both the
150
  // earlier Huffman tree with.
151
368
  uint8_t code_length_bitdepth[kCodeLengthCodes] = {0};
152
368
  uint16_t code_length_bitdepth_symbols[kCodeLengthCodes] = {0};
153
368
  CreateHuffmanTree(&huffman_tree_histogram[0], kCodeLengthCodes, 5,
154
368
                    &code_length_bitdepth[0]);
155
368
  ConvertBitDepthsToSymbols(code_length_bitdepth, kCodeLengthCodes,
156
368
                            &code_length_bitdepth_symbols[0]);
157
158
  // Now, we have all the data, let's start storing it
159
368
  StoreHuffmanTreeOfHuffmanTreeToBitMask(num_codes, code_length_bitdepth,
160
368
                                         writer);
161
162
368
  if (num_codes == 1) {
163
0
    code_length_bitdepth[code] = 0;
164
0
  }
165
166
  // Store the real huffman tree now.
167
368
  StoreHuffmanTreeToBitMask(huffman_tree_size, huffman_tree,
168
368
                            huffman_tree_extra_bits, &code_length_bitdepth[0],
169
368
                            code_length_bitdepth_symbols, writer);
170
368
}
171
172
}  // namespace
173
174
void BuildAndStoreHuffmanTree(const uint32_t* histogram, const size_t length,
175
                              uint8_t* depth, uint16_t* bits,
176
460
                              BitWriter* writer) {
177
460
  size_t count = 0;
178
460
  size_t s4[4] = {0};
179
4.23k
  for (size_t i = 0; i < length; i++) {
180
4.04k
    if (histogram[i]) {
181
2.48k
      if (count < 4) {
182
1.84k
        s4[count] = i;
183
1.84k
      } else if (count > 4) {
184
276
        break;
185
276
      }
186
2.20k
      count++;
187
2.20k
    }
188
4.04k
  }
189
190
460
  size_t max_bits_counter = length - 1;
191
460
  size_t max_bits = 0;
192
2.02k
  while (max_bits_counter) {
193
1.56k
    max_bits_counter >>= 1;
194
1.56k
    ++max_bits;
195
1.56k
  }
196
197
460
  if (count <= 1) {
198
    // Output symbol bits and depths are initialized with 0, nothing to do.
199
0
    writer->Write(4, 1);
200
0
    writer->Write(max_bits, s4[0]);
201
0
    return;
202
0
  }
203
204
460
  CreateHuffmanTree(histogram, length, 15, depth);
205
460
  ConvertBitDepthsToSymbols(depth, length, bits);
206
207
460
  if (count <= 4) {
208
92
    StoreSimpleHuffmanTree(depth, s4, count, max_bits, writer);
209
368
  } else {
210
368
    StoreHuffmanTree(depth, length, writer);
211
368
  }
212
460
}
213
214
}  // namespace jxl