1 // Copyright (c) Team CharLS.
2 // SPDX-License-Identifier: BSD-3-Clause
3
4 #include "default_traits.h"
5 #include "encoder_strategy.h"
6 #include "jls_codec_factory.h"
7 #include "jpegls_preset_coding_parameters.h"
8 #include "lossless_traits.h"
9 #include "scan.h"
10 #include "util.h"
11
12 #include <array>
13 #include <vector>
14
15 namespace charls {
16
17 using std::array;
18 using std::make_unique;
19 using std::unique_ptr;
20 using std::vector;
21
22 namespace {
23
24 // See JPEG-LS standard ISO/IEC 14495-1, A.3.3, golomb_code Segment A.4
quantize_gradient_org(const jpegls_pc_parameters & preset,const int32_t di)25 int8_t quantize_gradient_org(const jpegls_pc_parameters& preset, const int32_t di) noexcept
26 {
27 constexpr int32_t near_lossless{};
28
29 if (di <= -preset.threshold3)
30 return -4;
31 if (di <= -preset.threshold2)
32 return -3;
33 if (di <= -preset.threshold1)
34 return -2;
35 if (di < -near_lossless)
36 return -1;
37 if (di <= near_lossless)
38 return 0;
39 if (di < preset.threshold1)
40 return 1;
41 if (di < preset.threshold2)
42 return 2;
43 if (di < preset.threshold3)
44 return 3;
45
46 return 4;
47 }
48
create_quantize_lut_lossless(const int32_t bit_count)49 vector<int8_t> create_quantize_lut_lossless(const int32_t bit_count)
50 {
51 const jpegls_pc_parameters preset{compute_default((1 << static_cast<uint32_t>(bit_count)) - 1, 0)};
52 const int32_t range{preset.maximum_sample_value + 1};
53
54 vector<int8_t> lut(static_cast<size_t>(range) * 2);
55 for (size_t i{}; i < lut.size(); ++i)
56 {
57 lut[i] = quantize_gradient_org(preset, static_cast<int32_t>(i) - range);
58 }
59
60 return lut;
61 }
62
63 template<typename Strategy, typename Traits>
make_codec(const Traits & traits,const frame_info & frame_info,const coding_parameters & parameters)64 unique_ptr<Strategy> make_codec(const Traits& traits, const frame_info& frame_info, const coding_parameters& parameters)
65 {
66 return make_unique<charls::jls_codec<Traits, Strategy>>(traits, frame_info, parameters);
67 }
68
69 } // namespace
70
71
72 // Lookup tables to replace code with lookup tables.
73 // To avoid threading issues, all tables are created when the program is loaded.
74
75 // Lookup table: decode symbols that are smaller or equal to 8 bit (16 tables for each value of k)
76 // NOLINTNEXTLINE(clang-diagnostic-global-constructors)
77 const array<golomb_code_table, max_k_value> decoding_tables{
78 initialize_table(0), initialize_table(1), initialize_table(2), initialize_table(3),
79 initialize_table(4), initialize_table(5), initialize_table(6), initialize_table(7),
80 initialize_table(8), initialize_table(9), initialize_table(10), initialize_table(11),
81 initialize_table(12), initialize_table(13), initialize_table(14), initialize_table(15)};
82
83 // Lookup tables: sample differences to bin indexes.
84 // NOLINTNEXTLINE(clang-diagnostic-global-constructors)
85 const vector<int8_t> quantization_lut_lossless_8{create_quantize_lut_lossless(8)};
86
87 // NOLINTNEXTLINE(clang-diagnostic-global-constructors)
88 const vector<int8_t> quantization_lut_lossless_10{create_quantize_lut_lossless(10)};
89
90 // NOLINTNEXTLINE(clang-diagnostic-global-constructors)
91 const vector<int8_t> quantization_lut_lossless_12{create_quantize_lut_lossless(12)};
92
93 // NOLINTNEXTLINE(clang-diagnostic-global-constructors)
94 const vector<int8_t> quantization_lut_lossless_16{create_quantize_lut_lossless(16)};
95
96
97 template<typename Strategy>
create_codec(const frame_info & frame,const coding_parameters & parameters,const jpegls_pc_parameters & preset_coding_parameters)98 unique_ptr<Strategy> jls_codec_factory<Strategy>::create_codec(const frame_info& frame, const coding_parameters& parameters,
99 const jpegls_pc_parameters& preset_coding_parameters)
100 {
101 unique_ptr<Strategy> codec;
102
103 if (preset_coding_parameters.reset_value == 0 || preset_coding_parameters.reset_value == default_reset_value)
104 {
105 codec = try_create_optimized_codec(frame, parameters);
106 }
107
108 if (!codec)
109 {
110 if (frame.bits_per_sample <= 8)
111 {
112 default_traits<uint8_t, uint8_t> traits(
113 static_cast<int32_t>(calculate_maximum_sample_value(frame.bits_per_sample)), parameters.near_lossless,
114 preset_coding_parameters.reset_value);
115 traits.maximum_sample_value = preset_coding_parameters.maximum_sample_value;
116 codec = make_unique<jls_codec<default_traits<uint8_t, uint8_t>, Strategy>>(traits, frame, parameters);
117 }
118 else
119 {
120 default_traits<uint16_t, uint16_t> traits(
121 static_cast<int32_t>(calculate_maximum_sample_value(frame.bits_per_sample)), parameters.near_lossless,
122 preset_coding_parameters.reset_value);
123 traits.maximum_sample_value = preset_coding_parameters.maximum_sample_value;
124 codec = make_unique<jls_codec<default_traits<uint16_t, uint16_t>, Strategy>>(traits, frame, parameters);
125 }
126 }
127
128 codec->set_presets(preset_coding_parameters);
129 return codec;
130 }
131
132 template<typename Strategy>
try_create_optimized_codec(const frame_info & frame,const coding_parameters & parameters)133 unique_ptr<Strategy> jls_codec_factory<Strategy>::try_create_optimized_codec(const frame_info& frame,
134 const coding_parameters& parameters)
135 {
136 if (parameters.interleave_mode == interleave_mode::sample && frame.component_count != 3 && frame.component_count != 4)
137 return nullptr;
138
139 #ifndef DISABLE_SPECIALIZATIONS
140
141 // optimized lossless versions common formats
142 if (parameters.near_lossless == 0)
143 {
144 if (parameters.interleave_mode == interleave_mode::sample)
145 {
146 if (frame.component_count == 3 && frame.bits_per_sample == 8)
147 return make_codec<Strategy>(lossless_traits<triplet<uint8_t>, 8>(), frame, parameters);
148 if (frame.component_count == 4 && frame.bits_per_sample == 8)
149 return make_codec<Strategy>(lossless_traits<quad<uint8_t>, 8>(), frame, parameters);
150 }
151 else
152 {
153 switch (frame.bits_per_sample)
154 {
155 case 8:
156 return make_codec<Strategy>(lossless_traits<uint8_t, 8>(), frame, parameters);
157 case 12:
158 return make_codec<Strategy>(lossless_traits<uint16_t, 12>(), frame, parameters);
159 case 16:
160 return make_codec<Strategy>(lossless_traits<uint16_t, 16>(), frame, parameters);
161 default:
162 break;
163 }
164 }
165 }
166
167 #endif
168
169 const auto maxval = static_cast<int>(calculate_maximum_sample_value(frame.bits_per_sample));
170
171 if (frame.bits_per_sample <= 8)
172 {
173 if (parameters.interleave_mode == interleave_mode::sample)
174 {
175 if (frame.component_count == 3)
176 {
177 return make_codec<Strategy>(default_traits<uint8_t, triplet<uint8_t>>(maxval, parameters.near_lossless),
178 frame, parameters);
179 }
180
181 if (frame.component_count == 4)
182 {
183 return make_codec<Strategy>(default_traits<uint8_t, quad<uint8_t>>(maxval, parameters.near_lossless), frame,
184 parameters);
185 }
186 }
187
188 return make_codec<Strategy>(default_traits<uint8_t, uint8_t>(maxval, parameters.near_lossless), frame, parameters);
189 }
190 if (frame.bits_per_sample <= 16)
191 {
192 if (parameters.interleave_mode == interleave_mode::sample)
193 {
194 if (frame.component_count == 3)
195 {
196 return make_codec<Strategy>(default_traits<uint16_t, triplet<uint16_t>>(maxval, parameters.near_lossless),
197 frame, parameters);
198 }
199
200 if (frame.component_count == 4)
201 {
202 return make_codec<Strategy>(default_traits<uint16_t, quad<uint16_t>>(maxval, parameters.near_lossless),
203 frame, parameters);
204 }
205 }
206
207 return make_codec<Strategy>(default_traits<uint16_t, uint16_t>(maxval, parameters.near_lossless), frame, parameters);
208 }
209 return nullptr;
210 }
211
212
213 template class jls_codec_factory<decoder_strategy>;
214 template class jls_codec_factory<encoder_strategy>;
215
216 } // namespace charls
217