/src/libjxl/lib/jxl/enc_quant_weights.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_quant_weights.h" |
7 | | |
8 | | #include <stdio.h> |
9 | | #include <stdlib.h> |
10 | | |
11 | | #include <algorithm> |
12 | | #include <cmath> |
13 | | #include <limits> |
14 | | #include <utility> |
15 | | |
16 | | #include "lib/jxl/base/bits.h" |
17 | | #include "lib/jxl/base/status.h" |
18 | | #include "lib/jxl/common.h" |
19 | | #include "lib/jxl/dct_scales.h" |
20 | | #include "lib/jxl/enc_aux_out.h" |
21 | | #include "lib/jxl/enc_bit_writer.h" |
22 | | #include "lib/jxl/enc_modular.h" |
23 | | #include "lib/jxl/fields.h" |
24 | | #include "lib/jxl/image.h" |
25 | | #include "lib/jxl/modular/encoding/encoding.h" |
26 | | #include "lib/jxl/modular/options.h" |
27 | | |
28 | | namespace jxl { |
29 | | |
30 | | struct AuxOut; |
31 | | |
32 | | namespace { |
33 | | |
34 | 0 | Status EncodeDctParams(const DctQuantWeightParams& params, BitWriter* writer) { |
35 | 0 | JXL_ASSERT(params.num_distance_bands >= 1); |
36 | 0 | writer->Write(DctQuantWeightParams::kLog2MaxDistanceBands, |
37 | 0 | params.num_distance_bands - 1); |
38 | 0 | for (size_t c = 0; c < 3; c++) { |
39 | 0 | for (size_t i = 0; i < params.num_distance_bands; i++) { |
40 | 0 | JXL_RETURN_IF_ERROR(F16Coder::Write( |
41 | 0 | params.distance_bands[c][i] * (i == 0 ? (1 / 64.0f) : 1.0f), writer)); |
42 | 0 | } |
43 | 0 | } |
44 | 0 | return true; |
45 | 0 | } |
46 | | |
47 | | Status EncodeQuant(const QuantEncoding& encoding, size_t idx, size_t size_x, |
48 | | size_t size_y, BitWriter* writer, |
49 | 0 | ModularFrameEncoder* modular_frame_encoder) { |
50 | 0 | writer->Write(kLog2NumQuantModes, encoding.mode); |
51 | 0 | size_x *= kBlockDim; |
52 | 0 | size_y *= kBlockDim; |
53 | 0 | switch (encoding.mode) { |
54 | 0 | case QuantEncoding::kQuantModeLibrary: { |
55 | 0 | writer->Write(kCeilLog2NumPredefinedTables, encoding.predefined); |
56 | 0 | break; |
57 | 0 | } |
58 | 0 | case QuantEncoding::kQuantModeID: { |
59 | 0 | for (size_t c = 0; c < 3; c++) { |
60 | 0 | for (size_t i = 0; i < 3; i++) { |
61 | 0 | JXL_RETURN_IF_ERROR( |
62 | 0 | F16Coder::Write(encoding.idweights[c][i] * (1.0f / 64), writer)); |
63 | 0 | } |
64 | 0 | } |
65 | 0 | break; |
66 | 0 | } |
67 | 0 | case QuantEncoding::kQuantModeDCT2: { |
68 | 0 | for (size_t c = 0; c < 3; c++) { |
69 | 0 | for (size_t i = 0; i < 6; i++) { |
70 | 0 | JXL_RETURN_IF_ERROR(F16Coder::Write( |
71 | 0 | encoding.dct2weights[c][i] * (1.0f / 64), writer)); |
72 | 0 | } |
73 | 0 | } |
74 | 0 | break; |
75 | 0 | } |
76 | 0 | case QuantEncoding::kQuantModeDCT4X8: { |
77 | 0 | for (size_t c = 0; c < 3; c++) { |
78 | 0 | JXL_RETURN_IF_ERROR( |
79 | 0 | F16Coder::Write(encoding.dct4x8multipliers[c], writer)); |
80 | 0 | } |
81 | 0 | JXL_RETURN_IF_ERROR(EncodeDctParams(encoding.dct_params, writer)); |
82 | 0 | break; |
83 | 0 | } |
84 | 0 | case QuantEncoding::kQuantModeDCT4: { |
85 | 0 | for (size_t c = 0; c < 3; c++) { |
86 | 0 | for (size_t i = 0; i < 2; i++) { |
87 | 0 | JXL_RETURN_IF_ERROR( |
88 | 0 | F16Coder::Write(encoding.dct4multipliers[c][i], writer)); |
89 | 0 | } |
90 | 0 | } |
91 | 0 | JXL_RETURN_IF_ERROR(EncodeDctParams(encoding.dct_params, writer)); |
92 | 0 | break; |
93 | 0 | } |
94 | 0 | case QuantEncoding::kQuantModeDCT: { |
95 | 0 | JXL_RETURN_IF_ERROR(EncodeDctParams(encoding.dct_params, writer)); |
96 | 0 | break; |
97 | 0 | } |
98 | 0 | case QuantEncoding::kQuantModeRAW: { |
99 | 0 | ModularFrameEncoder::EncodeQuantTable(size_x, size_y, writer, encoding, |
100 | 0 | idx, modular_frame_encoder); |
101 | 0 | break; |
102 | 0 | } |
103 | 0 | case QuantEncoding::kQuantModeAFV: { |
104 | 0 | for (size_t c = 0; c < 3; c++) { |
105 | 0 | for (size_t i = 0; i < 9; i++) { |
106 | 0 | JXL_RETURN_IF_ERROR(F16Coder::Write( |
107 | 0 | encoding.afv_weights[c][i] * (i < 6 ? 1.0f / 64 : 1.0f), writer)); |
108 | 0 | } |
109 | 0 | } |
110 | 0 | JXL_RETURN_IF_ERROR(EncodeDctParams(encoding.dct_params, writer)); |
111 | 0 | JXL_RETURN_IF_ERROR(EncodeDctParams(encoding.dct_params_afv_4x4, writer)); |
112 | 0 | break; |
113 | 0 | } |
114 | 0 | } |
115 | 0 | return true; |
116 | 0 | } |
117 | | |
118 | | } // namespace |
119 | | |
120 | | Status DequantMatricesEncode(const DequantMatrices* matrices, BitWriter* writer, |
121 | | size_t layer, AuxOut* aux_out, |
122 | 0 | ModularFrameEncoder* modular_frame_encoder) { |
123 | 0 | bool all_default = true; |
124 | 0 | const std::vector<QuantEncoding>& encodings = matrices->encodings(); |
125 | |
|
126 | 0 | for (size_t i = 0; i < encodings.size(); i++) { |
127 | 0 | if (encodings[i].mode != QuantEncoding::kQuantModeLibrary || |
128 | 0 | encodings[i].predefined != 0) { |
129 | 0 | all_default = false; |
130 | 0 | } |
131 | 0 | } |
132 | | // TODO(janwas): better bound |
133 | 0 | BitWriter::Allotment allotment(writer, 512 * 1024); |
134 | 0 | writer->Write(1, all_default); |
135 | 0 | if (!all_default) { |
136 | 0 | for (size_t i = 0; i < encodings.size(); i++) { |
137 | 0 | JXL_RETURN_IF_ERROR(EncodeQuant( |
138 | 0 | encodings[i], i, DequantMatrices::required_size_x[i], |
139 | 0 | DequantMatrices::required_size_y[i], writer, modular_frame_encoder)); |
140 | 0 | } |
141 | 0 | } |
142 | 0 | allotment.ReclaimAndCharge(writer, layer, aux_out); |
143 | 0 | return true; |
144 | 0 | } |
145 | | |
146 | | Status DequantMatricesEncodeDC(const DequantMatrices* matrices, |
147 | | BitWriter* writer, size_t layer, |
148 | 0 | AuxOut* aux_out) { |
149 | 0 | bool all_default = true; |
150 | 0 | const float* dc_quant = matrices->DCQuants(); |
151 | 0 | for (size_t c = 0; c < 3; c++) { |
152 | 0 | if (dc_quant[c] != kDCQuant[c]) { |
153 | 0 | all_default = false; |
154 | 0 | } |
155 | 0 | } |
156 | 0 | BitWriter::Allotment allotment(writer, 1 + sizeof(float) * kBitsPerByte * 3); |
157 | 0 | writer->Write(1, all_default); |
158 | 0 | if (!all_default) { |
159 | 0 | for (size_t c = 0; c < 3; c++) { |
160 | 0 | JXL_RETURN_IF_ERROR(F16Coder::Write(dc_quant[c] * 128.0f, writer)); |
161 | 0 | } |
162 | 0 | } |
163 | 0 | allotment.ReclaimAndCharge(writer, layer, aux_out); |
164 | 0 | return true; |
165 | 0 | } |
166 | | |
167 | 0 | void DequantMatricesSetCustomDC(DequantMatrices* matrices, const float* dc) { |
168 | 0 | matrices->SetDCQuant(dc); |
169 | | // Roundtrip encode/decode DC to ensure same values as decoder. |
170 | 0 | BitWriter writer; |
171 | 0 | JXL_CHECK(DequantMatricesEncodeDC(matrices, &writer, 0, nullptr)); |
172 | 0 | writer.ZeroPadToByte(); |
173 | 0 | BitReader br(writer.GetSpan()); |
174 | | // Called only in the encoder: should fail only for programmer errors. |
175 | 0 | JXL_CHECK(matrices->DecodeDC(&br)); |
176 | 0 | JXL_CHECK(br.Close()); |
177 | 0 | } |
178 | | |
179 | 0 | void DequantMatricesScaleDC(DequantMatrices* matrices, const float scale) { |
180 | 0 | float dc[3]; |
181 | 0 | for (size_t c = 0; c < 3; ++c) { |
182 | 0 | dc[c] = matrices->InvDCQuant(c) * (1.0f / scale); |
183 | 0 | } |
184 | 0 | DequantMatricesSetCustomDC(matrices, dc); |
185 | 0 | } |
186 | | |
187 | 0 | void DequantMatricesRoundtrip(DequantMatrices* matrices) { |
188 | | // Do not pass modular en/decoder, as they only change entropy and not |
189 | | // values. |
190 | 0 | BitWriter writer; |
191 | 0 | JXL_CHECK(DequantMatricesEncode(matrices, &writer, 0, nullptr)); |
192 | 0 | writer.ZeroPadToByte(); |
193 | 0 | BitReader br(writer.GetSpan()); |
194 | | // Called only in the encoder: should fail only for programmer errors. |
195 | 0 | JXL_CHECK(matrices->Decode(&br)); |
196 | 0 | JXL_CHECK(br.Close()); |
197 | 0 | } |
198 | | |
199 | | void DequantMatricesSetCustom(DequantMatrices* matrices, |
200 | | const std::vector<QuantEncoding>& encodings, |
201 | 0 | ModularFrameEncoder* encoder) { |
202 | 0 | JXL_ASSERT(encodings.size() == DequantMatrices::kNum); |
203 | 0 | matrices->SetEncodings(encodings); |
204 | 0 | for (size_t i = 0; i < encodings.size(); i++) { |
205 | 0 | if (encodings[i].mode == QuantEncodingInternal::kQuantModeRAW) { |
206 | 0 | encoder->AddQuantTable(DequantMatrices::required_size_x[i] * kBlockDim, |
207 | 0 | DequantMatrices::required_size_y[i] * kBlockDim, |
208 | 0 | encodings[i], i); |
209 | 0 | } |
210 | 0 | } |
211 | 0 | DequantMatricesRoundtrip(matrices); |
212 | 0 | } |
213 | | |
214 | | } // namespace jxl |