/src/libjxl/lib/jxl/frame_header.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_FRAME_HEADER_H_ |
7 | | #define LIB_JXL_FRAME_HEADER_H_ |
8 | | |
9 | | // Frame header with backward and forward-compatible extension capability and |
10 | | // compressed integer fields. |
11 | | |
12 | | #include <algorithm> |
13 | | #include <array> |
14 | | #include <cstddef> |
15 | | #include <cstdint> |
16 | | #include <string> |
17 | | #include <vector> |
18 | | |
19 | | #include "lib/jxl/base/common.h" |
20 | | #include "lib/jxl/base/compiler_specific.h" |
21 | | #include "lib/jxl/base/status.h" |
22 | | #include "lib/jxl/coeff_order_fwd.h" |
23 | | #include "lib/jxl/common.h" // kMaxNumPasses |
24 | | #include "lib/jxl/dec_bit_reader.h" |
25 | | #include "lib/jxl/field_encodings.h" |
26 | | #include "lib/jxl/fields.h" |
27 | | #include "lib/jxl/frame_dimensions.h" |
28 | | #include "lib/jxl/image_metadata.h" |
29 | | #include "lib/jxl/loop_filter.h" |
30 | | |
31 | | namespace jxl { |
32 | | |
33 | | // TODO(eustas): move to proper place? |
34 | | // Also used by extra channel names. |
35 | | static inline Status VisitNameString(Visitor* JXL_RESTRICT visitor, |
36 | 212k | std::string* name) { |
37 | 212k | uint32_t name_length = static_cast<uint32_t>(name->length()); |
38 | | // Allows layer name lengths up to 1071 bytes |
39 | 212k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(0), Bits(4), BitsOffset(5, 16), |
40 | 212k | BitsOffset(10, 48), 0, &name_length)); |
41 | 212k | if (visitor->IsReading()) { |
42 | 20.2k | name->resize(name_length); |
43 | 20.2k | } |
44 | 349k | for (size_t i = 0; i < name_length; i++) { |
45 | 137k | uint32_t c = static_cast<uint8_t>((*name)[i]); |
46 | 137k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(8, 0, &c)); |
47 | 137k | (*name)[i] = static_cast<char>(c); |
48 | 137k | } |
49 | 212k | return true; |
50 | 212k | } Unexecuted instantiation: fields_fuzzer.cc:jxl::VisitNameString(jxl::Visitor*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) frame_header.cc:jxl::VisitNameString(jxl::Visitor*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) Line | Count | Source | 36 | 624 | std::string* name) { | 37 | 624 | uint32_t name_length = static_cast<uint32_t>(name->length()); | 38 | | // Allows layer name lengths up to 1071 bytes | 39 | 624 | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(0), Bits(4), BitsOffset(5, 16), | 40 | 624 | BitsOffset(10, 48), 0, &name_length)); | 41 | 539 | if (visitor->IsReading()) { | 42 | 145 | name->resize(name_length); | 43 | 145 | } | 44 | 7.29k | for (size_t i = 0; i < name_length; i++) { | 45 | 6.79k | uint32_t c = static_cast<uint8_t>((*name)[i]); | 46 | 6.79k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(8, 0, &c)); | 47 | 6.75k | (*name)[i] = static_cast<char>(c); | 48 | 6.75k | } | 49 | 508 | return true; | 50 | 539 | } |
image_metadata.cc:jxl::VisitNameString(jxl::Visitor*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*) Line | Count | Source | 36 | 212k | std::string* name) { | 37 | 212k | uint32_t name_length = static_cast<uint32_t>(name->length()); | 38 | | // Allows layer name lengths up to 1071 bytes | 39 | 212k | JXL_QUIET_RETURN_IF_ERROR(visitor->U32(Val(0), Bits(4), BitsOffset(5, 16), | 40 | 212k | BitsOffset(10, 48), 0, &name_length)); | 41 | 212k | if (visitor->IsReading()) { | 42 | 20.1k | name->resize(name_length); | 43 | 20.1k | } | 44 | 342k | for (size_t i = 0; i < name_length; i++) { | 45 | 130k | uint32_t c = static_cast<uint8_t>((*name)[i]); | 46 | 130k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(8, 0, &c)); | 47 | 130k | (*name)[i] = static_cast<char>(c); | 48 | 130k | } | 49 | 212k | return true; | 50 | 212k | } |
|
51 | | |
52 | | enum class FrameEncoding : uint32_t { |
53 | | kVarDCT, |
54 | | kModular, |
55 | | }; |
56 | | |
57 | | enum class ColorTransform : uint32_t { |
58 | | kXYB, // Values are encoded with XYB. May only be used if |
59 | | // ImageBundle::xyb_encoded. |
60 | | kNone, // Values are encoded according to the attached color profile. May |
61 | | // only be used if !ImageBundle::xyb_encoded. |
62 | | kYCbCr, // Values are encoded according to the attached color profile, but |
63 | | // transformed to YCbCr. May only be used if |
64 | | // !ImageBundle::xyb_encoded. |
65 | | }; |
66 | | |
67 | 0 | inline std::array<int, 3> JpegOrder(ColorTransform ct, bool is_gray) { |
68 | 0 | if (is_gray) { |
69 | 0 | return {{0, 0, 0}}; |
70 | 0 | } |
71 | 0 | JXL_ASSERT(ct != ColorTransform::kXYB); |
72 | 0 | if (ct == ColorTransform::kYCbCr) { |
73 | 0 | return {{1, 0, 2}}; |
74 | 0 | } else { |
75 | 0 | return {{0, 1, 2}}; |
76 | 0 | } |
77 | 0 | } |
78 | | |
79 | | struct YCbCrChromaSubsampling : public Fields { |
80 | | YCbCrChromaSubsampling(); |
81 | | JXL_FIELDS_NAME(YCbCrChromaSubsampling) |
82 | 0 | size_t HShift(size_t c) const { return maxhs_ - kHShift[channel_mode_[c]]; } |
83 | 0 | size_t VShift(size_t c) const { return maxvs_ - kVShift[channel_mode_[c]]; } |
84 | | |
85 | 406 | Status VisitFields(Visitor* JXL_RESTRICT visitor) override { |
86 | | // TODO(veluca): consider allowing 4x downsamples |
87 | 1.21k | for (uint32_t& ch : channel_mode_) { |
88 | 1.21k | JXL_QUIET_RETURN_IF_ERROR(visitor->Bits(2, 0, &ch)); |
89 | 1.21k | } |
90 | 405 | Recompute(); |
91 | 405 | return true; |
92 | 406 | } |
93 | | |
94 | 0 | uint8_t MaxHShift() const { return maxhs_; } |
95 | 0 | uint8_t MaxVShift() const { return maxvs_; } |
96 | | |
97 | 0 | uint8_t RawHShift(size_t c) const { return kHShift[channel_mode_[c]]; } |
98 | 0 | uint8_t RawVShift(size_t c) const { return kVShift[channel_mode_[c]]; } |
99 | | |
100 | | // Uses JPEG channel order (Y, Cb, Cr). |
101 | 0 | Status Set(const uint8_t* hsample, const uint8_t* vsample) { |
102 | 0 | for (size_t c = 0; c < 3; c++) { |
103 | 0 | size_t cjpeg = c < 2 ? c ^ 1 : c; |
104 | 0 | size_t i = 0; |
105 | 0 | for (; i < 4; i++) { |
106 | 0 | if (1 << kHShift[i] == hsample[cjpeg] && |
107 | 0 | 1 << kVShift[i] == vsample[cjpeg]) { |
108 | 0 | channel_mode_[c] = i; |
109 | 0 | break; |
110 | 0 | } |
111 | 0 | } |
112 | 0 | if (i == 4) { |
113 | 0 | return JXL_FAILURE("Invalid subsample mode"); |
114 | 0 | } |
115 | 0 | } |
116 | 0 | Recompute(); |
117 | 0 | return true; |
118 | 0 | } |
119 | | |
120 | 0 | bool Is444() const { |
121 | 0 | return HShift(0) == 0 && VShift(0) == 0 && // Cb |
122 | 0 | HShift(2) == 0 && VShift(2) == 0 && // Cr |
123 | 0 | HShift(1) == 0 && VShift(1) == 0; // Y |
124 | 0 | } |
125 | | |
126 | 0 | bool Is420() const { |
127 | 0 | return HShift(0) == 1 && VShift(0) == 1 && // Cb |
128 | 0 | HShift(2) == 1 && VShift(2) == 1 && // Cr |
129 | 0 | HShift(1) == 0 && VShift(1) == 0; // Y |
130 | 0 | } |
131 | | |
132 | 0 | bool Is422() const { |
133 | 0 | return HShift(0) == 1 && VShift(0) == 0 && // Cb |
134 | 0 | HShift(2) == 1 && VShift(2) == 0 && // Cr |
135 | 0 | HShift(1) == 0 && VShift(1) == 0; // Y |
136 | 0 | } |
137 | | |
138 | 0 | bool Is440() const { |
139 | 0 | return HShift(0) == 0 && VShift(0) == 1 && // Cb |
140 | 0 | HShift(2) == 0 && VShift(2) == 1 && // Cr |
141 | 0 | HShift(1) == 0 && VShift(1) == 0; // Y |
142 | 0 | } |
143 | | |
144 | 0 | std::string DebugString() const { |
145 | 0 | if (Is444()) return "444"; |
146 | 0 | if (Is420()) return "420"; |
147 | 0 | if (Is422()) return "422"; |
148 | 0 | if (Is440()) return "440"; |
149 | 0 | return "cs" + std::to_string(channel_mode_[0]) + |
150 | 0 | std::to_string(channel_mode_[1]) + std::to_string(channel_mode_[2]); |
151 | 0 | } |
152 | | |
153 | | private: |
154 | 405 | void Recompute() { |
155 | 405 | maxhs_ = 0; |
156 | 405 | maxvs_ = 0; |
157 | 1.21k | for (uint32_t ch : channel_mode_) { |
158 | 1.21k | maxhs_ = std::max(maxhs_, kHShift[ch]); |
159 | 1.21k | maxvs_ = std::max(maxvs_, kVShift[ch]); |
160 | 1.21k | } |
161 | 405 | } |
162 | | static const uint8_t kHShift[4]; |
163 | | static const uint8_t kVShift[4]; |
164 | | uint32_t channel_mode_[3]; |
165 | | uint8_t maxhs_; |
166 | | uint8_t maxvs_; |
167 | | }; |
168 | | |
169 | | // Indicates how to combine the current frame with a previously-saved one. Can |
170 | | // be independently controlled for color and extra channels. Formulas are |
171 | | // indicative and treat alpha as if it is in range 0.0-1.0. In descriptions |
172 | | // below, alpha channel is the extra channel of type alpha used for blending |
173 | | // according to the blend_channel, or fully opaque if there is no alpha channel. |
174 | | // The blending specified here is used for performing blending *after* color |
175 | | // transforms - in linear sRGB if blending a XYB-encoded frame on another |
176 | | // XYB-encoded frame, in sRGB if blending a frame with kColorSpace == kSRGB, or |
177 | | // in the original colorspace otherwise. Blending in XYB or YCbCr is done by |
178 | | // using patches. |
179 | | enum class BlendMode { |
180 | | // The new values (in the crop) replace the old ones: sample = new |
181 | | kReplace = 0, |
182 | | // The new values (in the crop) get added to the old ones: sample = old + new |
183 | | kAdd = 1, |
184 | | // The new values (in the crop) replace the old ones if alpha>0: |
185 | | // For the alpha channel that is used as source: |
186 | | // alpha = old + new * (1 - old) |
187 | | // For other channels if !alpha_associated: |
188 | | // sample = ((1 - new_alpha) * old * old_alpha + new_alpha * new) / alpha |
189 | | // For other channels if alpha_associated: |
190 | | // sample = (1 - new_alpha) * old + new |
191 | | // The alpha formula applies to the alpha used for the division in the other |
192 | | // channels formula, and applies to the alpha channel itself if its |
193 | | // blend_channel value matches itself. |
194 | | kBlend = 2, |
195 | | // The new values (in the crop) are added to the old ones if alpha>0: |
196 | | // For the alpha channel that is used as source: |
197 | | // sample = sample = old + new * (1 - old) |
198 | | // For other channels: sample = old + alpha * new |
199 | | kAlphaWeightedAdd = 3, |
200 | | // The new values (in the crop) get multiplied by the old ones: |
201 | | // sample = old * new |
202 | | // The range of the new value matters for multiplication purposes, and its |
203 | | // nominal range of 0..1 is computed the same way as this is done for the |
204 | | // alpha values in kBlend and kAlphaWeightedAdd. |
205 | | // If using kMul as a blend mode for color channels, no color transform is |
206 | | // performed on the current frame. |
207 | | kMul = 4, |
208 | | }; |
209 | | |
210 | | struct BlendingInfo : public Fields { |
211 | | BlendingInfo(); |
212 | | JXL_FIELDS_NAME(BlendingInfo) |
213 | | Status VisitFields(Visitor* JXL_RESTRICT visitor) override; |
214 | | BlendMode mode; |
215 | | // Which extra channel to use as alpha channel for blending, only encoded |
216 | | // for blend modes that involve alpha and if there are more than 1 extra |
217 | | // channels. |
218 | | uint32_t alpha_channel; |
219 | | // Clamp alpha or channel values to 0-1 range. |
220 | | bool clamp; |
221 | | // Frame ID to copy from (0-3). Only encoded if blend_mode is not kReplace. |
222 | | uint32_t source; |
223 | | |
224 | | std::string DebugString() const; |
225 | | |
226 | | size_t nonserialized_num_extra_channels = 0; |
227 | | bool nonserialized_is_partial_frame = false; |
228 | | }; |
229 | | |
230 | | // Origin of the current frame. Not present for frames of type |
231 | | // kOnlyPatches. |
232 | | struct FrameOrigin { |
233 | | int32_t x0, y0; // can be negative. |
234 | | }; |
235 | | |
236 | | // Size of the current frame. |
237 | | struct FrameSize { |
238 | | uint32_t xsize, ysize; |
239 | | }; |
240 | | |
241 | | // AnimationFrame defines duration of animation frames. |
242 | | struct AnimationFrame : public Fields { |
243 | | explicit AnimationFrame(const CodecMetadata* metadata); |
244 | | JXL_FIELDS_NAME(AnimationFrame) |
245 | | |
246 | | Status VisitFields(Visitor* JXL_RESTRICT visitor) override; |
247 | | |
248 | | // How long to wait [in ticks, see Animation{}] after rendering. |
249 | | // May be 0 if the current frame serves as a foundation for another frame. |
250 | | uint32_t duration; |
251 | | |
252 | | uint32_t timecode; // 0xHHMMSSFF |
253 | | |
254 | | // Must be set to the one ImageMetadata acting as the full codestream header, |
255 | | // with correct xyb_encoded, list of extra channels, etc... |
256 | | const CodecMetadata* nonserialized_metadata = nullptr; |
257 | | }; |
258 | | |
259 | | // For decoding to lower resolutions. Only used for kRegular frames. |
260 | | struct Passes : public Fields { |
261 | | Passes(); |
262 | | JXL_FIELDS_NAME(Passes) |
263 | | |
264 | | Status VisitFields(Visitor* JXL_RESTRICT visitor) override; |
265 | | |
266 | 0 | void GetDownsamplingBracket(size_t pass, int& minShift, int& maxShift) const { |
267 | 0 | maxShift = 2; |
268 | 0 | minShift = 3; |
269 | 0 | for (size_t i = 0;; i++) { |
270 | 0 | for (uint32_t j = 0; j < num_downsample; ++j) { |
271 | 0 | if (i == last_pass[j]) { |
272 | 0 | if (downsample[j] == 8) minShift = 3; |
273 | 0 | if (downsample[j] == 4) minShift = 2; |
274 | 0 | if (downsample[j] == 2) minShift = 1; |
275 | 0 | if (downsample[j] == 1) minShift = 0; |
276 | 0 | } |
277 | 0 | } |
278 | 0 | if (i == num_passes - 1) minShift = 0; |
279 | 0 | if (i == pass) return; |
280 | 0 | maxShift = minShift - 1; |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | 0 | uint32_t GetDownsamplingTargetForCompletedPasses(uint32_t num_p) const { |
285 | 0 | if (num_p >= num_passes) return 1; |
286 | 0 | uint32_t retval = 8; |
287 | 0 | for (uint32_t i = 0; i < num_downsample; ++i) { |
288 | 0 | if (num_p > last_pass[i]) { |
289 | 0 | retval = std::min(retval, downsample[i]); |
290 | 0 | } |
291 | 0 | } |
292 | 0 | return retval; |
293 | 0 | } |
294 | | |
295 | | std::string DebugString() const; |
296 | | |
297 | | uint32_t num_passes; // <= kMaxNumPasses |
298 | | uint32_t num_downsample; // <= num_passes |
299 | | |
300 | | // Array of num_downsample pairs. downsample=1/last_pass=num_passes-1 and |
301 | | // downsample=8/last_pass=0 need not be specified; they are implicit. |
302 | | uint32_t downsample[kMaxNumPasses]; |
303 | | uint32_t last_pass[kMaxNumPasses]; |
304 | | // Array of shift values for each pass. It is implicitly assumed to be 0 for |
305 | | // the last pass. |
306 | | uint32_t shift[kMaxNumPasses]; |
307 | | }; |
308 | | |
309 | | enum FrameType { |
310 | | // A "regular" frame: might be a crop, and will be blended on a previous |
311 | | // frame, if any, and displayed or blended in future frames. |
312 | | kRegularFrame = 0, |
313 | | // A DC frame: this frame is downsampled and will be *only* used as the DC of |
314 | | // a future frame and, possibly, for previews. Cannot be cropped, blended, or |
315 | | // referenced by patches or blending modes. Frames that *use* a DC frame |
316 | | // cannot have non-default sizes either. |
317 | | kDCFrame = 1, |
318 | | // A PatchesSource frame: this frame will be only used as a source frame for |
319 | | // taking patches. Can be cropped, but cannot have non-(0, 0) x0 and y0. |
320 | | kReferenceOnly = 2, |
321 | | // Same as kRegularFrame, but not used for progressive rendering. This also |
322 | | // implies no early display of DC. |
323 | | kSkipProgressive = 3, |
324 | | }; |
325 | | |
326 | | // Image/frame := one of more of these, where the last has is_last = true. |
327 | | // Starts at a byte-aligned address "a"; the next pass starts at "a + size". |
328 | | struct FrameHeader : public Fields { |
329 | | // Optional postprocessing steps. These flags are the source of truth; |
330 | | // Override must set/clear them rather than change their meaning. Values |
331 | | // chosen such that typical flags == 0 (encoded in only two bits). |
332 | | enum Flags { |
333 | | // Often but not always off => low bit value: |
334 | | |
335 | | // Inject noise into decoded output. |
336 | | kNoise = 1, |
337 | | |
338 | | // Overlay patches. |
339 | | kPatches = 2, |
340 | | |
341 | | // 4, 8 = reserved for future sometimes-off |
342 | | |
343 | | // Overlay splines. |
344 | | kSplines = 16, |
345 | | |
346 | | kUseDcFrame = 32, // Implies kSkipAdaptiveDCSmoothing. |
347 | | |
348 | | // 64 = reserved for future often-off |
349 | | |
350 | | // Almost always on => negated: |
351 | | |
352 | | kSkipAdaptiveDCSmoothing = 128, |
353 | | }; |
354 | | |
355 | | explicit FrameHeader(const CodecMetadata* metadata); |
356 | | JXL_FIELDS_NAME(FrameHeader) |
357 | | |
358 | | Status VisitFields(Visitor* JXL_RESTRICT visitor) override; |
359 | | |
360 | | // Sets/clears `flag` based upon `condition`. |
361 | 0 | void UpdateFlag(const bool condition, const uint64_t flag) { |
362 | 0 | if (condition) { |
363 | 0 | flags |= flag; |
364 | 0 | } else { |
365 | 0 | flags &= ~flag; |
366 | 0 | } |
367 | 0 | } |
368 | | |
369 | | // Returns true if this frame is supposed to be saved for future usage by |
370 | | // other frames. |
371 | 607 | bool CanBeReferenced() const { |
372 | | // DC frames cannot be referenced. The last frame cannot be referenced. A |
373 | | // duration 0 frame makes little sense if it is not referenced. A |
374 | | // non-duration 0 frame may or may not be referenced. |
375 | 607 | return !is_last && frame_type != FrameType::kDCFrame && |
376 | 607 | (animation_frame.duration == 0 || save_as_reference != 0); |
377 | 607 | } |
378 | | |
379 | | mutable bool all_default; |
380 | | |
381 | | // Always present |
382 | | FrameEncoding encoding; |
383 | | // Some versions of UBSAN complain in VisitFrameType if not initialized. |
384 | | FrameType frame_type = FrameType::kRegularFrame; |
385 | | |
386 | | uint64_t flags; |
387 | | |
388 | | ColorTransform color_transform; |
389 | | YCbCrChromaSubsampling chroma_subsampling; |
390 | | |
391 | | uint32_t group_size_shift; // only if encoding == kModular; |
392 | | |
393 | | uint32_t x_qm_scale; // only if VarDCT and color_transform == kXYB |
394 | | uint32_t b_qm_scale; // only if VarDCT and color_transform == kXYB |
395 | | |
396 | | std::string name; |
397 | | |
398 | | // Skipped for kReferenceOnly. |
399 | | Passes passes; |
400 | | |
401 | | // Skipped for kDCFrame |
402 | | bool custom_size_or_origin; |
403 | | FrameSize frame_size; |
404 | | |
405 | | // upsampling factors for color and extra channels. |
406 | | // Upsampling is always performed before applying any inverse color transform. |
407 | | // Skipped (1) if kUseDCFrame |
408 | | uint32_t upsampling; |
409 | | std::vector<uint32_t> extra_channel_upsampling; |
410 | | |
411 | | // Only for kRegular frames. |
412 | | FrameOrigin frame_origin; |
413 | | |
414 | | BlendingInfo blending_info; |
415 | | std::vector<BlendingInfo> extra_channel_blending_info; |
416 | | |
417 | | // Animation info for this frame. |
418 | | AnimationFrame animation_frame; |
419 | | |
420 | | // This is the last frame. |
421 | | bool is_last; |
422 | | |
423 | | // ID to refer to this frame with. 0-3, not present if kDCFrame. |
424 | | // 0 has a special meaning for kRegular frames of nonzero duration: it defines |
425 | | // a frame that will not be referenced in the future. |
426 | | uint32_t save_as_reference; |
427 | | |
428 | | // Whether to save this frame before or after the color transform. A frame |
429 | | // that is saved before the color tansform can only be used for blending |
430 | | // through patches. On the contrary, a frame that is saved after the color |
431 | | // transform can only be used for blending through blending modes. |
432 | | // Irrelevant for extra channel blending. Can only be true if |
433 | | // blending_info.mode == kReplace and this is not a partial kRegularFrame; if |
434 | | // this is a DC frame, it is always true. |
435 | | bool save_before_color_transform; |
436 | | |
437 | | uint32_t dc_level; // 1-4 if kDCFrame (0 otherwise). |
438 | | |
439 | | // Must be set to the one ImageMetadata acting as the full codestream header, |
440 | | // with correct xyb_encoded, list of extra channels, etc... |
441 | | const CodecMetadata* nonserialized_metadata = nullptr; |
442 | | |
443 | | // NOTE: This is ignored by AllDefault. |
444 | | LoopFilter loop_filter; |
445 | | |
446 | | bool nonserialized_is_preview = false; |
447 | | |
448 | 639 | size_t default_xsize() const { |
449 | 639 | if (!nonserialized_metadata) return 0; |
450 | 639 | if (nonserialized_is_preview) { |
451 | 0 | return nonserialized_metadata->m.preview_size.xsize(); |
452 | 0 | } |
453 | 639 | return nonserialized_metadata->xsize(); |
454 | 639 | } |
455 | | |
456 | 639 | size_t default_ysize() const { |
457 | 639 | if (!nonserialized_metadata) return 0; |
458 | 639 | if (nonserialized_is_preview) { |
459 | 0 | return nonserialized_metadata->m.preview_size.ysize(); |
460 | 0 | } |
461 | 639 | return nonserialized_metadata->ysize(); |
462 | 639 | } |
463 | | |
464 | 0 | FrameDimensions ToFrameDimensions() const { |
465 | 0 | size_t xsize = default_xsize(); |
466 | 0 | size_t ysize = default_ysize(); |
467 | 0 |
|
468 | 0 | xsize = frame_size.xsize ? frame_size.xsize : xsize; |
469 | 0 | ysize = frame_size.ysize ? frame_size.ysize : ysize; |
470 | 0 |
|
471 | 0 | if (dc_level != 0) { |
472 | 0 | xsize = DivCeil(xsize, 1 << (3 * dc_level)); |
473 | 0 | ysize = DivCeil(ysize, 1 << (3 * dc_level)); |
474 | 0 | } |
475 | 0 |
|
476 | 0 | FrameDimensions frame_dim; |
477 | 0 | frame_dim.Set(xsize, ysize, group_size_shift, |
478 | 0 | chroma_subsampling.MaxHShift(), |
479 | 0 | chroma_subsampling.MaxVShift(), |
480 | 0 | encoding == FrameEncoding::kModular, upsampling); |
481 | 0 | return frame_dim; |
482 | 0 | } |
483 | | |
484 | | // True if a color transform should be applied to this frame. |
485 | 0 | bool needs_color_transform() const { |
486 | 0 | return !save_before_color_transform || |
487 | 0 | frame_type == FrameType::kRegularFrame || |
488 | 0 | frame_type == FrameType::kSkipProgressive; |
489 | 0 | } |
490 | | |
491 | | std::string DebugString() const; |
492 | | |
493 | | uint64_t extensions; |
494 | | }; |
495 | | |
496 | | Status ReadFrameHeader(BitReader* JXL_RESTRICT reader, |
497 | | FrameHeader* JXL_RESTRICT frame); |
498 | | |
499 | | // Shared by enc/dec. 5F and 13 are by far the most common for d1/2/4/8, 0 |
500 | | // ensures low overhead for small images. |
501 | | static constexpr U32Enc kOrderEnc = |
502 | | U32Enc(Val(0x5F), Val(0x13), Val(0), Bits(kNumOrders)); |
503 | | |
504 | | } // namespace jxl |
505 | | |
506 | | #endif // LIB_JXL_FRAME_HEADER_H_ |