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_PARAMS_H_
7 #define LIB_JXL_ENC_PARAMS_H_
8 
9 // Parameters and flags that govern JXL compression.
10 
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include <string>
15 
16 #include "lib/jxl/base/override.h"
17 #include "lib/jxl/butteraugli/butteraugli.h"
18 #include "lib/jxl/frame_header.h"
19 #include "lib/jxl/modular/options.h"
20 
21 namespace jxl {
22 
23 enum class SpeedTier {
24   // Turns on FindBestQuantizationHQ loop. Equivalent to "guetzli" mode.
25   kTortoise = 1,
26   // Turns on FindBestQuantization butteraugli loop.
27   kKitten = 2,
28   // Turns on dots, patches, and spline detection by default, as well as full
29   // context clustering. Default.
30   kSquirrel = 3,
31   // Turns on error diffusion and full AC strategy heuristics. Equivalent to
32   // "fast" mode.
33   kWombat = 4,
34   // Turns on gaborish by default, non-default cmap, initial quant field.
35   kHare = 5,
36   // Turns on simple heuristics for AC strategy, quant field, and clustering;
37   // also enables coefficient reordering.
38   kCheetah = 6,
39   // Turns off most encoder features. Does context clustering.
40   // Modular: uses fixed tree with Weighted predictor.
41   kFalcon = 7,
42   // Currently fastest possible setting for VarDCT.
43   // Modular: uses fixed tree with Gradient predictor.
44   kThunder = 8,
45   // VarDCT: same as kThunder.
46   // Modular: no tree, Gradient predictor, fast histograms
47   kLightning = 9
48 };
49 
ParseSpeedTier(const std::string & s,SpeedTier * out)50 inline bool ParseSpeedTier(const std::string& s, SpeedTier* out) {
51   if (s == "lightning") {
52     *out = SpeedTier::kLightning;
53     return true;
54   } else if (s == "thunder") {
55     *out = SpeedTier::kThunder;
56     return true;
57   } else if (s == "falcon") {
58     *out = SpeedTier::kFalcon;
59     return true;
60   } else if (s == "cheetah") {
61     *out = SpeedTier::kCheetah;
62     return true;
63   } else if (s == "hare") {
64     *out = SpeedTier::kHare;
65     return true;
66   } else if (s == "fast" || s == "wombat") {
67     *out = SpeedTier::kWombat;
68     return true;
69   } else if (s == "squirrel") {
70     *out = SpeedTier::kSquirrel;
71     return true;
72   } else if (s == "kitten") {
73     *out = SpeedTier::kKitten;
74     return true;
75   } else if (s == "guetzli" || s == "tortoise") {
76     *out = SpeedTier::kTortoise;
77     return true;
78   }
79   size_t st = 10 - static_cast<size_t>(strtoull(s.c_str(), nullptr, 0));
80   if (st <= static_cast<size_t>(SpeedTier::kLightning) &&
81       st >= static_cast<size_t>(SpeedTier::kTortoise)) {
82     *out = SpeedTier(st);
83     return true;
84   }
85   return false;
86 }
87 
SpeedTierName(SpeedTier speed_tier)88 inline const char* SpeedTierName(SpeedTier speed_tier) {
89   switch (speed_tier) {
90     case SpeedTier::kLightning:
91       return "lightning";
92     case SpeedTier::kThunder:
93       return "thunder";
94     case SpeedTier::kFalcon:
95       return "falcon";
96     case SpeedTier::kCheetah:
97       return "cheetah";
98     case SpeedTier::kHare:
99       return "hare";
100     case SpeedTier::kWombat:
101       return "wombat";
102     case SpeedTier::kSquirrel:
103       return "squirrel";
104     case SpeedTier::kKitten:
105       return "kitten";
106     case SpeedTier::kTortoise:
107       return "tortoise";
108   }
109   return "INVALID";
110 }
111 
112 // NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding)
113 struct CompressParams {
114   float butteraugli_distance = 1.0f;
115   size_t target_size = 0;
116   float target_bitrate = 0.0f;
117 
118   // 0.0 means search for the adaptive quantization map that matches the
119   // butteraugli distance, positive values mean quantize everywhere with that
120   // value.
121   float uniform_quant = 0.0f;
122   float quant_border_bias = 0.0f;
123 
124   // Try to achieve a maximum pixel-by-pixel error on each channel.
125   bool max_error_mode = false;
126   float max_error[3] = {0.0, 0.0, 0.0};
127 
128   SpeedTier speed_tier = SpeedTier::kSquirrel;
129 
130   // 0 = default.
131   // 1 = slightly worse quality.
132   // 4 = fastest speed, lowest quality
133   // TODO(veluca): hook this up to the C API.
134   size_t decoding_speed_tier = 0;
135 
136   int max_butteraugli_iters = 4;
137 
138   int max_butteraugli_iters_guetzli_mode = 100;
139 
140   ColorTransform color_transform = ColorTransform::kXYB;
141   YCbCrChromaSubsampling chroma_subsampling;
142 
143   // If true, the "modular mode options" members below are used.
144   bool modular_mode = false;
145 
146   // Change group size in modular mode (0=128, 1=256, 2=512, 3=1024).
147   size_t modular_group_size_shift = 1;
148 
149   Override preview = Override::kDefault;
150   Override noise = Override::kDefault;
151   Override dots = Override::kDefault;
152   Override patches = Override::kDefault;
153   Override gaborish = Override::kDefault;
154   int epf = -1;
155 
156   // Progressive mode.
157   bool progressive_mode = false;
158 
159   // Quantized-progressive mode.
160   bool qprogressive_mode = false;
161 
162   // Put center groups first in the bitstream.
163   bool centerfirst = false;
164 
165   // Pixel coordinates of the center. First group will contain that center.
166   size_t center_x = static_cast<size_t>(-1);
167   size_t center_y = static_cast<size_t>(-1);
168 
169   int progressive_dc = -1;
170 
171   // If on: preserve color of invisible pixels (if off: don't care)
172   // Default: on for lossless, off for lossy
173   Override keep_invisible = Override::kDefault;
174 
175   // Progressive-mode saliency.
176   //
177   // How many progressive saliency-encoding steps to perform.
178   // - 1: Encode only DC and lowest-frequency AC. Does not need a saliency-map.
179   // - 2: Encode only DC+LF, dropping all HF AC data.
180   //      Does not need a saliency-map.
181   // - 3: Encode DC+LF+{salient HF}, dropping all non-salient HF data.
182   // - 4: Encode DC+LF+{salient HF}+{other HF}.
183   // - 5: Encode DC+LF+{quantized HF}+{low HF bits}.
184   size_t saliency_num_progressive_steps = 3;
185   // Every saliency-heatmap cell with saliency >= threshold will be considered
186   // as 'salient'. The default value of 0.0 will consider every AC-block
187   // as salient, hence not require a saliency-map, and not actually generate
188   // a 4th progressive step.
189   float saliency_threshold = 0.0f;
190   // Saliency-map (owned by caller).
191   ImageF* saliency_map = nullptr;
192 
193   // Input and output file name. Will be used to provide pluggable saliency
194   // extractor with paths.
195   const char* file_in = nullptr;
196   const char* file_out = nullptr;
197 
198   // Currently unused as of 2020-01.
199   bool clear_metadata = false;
200 
201   // Prints extra information during/after encoding.
202   bool verbose = false;
203 
204   ButteraugliParams ba_params;
205 
206   // Force usage of CfL when doing JPEG recompression. This can have unexpected
207   // effects on the decoded pixels, while still being JPEG-compliant and
208   // allowing reconstruction of the original JPEG.
209   bool force_cfl_jpeg_recompression = true;
210 
211   // Set the noise to what it would approximately be if shooting at the nominal
212   // exposure for a given ISO setting on a 35mm camera.
213   float photon_noise_iso = 0;
214 
215   // modular mode options below
216   ModularOptions options;
217   int responsive = -1;
218   // A pair of <quality, cquality>.
219   std::pair<float, float> quality_pair{100.f, 100.f};
220   int colorspace = -1;
221   // Use Global channel palette if #colors < this percentage of range
222   float channel_colors_pre_transform_percent = 95.f;
223   // Use Local channel palette if #colors < this percentage of range
224   float channel_colors_percent = 80.f;
225   int palette_colors = 1 << 10;  // up to 10-bit palette is probably worthwhile
226   bool lossy_palette = false;
227 
228   // Returns whether these params are lossless as defined by SetLossless();
IsLosslessCompressParams229   bool IsLossless() const {
230     return modular_mode && quality_pair.first == 100 &&
231            quality_pair.second == 100 &&
232            color_transform == jxl::ColorTransform::kNone;
233   }
234 
235   // Sets the parameters required to make the codec lossless.
SetLosslessCompressParams236   void SetLossless() {
237     modular_mode = true;
238     quality_pair.first = 100;
239     quality_pair.second = 100;
240     color_transform = jxl::ColorTransform::kNone;
241   }
242 
243   bool use_new_heuristics = false;
244 
245   // Down/upsample the image before encoding / after decoding by this factor.
246   // The resampling value can also be set to 0 to automatically choose based
247   // on distance, however EncodeFrame doesn't support this, so it is
248   // required to process the CompressParams to set a valid positive resampling
249   // value and altered butteraugli score if this is used.
250   size_t resampling = 1;
251   size_t ec_resampling = 1;
252   // Skip the downsampling before encoding if this is true.
253   bool already_downsampled = false;
254 };
255 
256 static constexpr float kMinButteraugliForDynamicAR = 0.5f;
257 static constexpr float kMinButteraugliForDots = 3.0f;
258 static constexpr float kMinButteraugliToSubtractOriginalPatches = 3.0f;
259 static constexpr float kMinButteraugliDistanceForProgressiveDc = 4.5f;
260 
261 // Always off
262 static constexpr float kMinButteraugliForNoise = 99.0f;
263 
264 // Minimum butteraugli distance the encoder accepts.
265 static constexpr float kMinButteraugliDistance = 0.01f;
266 
267 // Tile size for encoder-side processing. Must be equal to color tile dim in the
268 // current implementation.
269 static constexpr size_t kEncTileDim = 64;
270 static constexpr size_t kEncTileDimInBlocks = kEncTileDim / kBlockDim;
271 
272 }  // namespace jxl
273 
274 #endif  // LIB_JXL_ENC_PARAMS_H_
275