Coverage Report

Created: 2025-06-16 07:00

/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_