/src/libjxl/lib/jxl/fields.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_FIELDS_H_ |
7 | | #define LIB_JXL_FIELDS_H_ |
8 | | |
9 | | // Forward/backward-compatible 'bundles' with auto-serialized 'fields'. |
10 | | |
11 | | #include <cstddef> |
12 | | #include <cstdint> |
13 | | #include <cstdlib> |
14 | | #include <cstring> |
15 | | |
16 | | #include "lib/jxl/base/compiler_specific.h" |
17 | | #include "lib/jxl/base/status.h" |
18 | | #include "lib/jxl/dec_bit_reader.h" |
19 | | #include "lib/jxl/field_encodings.h" |
20 | | |
21 | | namespace jxl { |
22 | | |
23 | | struct AuxOut; |
24 | | struct BitWriter; |
25 | | |
26 | | // Integer coders: BitsCoder (raw), U32Coder (table), U64Coder (varint). |
27 | | |
28 | | // Reads/writes a given (fixed) number of bits <= 32. |
29 | | namespace BitsCoder { |
30 | | size_t MaxEncodedBits(size_t bits); |
31 | | |
32 | | Status CanEncode(size_t bits, uint32_t value, |
33 | | size_t* JXL_RESTRICT encoded_bits); |
34 | | |
35 | | uint32_t Read(size_t bits, BitReader* JXL_RESTRICT reader); |
36 | | |
37 | | // Returns false if the value is too large to encode. |
38 | | Status Write(size_t bits, uint32_t value, BitWriter* JXL_RESTRICT writer); |
39 | | } // namespace BitsCoder |
40 | | |
41 | | // Encodes u32 using a lookup table and/or extra bits, governed by a per-field |
42 | | // encoding `enc` which consists of four distributions `d` chosen via a 2-bit |
43 | | // selector (least significant = 0). Each d may have two modes: |
44 | | // - direct: if d.IsDirect(), the value is d.Direct(); |
45 | | // - offset: the value is derived from d.ExtraBits() extra bits plus d.Offset(); |
46 | | // This encoding is denser than Exp-Golomb or Gamma codes when both small and |
47 | | // large values occur. |
48 | | // |
49 | | // Examples: |
50 | | // Direct: U32Enc(Val(8), Val(16), Val(32), Bits(6)), value 32 => 10b. |
51 | | // Offset: U32Enc(Val(0), BitsOffset(1, 1), BitsOffset(2, 3), BitsOffset(8, 8)) |
52 | | // defines the following prefix code: |
53 | | // 00 -> 0 |
54 | | // 01x -> 1..2 |
55 | | // 10xx -> 3..7 |
56 | | // 11xxxxxxxx -> 8..263 |
57 | | namespace U32Coder { |
58 | | size_t MaxEncodedBits(U32Enc enc); |
59 | | Status CanEncode(U32Enc enc, uint32_t value, size_t* JXL_RESTRICT encoded_bits); |
60 | | uint32_t Read(U32Enc enc, BitReader* JXL_RESTRICT reader); |
61 | | |
62 | | // Returns false if the value is too large to encode. |
63 | | Status Write(U32Enc enc, uint32_t value, BitWriter* JXL_RESTRICT writer); |
64 | | |
65 | | // "private" |
66 | | Status ChooseSelector(U32Enc enc, uint32_t value, |
67 | | uint32_t* JXL_RESTRICT selector, |
68 | | size_t* JXL_RESTRICT total_bits); |
69 | | } // namespace U32Coder |
70 | | |
71 | | // Encodes 64-bit unsigned integers with a fixed distribution, taking 2 bits |
72 | | // to encode 0, 6 bits to encode 1 to 16, 10 bits to encode 17 to 272, 15 bits |
73 | | // to encode up to 4095, and on the order of log2(value) * 1.125 bits for |
74 | | // larger values. |
75 | | namespace U64Coder { |
76 | 0 | constexpr size_t MaxEncodedBits() { return 2 + 12 + 6 * (8 + 1) + (4 + 1); } |
77 | | |
78 | | uint64_t Read(BitReader* JXL_RESTRICT reader); |
79 | | |
80 | | // Returns false if the value is too large to encode. |
81 | | Status Write(uint64_t value, BitWriter* JXL_RESTRICT writer); |
82 | | |
83 | | // Can always encode, but useful because it also returns bit size. |
84 | | Status CanEncode(uint64_t value, size_t* JXL_RESTRICT encoded_bits); |
85 | | } // namespace U64Coder |
86 | | |
87 | | // IEEE 754 half-precision (binary16). Refuses to read/write NaN/Inf. |
88 | | namespace F16Coder { |
89 | 0 | constexpr size_t MaxEncodedBits() { return 16; } |
90 | | |
91 | | // Returns false if the bit representation is NaN or infinity |
92 | | Status Read(BitReader* JXL_RESTRICT reader, float* JXL_RESTRICT value); |
93 | | |
94 | | // Returns false if the value is too large to encode. |
95 | | Status Write(float value, BitWriter* JXL_RESTRICT writer); |
96 | | Status CanEncode(float value, size_t* JXL_RESTRICT encoded_bits); |
97 | | } // namespace F16Coder |
98 | | |
99 | | // A "bundle" is a forward- and backward compatible collection of fields. |
100 | | // They are used for SizeHeader/FrameHeader/GroupHeader. Bundles can be |
101 | | // extended by appending(!) fields. Optional fields may be omitted from the |
102 | | // bitstream by conditionally visiting them. When reading new bitstreams with |
103 | | // old code, we skip unknown fields at the end of the bundle. This requires |
104 | | // storing the amount of extra appended bits, and that fields are visited in |
105 | | // chronological order of being added to the format, because old decoders |
106 | | // cannot skip some future fields and resume reading old fields. Similarly, |
107 | | // new readers query bits in an "extensions" field to skip (groups of) fields |
108 | | // not present in old bitstreams. Note that each bundle must include an |
109 | | // "extensions" field prior to freezing the format, otherwise it cannot be |
110 | | // extended. |
111 | | // |
112 | | // To ensure interoperability, there will be no opaque fields. |
113 | | // |
114 | | // HOWTO: |
115 | | // - basic usage: define a struct with member variables ("fields") and a |
116 | | // VisitFields(v) member function that calls v->U32/Bool etc. for each |
117 | | // field, specifying their default values. The ctor must call |
118 | | // Bundle::Init(this). |
119 | | // |
120 | | // - print a trace of visitors: ensure each bundle has a static Name() member |
121 | | // function, and change Bundle::Print* to return true. |
122 | | // |
123 | | // - optional fields: in VisitFields, add if (v->Conditional(your_condition)) |
124 | | // { v->Bool(default, &field); }. This prevents reading/writing field |
125 | | // if !your_condition, which is typically computed from a prior field. |
126 | | // WARNING: to ensure all fields are initialized, do not add an else branch; |
127 | | // instead add another if (v->Conditional(!your_condition)). |
128 | | // |
129 | | // - repeated fields: for dynamic sizes, use e.g. std::vector and in |
130 | | // VisitFields, if (v->IsReading()) field.resize(size) before accessing field. |
131 | | // For static or bounded sizes, use an array or std::array. In all cases, |
132 | | // simply visit each array element as if it were a normal field. |
133 | | // |
134 | | // - nested bundles: add a bundle as a normal field and in VisitFields call |
135 | | // JXL_RETURN_IF_ERROR(v->VisitNested(&nested)); |
136 | | // |
137 | | // - allow future extensions: define a "uint64_t extensions" field and call |
138 | | // v->BeginExtensions(&extensions) after visiting all non-extension fields, |
139 | | // and `return v->EndExtensions();` after the last extension field. |
140 | | // |
141 | | // - encode an entire bundle in one bit if ALL its fields equal their default |
142 | | // values: add a "mutable bool all_default" field and as the first visitor: |
143 | | // if (v->AllDefault(*this, &all_default)) { |
144 | | // // Overwrite all serialized fields, but not any nonserialized_*. |
145 | | // v->SetDefault(this); |
146 | | // return true; |
147 | | // } |
148 | | // Note: if extensions are present, AllDefault() == false. |
149 | | |
150 | | namespace Bundle { |
151 | | constexpr size_t kMaxExtensions = 64; // bits in u64 |
152 | | |
153 | | // Initializes fields to the default values. It is not recursive to nested |
154 | | // fields, this function is intended to be called in the constructors so |
155 | | // each nested field will already Init itself. |
156 | | void Init(Fields* JXL_RESTRICT fields); |
157 | | |
158 | | // Similar to Init, but recursive to nested fields. |
159 | | void SetDefault(Fields* JXL_RESTRICT fields); |
160 | | |
161 | | // Returns whether ALL fields (including `extensions`, if present) are equal |
162 | | // to their default value. |
163 | | bool AllDefault(const Fields& fields); |
164 | | |
165 | | // Returns max number of bits required to encode a T. |
166 | | size_t MaxBits(const Fields& fields); |
167 | | |
168 | | // Returns whether a header's fields can all be encoded, i.e. they have a |
169 | | // valid representation. If so, "*total_bits" is the exact number of bits |
170 | | // required. Called by Write. |
171 | | Status CanEncode(const Fields& fields, size_t* JXL_RESTRICT extension_bits, |
172 | | size_t* JXL_RESTRICT total_bits); |
173 | | |
174 | | Status Read(BitReader* reader, Fields* JXL_RESTRICT fields); |
175 | | |
176 | | // Returns whether enough bits are available to fully read this bundle using |
177 | | // Read. Also returns true in case of a codestream error (other than not being |
178 | | // large enough): that means enough bits are available to determine there's an |
179 | | // error, use Read to get such error status. |
180 | | // NOTE: this advances the BitReader, a different one pointing back at the |
181 | | // original bit position in the codestream must be created to use Read after |
182 | | // this. |
183 | | bool CanRead(BitReader* reader, Fields* JXL_RESTRICT fields); |
184 | | |
185 | | Status Write(const Fields& fields, BitWriter* JXL_RESTRICT writer, size_t layer, |
186 | | AuxOut* aux_out); |
187 | | } // namespace Bundle |
188 | | |
189 | | // Different subclasses of Visitor are passed to implementations of Fields |
190 | | // throughout their lifetime. Templates used to be used for this but dynamic |
191 | | // polymorphism produces more compact executables than template reification did. |
192 | | class Visitor { |
193 | | public: |
194 | 5.93k | virtual ~Visitor() = default; |
195 | | virtual Status Visit(Fields* fields) = 0; |
196 | | |
197 | | virtual Status Bool(bool default_value, bool* JXL_RESTRICT value) = 0; |
198 | | virtual Status U32(U32Enc, uint32_t, uint32_t*) = 0; |
199 | | |
200 | | // Helper to construct U32Enc from U32Distr. |
201 | | Status U32(const U32Distr d0, const U32Distr d1, const U32Distr d2, |
202 | | const U32Distr d3, const uint32_t default_value, |
203 | 7.06k | uint32_t* JXL_RESTRICT value) { |
204 | 7.06k | return U32(U32Enc(d0, d1, d2, d3), default_value, value); |
205 | 7.06k | } |
206 | | |
207 | | template <typename EnumT> |
208 | 0 | Status Enum(const EnumT default_value, EnumT* JXL_RESTRICT value) { |
209 | 0 | uint32_t u32 = static_cast<uint32_t>(*value); |
210 | | // 00 -> 0 |
211 | | // 01 -> 1 |
212 | | // 10xxxx -> 2..17 |
213 | | // 11yyyyyy -> 18..81 |
214 | 0 | JXL_RETURN_IF_ERROR(U32(Val(0), Val(1), BitsOffset(4, 2), BitsOffset(6, 18), |
215 | 0 | static_cast<uint32_t>(default_value), &u32)); |
216 | 0 | *value = static_cast<EnumT>(u32); |
217 | 0 | return EnumValid(*value); |
218 | 0 | } Unexecuted instantiation: jxl::Status jxl::Visitor::Enum<jxl::cms::TransferFunction>(jxl::cms::TransferFunction, jxl::cms::TransferFunction*) Unexecuted instantiation: jxl::Status jxl::Visitor::Enum<jxl::cms::ColorSpace>(jxl::cms::ColorSpace, jxl::cms::ColorSpace*) Unexecuted instantiation: jxl::Status jxl::Visitor::Enum<jxl::cms::WhitePoint>(jxl::cms::WhitePoint, jxl::cms::WhitePoint*) Unexecuted instantiation: jxl::Status jxl::Visitor::Enum<jxl::cms::Primaries>(jxl::cms::Primaries, jxl::cms::Primaries*) Unexecuted instantiation: jxl::Status jxl::Visitor::Enum<jxl::cms::RenderingIntent>(jxl::cms::RenderingIntent, jxl::cms::RenderingIntent*) Unexecuted instantiation: jxl::Status jxl::Visitor::Enum<jxl::ExtraChannel>(jxl::ExtraChannel, jxl::ExtraChannel*) |
219 | | |
220 | | virtual Status Bits(size_t bits, uint32_t default_value, |
221 | | uint32_t* JXL_RESTRICT value) = 0; |
222 | | virtual Status U64(uint64_t default_value, uint64_t* JXL_RESTRICT value) = 0; |
223 | | virtual Status F16(float default_value, float* JXL_RESTRICT value) = 0; |
224 | | |
225 | | // Returns whether VisitFields should visit some subsequent fields. |
226 | | // "condition" is typically from prior fields, e.g. flags. |
227 | | // Overridden by InitVisitor and MaxBitsVisitor. |
228 | 2.95k | virtual Status Conditional(bool condition) { return condition; } |
229 | | |
230 | | // Overridden by InitVisitor, AllDefaultVisitor and CanEncodeVisitor. |
231 | | virtual Status AllDefault(const Fields& /*fields*/, |
232 | 0 | bool* JXL_RESTRICT all_default) { |
233 | 0 | JXL_RETURN_IF_ERROR(Bool(true, all_default)); |
234 | 0 | return *all_default; |
235 | 0 | } |
236 | | |
237 | 0 | virtual void SetDefault(Fields* /*fields*/) { |
238 | | // Do nothing by default, this is overridden by ReadVisitor. |
239 | 0 | } |
240 | | |
241 | | // Returns the result of visiting a nested Bundle. |
242 | | // Overridden by InitVisitor. |
243 | 0 | virtual Status VisitNested(Fields* fields) { return Visit(fields); } |
244 | | |
245 | | // Overridden by ReadVisitor. Enables dynamically-sized fields. |
246 | 0 | virtual bool IsReading() const { return false; } |
247 | | |
248 | | virtual Status BeginExtensions(uint64_t* JXL_RESTRICT extensions) = 0; |
249 | | virtual Status EndExtensions() = 0; |
250 | | }; |
251 | | |
252 | | namespace fields_internal { |
253 | | // A bundle can be in one of three states concerning extensions: not-begun, |
254 | | // active, ended. Bundles may be nested, so we need a stack of states. |
255 | | class ExtensionStates { |
256 | | public: |
257 | 5.93k | void Push() { |
258 | | // Initial state = not-begun. |
259 | 5.93k | begun_ <<= 1; |
260 | 5.93k | ended_ <<= 1; |
261 | 5.93k | } |
262 | | |
263 | | // Clears current state; caller must check IsEnded beforehand. |
264 | 5.93k | void Pop() { |
265 | 5.93k | begun_ >>= 1; |
266 | 5.93k | ended_ >>= 1; |
267 | 5.93k | } |
268 | | |
269 | | // Returns true if state == active || state == ended. |
270 | 5.91k | Status IsBegun() const { return (begun_ & 1) != 0; } |
271 | | // Returns true if state != not-begun && state != active. |
272 | 0 | Status IsEnded() const { return (ended_ & 1) != 0; } |
273 | | |
274 | 0 | void Begin() { |
275 | 0 | JXL_ASSERT(!IsBegun()); |
276 | 0 | JXL_ASSERT(!IsEnded()); |
277 | 0 | begun_ += 1; |
278 | 0 | } |
279 | | |
280 | 0 | void End() { |
281 | 0 | JXL_ASSERT(IsBegun()); |
282 | 0 | JXL_ASSERT(!IsEnded()); |
283 | 0 | ended_ += 1; |
284 | 0 | } |
285 | | |
286 | | private: |
287 | | // Current state := least-significant bit of begun_ and ended_. |
288 | | uint64_t begun_ = 0; |
289 | | uint64_t ended_ = 0; |
290 | | }; |
291 | | |
292 | | // Visitors generate Init/AllDefault/Read/Write logic for all fields. Each |
293 | | // bundle's VisitFields member function calls visitor->U32 etc. We do not |
294 | | // overload operator() because a function name is easier to search for. |
295 | | |
296 | | class VisitorBase : public Visitor { |
297 | | public: |
298 | 5.93k | explicit VisitorBase() = default; |
299 | 5.93k | ~VisitorBase() override { JXL_ASSERT(depth_ == 0); } |
300 | | |
301 | | // This is the only call site of Fields::VisitFields. |
302 | | // Ensures EndExtensions was called. |
303 | 5.93k | Status Visit(Fields* fields) override { |
304 | 5.93k | depth_ += 1; |
305 | 5.93k | JXL_ASSERT(depth_ <= Bundle::kMaxExtensions); |
306 | 5.93k | extension_states_.Push(); |
307 | | |
308 | 5.93k | const Status ok = fields->VisitFields(this); |
309 | | |
310 | 5.93k | if (ok) { |
311 | | // If VisitFields called BeginExtensions, must also call |
312 | | // EndExtensions. |
313 | 5.91k | JXL_ASSERT(!extension_states_.IsBegun() || extension_states_.IsEnded()); |
314 | 5.91k | } else { |
315 | | // Failed, undefined state: don't care whether EndExtensions was |
316 | | // called. |
317 | 20 | } |
318 | | |
319 | 5.93k | extension_states_.Pop(); |
320 | 5.93k | JXL_ASSERT(depth_ != 0); |
321 | 5.93k | depth_ -= 1; |
322 | | |
323 | 5.93k | return ok; |
324 | 5.93k | } |
325 | | |
326 | | // For visitors accepting a const Visitor, need to const-cast so we can call |
327 | | // the non-const Visitor::VisitFields. NOTE: C is not modified except the |
328 | | // `all_default` field by CanEncodeVisitor. |
329 | 0 | Status VisitConst(const Fields& t) { return Visit(const_cast<Fields*>(&t)); } |
330 | | |
331 | | // Derived types (overridden by InitVisitor because it is unsafe to read |
332 | | // from *value there) |
333 | | |
334 | 2.96k | Status Bool(bool default_value, bool* JXL_RESTRICT value) override { |
335 | 2.96k | uint32_t bits = *value ? 1 : 0; |
336 | 2.96k | JXL_RETURN_IF_ERROR(Bits(1, static_cast<uint32_t>(default_value), &bits)); |
337 | 2.95k | JXL_DASSERT(bits <= 1); |
338 | 2.95k | *value = bits == 1; |
339 | 2.95k | return true; |
340 | 2.95k | } |
341 | | |
342 | | // Overridden by ReadVisitor and WriteVisitor. |
343 | | // Called before any conditional visit based on "extensions". |
344 | | // Overridden by ReadVisitor, CanEncodeVisitor and WriteVisitor. |
345 | 0 | Status BeginExtensions(uint64_t* JXL_RESTRICT extensions) override { |
346 | 0 | JXL_RETURN_IF_ERROR(U64(0, extensions)); |
347 | | |
348 | 0 | extension_states_.Begin(); |
349 | 0 | return true; |
350 | 0 | } |
351 | | |
352 | | // Called after all extension fields (if any). Although non-extension |
353 | | // fields could be visited afterward, we prefer the convention that |
354 | | // extension fields are always the last to be visited. Overridden by |
355 | | // ReadVisitor. |
356 | 0 | Status EndExtensions() override { |
357 | 0 | extension_states_.End(); |
358 | 0 | return true; |
359 | 0 | } |
360 | | |
361 | | private: |
362 | | size_t depth_ = 0; // to check nesting |
363 | | ExtensionStates extension_states_; |
364 | | }; |
365 | | } // namespace fields_internal |
366 | | |
367 | | Status CheckHasEnoughBits(Visitor* visitor, size_t bits); |
368 | | |
369 | | } // namespace jxl |
370 | | |
371 | | #endif // LIB_JXL_FIELDS_H_ |