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