/src/libjxl/lib/jxl/modular/encoding/enc_ma.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_MODULAR_ENCODING_ENC_MA_H_ |
7 | | #define LIB_JXL_MODULAR_ENCODING_ENC_MA_H_ |
8 | | |
9 | | #include <algorithm> |
10 | | #include <cstddef> |
11 | | #include <cstdint> |
12 | | #include <vector> |
13 | | |
14 | | #include "lib/jxl/base/common.h" |
15 | | #include "lib/jxl/base/status.h" |
16 | | #include "lib/jxl/enc_ans.h" |
17 | | #include "lib/jxl/modular/encoding/dec_ma.h" |
18 | | #include "lib/jxl/modular/modular_image.h" |
19 | | #include "lib/jxl/modular/options.h" |
20 | | |
21 | | namespace jxl { |
22 | | |
23 | | // Struct to collect all the data needed to build a tree. |
24 | | struct TreeSamples { |
25 | 111 | bool HasSamples() const { |
26 | 111 | return !residuals.empty() && !residuals[0].empty(); |
27 | 111 | } |
28 | 47.3k | size_t NumDistinctSamples() const { return sample_counts.size(); } |
29 | 111 | size_t NumSamples() const { return num_samples; } |
30 | | // Set the predictor to use. Must be called before adding any samples. |
31 | | Status SetPredictor(Predictor predictor, |
32 | | ModularOptions::TreeMode wp_tree_mode); |
33 | | // Set the properties to use. Must be called before adding any samples. |
34 | | Status SetProperties(const std::vector<uint32_t> &properties, |
35 | | ModularOptions::TreeMode wp_tree_mode); |
36 | | |
37 | 11.0M | size_t Token(size_t pred, size_t i) const { return residuals[pred][i].tok; } |
38 | 9.80M | size_t NBits(size_t pred, size_t i) const { return residuals[pred][i].nbits; } |
39 | 11.0M | size_t Count(size_t i) const { return sample_counts[i]; } |
40 | 6.07k | size_t PredictorIndex(Predictor predictor) const { |
41 | 6.07k | const auto predictor_elem = |
42 | 6.07k | std::find(predictors.begin(), predictors.end(), predictor); |
43 | 6.07k | JXL_DASSERT(predictor_elem != predictors.end()); |
44 | 6.07k | return predictor_elem - predictors.begin(); |
45 | 6.07k | } |
46 | 0 | size_t PropertyIndex(size_t property) const { |
47 | 0 | const auto property_elem = |
48 | 0 | std::find(props_to_use.begin(), props_to_use.end(), property); |
49 | 0 | JXL_DASSERT(property_elem != props_to_use.end()); |
50 | 0 | return property_elem - props_to_use.begin(); |
51 | 0 | } |
52 | 42.1k | size_t NumPropertyValues(size_t property_index) const { |
53 | 42.1k | return compact_properties[property_index].size() + 1; |
54 | 42.1k | } |
55 | | // Returns the *quantized* property value. |
56 | 18.1M | size_t Property(size_t property_index, size_t i) const { |
57 | 18.1M | return props[property_index][i]; |
58 | 18.1M | } |
59 | 2.98k | int UnquantizeProperty(size_t property_index, uint32_t quant) const { |
60 | 2.98k | JXL_DASSERT(quant < compact_properties[property_index].size()); |
61 | 2.98k | return compact_properties[property_index][quant]; |
62 | 2.98k | } |
63 | | |
64 | 3.99M | Predictor PredictorFromIndex(size_t index) const { |
65 | 3.99M | JXL_DASSERT(index < predictors.size()); |
66 | 3.99M | return predictors[index]; |
67 | 3.99M | } |
68 | 367k | size_t PropertyFromIndex(size_t index) const { |
69 | 367k | JXL_DASSERT(index < props_to_use.size()); |
70 | 367k | return props_to_use[index]; |
71 | 367k | } |
72 | 417 | size_t NumPredictors() const { return predictors.size(); } |
73 | 222 | size_t NumProperties() const { return props_to_use.size(); } |
74 | | |
75 | | // Preallocate data for a given number of samples. MUST be called before |
76 | | // adding any sample. |
77 | | void PrepareForSamples(size_t extra_num_samples); |
78 | | // Add a sample. |
79 | | void AddSample(pixel_type_w pixel, const Properties &properties, |
80 | | const pixel_type_w *predictions); |
81 | | // Pre-cluster property values. |
82 | | void PreQuantizeProperties( |
83 | | const StaticPropRange &range, |
84 | | const std::vector<ModularMultiplierInfo> &multiplier_info, |
85 | | const std::vector<uint32_t> &group_pixel_count, |
86 | | const std::vector<uint32_t> &channel_pixel_count, |
87 | | std::vector<pixel_type> &pixel_samples, |
88 | | std::vector<pixel_type> &diff_samples, size_t max_property_values); |
89 | | |
90 | 111 | void AllSamplesDone() { dedup_table_ = std::vector<uint32_t>(); } |
91 | | |
92 | 5.64M | uint32_t QuantizeProperty(uint32_t prop, pixel_type v) const { |
93 | 5.64M | v = jxl::Clamp1(v, -kPropertyRange, kPropertyRange) + kPropertyRange; |
94 | 5.64M | return property_mapping[prop][v]; |
95 | 5.64M | } |
96 | | |
97 | | // Swaps samples in position a and b. Does nothing if a == b. |
98 | | void Swap(size_t a, size_t b); |
99 | | |
100 | | private: |
101 | | // TODO(veluca): as the total number of properties and predictors are known |
102 | | // before adding any samples, it might be better to interleave predictors, |
103 | | // properties and counts in a single vector to improve locality. |
104 | | // A first attempt at doing this actually results in much slower encoding, |
105 | | // possibly because of the more complex addressing. |
106 | | struct ResidualToken { |
107 | | uint8_t tok; |
108 | | uint8_t nbits; |
109 | | }; |
110 | | // Residual information: token and number of extra bits, per predictor. |
111 | | std::vector<std::vector<ResidualToken>> residuals; |
112 | | // Number of occurrences of each sample. |
113 | | std::vector<uint16_t> sample_counts; |
114 | | // Property values, quantized to at most 256 distinct values. |
115 | | std::vector<std::vector<uint8_t>> props; |
116 | | // Decompactification info for `props`. |
117 | | std::vector<std::vector<int32_t>> compact_properties; |
118 | | // List of properties to use. |
119 | | std::vector<uint32_t> props_to_use; |
120 | | // List of predictors to use. |
121 | | std::vector<Predictor> predictors; |
122 | | // Mapping property value -> quantized property value. |
123 | | static constexpr int32_t kPropertyRange = 511; |
124 | | std::vector<std::vector<uint8_t>> property_mapping; |
125 | | // Number of samples seen. |
126 | | size_t num_samples = 0; |
127 | | // Table for deduplication. |
128 | | static constexpr uint32_t kDedupEntryUnused{static_cast<uint32_t>(-1)}; |
129 | | std::vector<uint32_t> dedup_table_; |
130 | | |
131 | | // Functions for sample deduplication. |
132 | | bool IsSameSample(size_t a, size_t b) const; |
133 | | size_t Hash1(size_t a) const; |
134 | | size_t Hash2(size_t a) const; |
135 | | void InitTable(size_t log_size); |
136 | | // Returns true if `a` was already present in the table. |
137 | | bool AddToTableAndMerge(size_t a); |
138 | | void AddToTable(size_t a); |
139 | | }; |
140 | | |
141 | | Status TokenizeTree(const Tree &tree, std::vector<Token> *tokens, |
142 | | Tree *decoder_tree); |
143 | | |
144 | | void CollectPixelSamples(const Image &image, const ModularOptions &options, |
145 | | uint32_t group_id, |
146 | | std::vector<uint32_t> &group_pixel_count, |
147 | | std::vector<uint32_t> &channel_pixel_count, |
148 | | std::vector<pixel_type> &pixel_samples, |
149 | | std::vector<pixel_type> &diff_samples); |
150 | | |
151 | | Status ComputeBestTree(TreeSamples &tree_samples, float threshold, |
152 | | const std::vector<ModularMultiplierInfo> &mul_info, |
153 | | StaticPropRange static_prop_range, |
154 | | float fast_decode_multiplier, Tree *tree); |
155 | | |
156 | | } // namespace jxl |
157 | | #endif // LIB_JXL_MODULAR_ENCODING_ENC_MA_H_ |