Coverage Report

Created: 2025-06-22 08:04

/src/libjxl/lib/jxl/enc_ans.h
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
#ifndef LIB_JXL_ENC_ANS_H_
7
#define LIB_JXL_ENC_ANS_H_
8
9
// Library to encode the ANS population counts to the bit-stream and encode
10
// symbols based on the respective distributions.
11
12
#include <jxl/memory_manager.h>
13
14
#include <cstddef>
15
#include <cstdint>
16
#include <vector>
17
18
#include "lib/jxl/ans_params.h"
19
#include "lib/jxl/base/status.h"
20
#include "lib/jxl/dec_ans.h"
21
#include "lib/jxl/enc_ans_params.h"
22
#include "lib/jxl/enc_bit_writer.h"
23
24
namespace jxl {
25
26
struct AuxOut;
27
enum class LayerType : uint8_t;
28
29
#define USE_MULT_BY_RECIPROCAL
30
31
// precision must be equal to:  #bits(state_) + #bits(freq)
32
0
#define RECIPROCAL_PRECISION (32 + ANS_LOG_TAB_SIZE)
33
34
// Data structure representing one element of the encoding table built
35
// from a distribution.
36
// TODO(veluca): split this up, or use an union.
37
struct ANSEncSymbolInfo {
38
  // ANS
39
  uint16_t freq_;
40
  std::vector<uint16_t> reverse_map_;
41
#ifdef USE_MULT_BY_RECIPROCAL
42
  uint64_t ifreq_;
43
#endif
44
  // Prefix coding.
45
  uint8_t depth;
46
  uint16_t bits;
47
};
48
49
class ANSCoder {
50
 public:
51
0
  ANSCoder() : state_(ANS_SIGNATURE << 16) {}
52
53
0
  uint32_t PutSymbol(const ANSEncSymbolInfo& t, uint8_t* nbits) {
54
0
    uint32_t bits = 0;
55
0
    *nbits = 0;
56
0
    if ((state_ >> (32 - ANS_LOG_TAB_SIZE)) >= t.freq_) {
57
0
      bits = state_ & 0xffff;
58
0
      state_ >>= 16;
59
0
      *nbits = 16;
60
0
    }
61
0
#ifdef USE_MULT_BY_RECIPROCAL
62
    // We use mult-by-reciprocal trick, but that requires 64b calc.
63
0
    const uint32_t v = (state_ * t.ifreq_) >> RECIPROCAL_PRECISION;
64
0
    const uint32_t offset = t.reverse_map_[state_ - v * t.freq_];
65
0
    state_ = (v << ANS_LOG_TAB_SIZE) + offset;
66
#else
67
    state_ = ((state_ / t.freq_) << ANS_LOG_TAB_SIZE) +
68
             t.reverse_map_[state_ % t.freq_];
69
#endif
70
0
    return bits;
71
0
  }
72
73
0
  uint32_t GetState() const { return state_; }
74
75
 private:
76
  uint32_t state_;
77
};
78
79
static const int kNumFixedHistograms = 1;
80
81
struct EntropyEncodingData {
82
  std::vector<std::vector<ANSEncSymbolInfo>> encoding_info;
83
  bool use_prefix_code;
84
  std::vector<HybridUintConfig> uint_config;
85
  LZ77Params lz77;
86
  std::vector<BitWriter> encoded_histograms;
87
};
88
89
// Integer to be encoded by an entropy coder, either ANS or Huffman.
90
struct Token {
91
  Token() = default;
92
  Token(uint32_t c, uint32_t value)
93
0
      : is_lz77_length(false), context(c), value(value) {}
94
  uint32_t is_lz77_length : 1;
95
  uint32_t context : 31;
96
  uint32_t value;
97
};
98
99
// Returns an estimate of the number of bits required to encode the given
100
// histogram (header bits plus data bits).
101
StatusOr<float> ANSPopulationCost(const ANSHistBin* data, size_t alphabet_size);
102
103
// Writes the context map to the bitstream and concatenates the individual
104
// histogram bistreams in codes.encoded_histograms. Used in streaming mode.
105
Status EncodeHistograms(const std::vector<uint8_t>& context_map,
106
                        const EntropyEncodingData& codes, BitWriter* writer,
107
                        LayerType layer, AuxOut* aux_out);
108
109
// Apply context clustering, compute histograms and encode them. Returns an
110
// estimate of the total bits used for encoding the stream. If `writer` ==
111
// nullptr, the bit estimate will not take into account the context map (which
112
// does not get written if `num_contexts` == 1).
113
// Returns cost
114
StatusOr<size_t> BuildAndEncodeHistograms(
115
    JxlMemoryManager* memory_manager, const HistogramParams& params,
116
    size_t num_contexts, std::vector<std::vector<Token>>& tokens,
117
    EntropyEncodingData* codes, std::vector<uint8_t>* context_map,
118
    BitWriter* writer, LayerType layer, AuxOut* aux_out);
119
120
// Write the tokens to a string.
121
Status WriteTokens(const std::vector<Token>& tokens,
122
                   const EntropyEncodingData& codes,
123
                   const std::vector<uint8_t>& context_map,
124
                   size_t context_offset, BitWriter* writer, LayerType layer,
125
                   AuxOut* aux_out);
126
127
// Same as above, but assumes allotment created by caller.
128
size_t WriteTokens(const std::vector<Token>& tokens,
129
                   const EntropyEncodingData& codes,
130
                   const std::vector<uint8_t>& context_map,
131
                   size_t context_offset, BitWriter* writer);
132
133
// Exposed for tests; to be used with Writer=BitWriter only.
134
template <typename Writer>
135
void EncodeUintConfigs(const std::vector<HybridUintConfig>& uint_config,
136
                       Writer* writer, size_t log_alpha_size);
137
extern template void EncodeUintConfigs(const std::vector<HybridUintConfig>&,
138
                                       BitWriter*, size_t);
139
140
// Globally set the option to create fuzzer-friendly ANS streams. Negatively
141
// impacts compression. Not thread-safe.
142
void SetANSFuzzerFriendly(bool ans_fuzzer_friendly);
143
}  // namespace jxl
144
145
#endif  // LIB_JXL_ENC_ANS_H_