Coverage Report

Created: 2025-06-22 08:04

/src/libjxl/lib/jxl/enc_fields.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#include "lib/jxl/enc_fields.h"
7
8
#include <cinttypes>  // PRIu64
9
10
#include "lib/jxl/enc_aux_out.h"
11
#include "lib/jxl/fields.h"
12
13
namespace jxl {
14
15
namespace {
16
using ::jxl::fields_internal::VisitorBase;
17
class WriteVisitor : public VisitorBase {
18
 public:
19
  WriteVisitor(const size_t extension_bits, BitWriter* JXL_RESTRICT writer)
20
0
      : extension_bits_(extension_bits), writer_(writer) {}
21
22
  Status Bits(const size_t bits, const uint32_t /*default_value*/,
23
0
              uint32_t* JXL_RESTRICT value) override {
24
0
    ok_ &= BitsCoder::Write(bits, *value, writer_);
25
0
    return true;
26
0
  }
27
  Status U32(const U32Enc enc, const uint32_t /*default_value*/,
28
0
             uint32_t* JXL_RESTRICT value) override {
29
0
    ok_ &= U32Coder::Write(enc, *value, writer_);
30
0
    return true;
31
0
  }
32
33
  Status U64(const uint64_t /*default_value*/,
34
0
             uint64_t* JXL_RESTRICT value) override {
35
0
    ok_ &= U64Coder::Write(*value, writer_);
36
0
    return true;
37
0
  }
38
39
  Status F16(const float /*default_value*/,
40
0
             float* JXL_RESTRICT value) override {
41
0
    ok_ &= F16Coder::Write(*value, writer_);
42
0
    return true;
43
0
  }
44
45
0
  Status BeginExtensions(uint64_t* JXL_RESTRICT extensions) override {
46
0
    JXL_QUIET_RETURN_IF_ERROR(VisitorBase::BeginExtensions(extensions));
47
0
    if (*extensions == 0) {
48
0
      JXL_ENSURE(extension_bits_ == 0);
49
0
      return true;
50
0
    }
51
    // TODO(janwas): extend API to pass in array of extension_bits, one per
52
    // extension. We currently ascribe all bits to the first extension, but
53
    // this is only an encoder limitation. NOTE: extension_bits_ can be zero
54
    // if an extension does not require any additional fields.
55
0
    ok_ &= U64Coder::Write(extension_bits_, writer_);
56
    // For each nonzero bit except the lowest/first (already written):
57
0
    for (uint64_t remaining_extensions = *extensions & (*extensions - 1);
58
0
         remaining_extensions != 0;
59
0
         remaining_extensions &= remaining_extensions - 1) {
60
0
      ok_ &= U64Coder::Write(0, writer_);
61
0
    }
62
0
    return true;
63
0
  }
64
  // EndExtensions = default.
65
66
0
  Status OK() const { return ok_; }
67
68
 private:
69
  const size_t extension_bits_;
70
  BitWriter* JXL_RESTRICT writer_;
71
  bool ok_ = true;
72
};
73
}  // namespace
74
75
Status Bundle::Write(const Fields& fields, BitWriter* writer, LayerType layer,
76
0
                     AuxOut* aux_out) {
77
0
  size_t extension_bits;
78
0
  size_t total_bits;
79
0
  JXL_RETURN_IF_ERROR(Bundle::CanEncode(fields, &extension_bits, &total_bits));
80
81
0
  return writer->WithMaxBits(total_bits, layer, aux_out, [&] {
82
0
    WriteVisitor visitor(extension_bits, writer);
83
0
    JXL_RETURN_IF_ERROR(visitor.VisitConst(fields));
84
0
    return visitor.OK();
85
0
  });
86
0
}
87
88
// Returns false if the value is too large to encode.
89
Status BitsCoder::Write(const size_t bits, const uint32_t value,
90
0
                        BitWriter* JXL_RESTRICT writer) {
91
0
  if (value >= (1ULL << bits)) {
92
0
    return JXL_FAILURE("Value %d too large to encode in %" PRIu64 " bits",
93
0
                       value, static_cast<uint64_t>(bits));
94
0
  }
95
0
  writer->Write(bits, value);
96
0
  return true;
97
0
}
98
99
// Returns false if the value is too large to encode.
100
Status U32Coder::Write(const U32Enc enc, const uint32_t value,
101
0
                       BitWriter* JXL_RESTRICT writer) {
102
0
  uint32_t selector;
103
0
  size_t total_bits;
104
0
  JXL_RETURN_IF_ERROR(ChooseSelector(enc, value, &selector, &total_bits));
105
106
0
  writer->Write(2, selector);
107
108
0
  const U32Distr d = enc.GetDistr(selector);
109
0
  if (!d.IsDirect()) {  // Nothing more to write for direct encoding
110
0
    const uint32_t offset = d.Offset();
111
0
    JXL_ENSURE(value >= offset);
112
0
    writer->Write(total_bits - 2, value - offset);
113
0
  }
114
115
0
  return true;
116
0
}
117
118
// Returns false if the value is too large to encode.
119
0
Status U64Coder::Write(uint64_t value, BitWriter* JXL_RESTRICT writer) {
120
0
  if (value == 0) {
121
    // Selector: use 0 bits, value 0
122
0
    writer->Write(2, 0);
123
0
  } else if (value <= 16) {
124
    // Selector: use 4 bits, value 1..16
125
0
    writer->Write(2, 1);
126
0
    writer->Write(4, value - 1);
127
0
  } else if (value <= 272) {
128
    // Selector: use 8 bits, value 17..272
129
0
    writer->Write(2, 2);
130
0
    writer->Write(8, value - 17);
131
0
  } else {
132
    // Selector: varint, first a 12-bit group, after that per 8-bit group.
133
0
    writer->Write(2, 3);
134
0
    writer->Write(12, value & 4095);
135
0
    value >>= 12;
136
0
    int shift = 12;
137
0
    while (value > 0 && shift < 60) {
138
      // Indicate varint not done
139
0
      writer->Write(1, 1);
140
0
      writer->Write(8, value & 255);
141
0
      value >>= 8;
142
0
      shift += 8;
143
0
    }
144
0
    if (value > 0) {
145
      // This only could happen if shift == N - 4.
146
0
      writer->Write(1, 1);
147
0
      writer->Write(4, value & 15);
148
      // Implicitly closed sequence, no extra stop bit is required.
149
0
    } else {
150
      // Indicate end of varint
151
0
      writer->Write(1, 0);
152
0
    }
153
0
  }
154
155
0
  return true;
156
0
}
157
158
0
Status F16Coder::Write(float value, BitWriter* JXL_RESTRICT writer) {
159
0
  uint32_t bits32;
160
0
  memcpy(&bits32, &value, sizeof(bits32));
161
0
  const uint32_t sign = bits32 >> 31;
162
0
  const uint32_t biased_exp32 = (bits32 >> 23) & 0xFF;
163
0
  const uint32_t mantissa32 = bits32 & 0x7FFFFF;
164
165
0
  const int32_t exp = static_cast<int32_t>(biased_exp32) - 127;
166
0
  if (JXL_UNLIKELY(exp > 15)) {
167
0
    return JXL_FAILURE("Too big to encode, CanEncode should return false");
168
0
  }
169
170
  // Tiny or zero => zero.
171
0
  if (exp < -24) {
172
0
    writer->Write(16, 0);
173
0
    return true;
174
0
  }
175
176
0
  uint32_t biased_exp16;
177
0
  uint32_t mantissa16;
178
179
  // exp = [-24, -15] => subnormal
180
0
  if (JXL_UNLIKELY(exp < -14)) {
181
0
    biased_exp16 = 0;
182
0
    const uint32_t sub_exp = static_cast<uint32_t>(-14 - exp);
183
0
    JXL_ENSURE(1 <= sub_exp && sub_exp < 11);
184
0
    mantissa16 = (1 << (10 - sub_exp)) + (mantissa32 >> (13 + sub_exp));
185
0
  } else {
186
    // exp = [-14, 15]
187
0
    biased_exp16 = static_cast<uint32_t>(exp + 15);
188
0
    JXL_ENSURE(1 <= biased_exp16 && biased_exp16 < 31);
189
0
    mantissa16 = mantissa32 >> 13;
190
0
  }
191
192
0
  JXL_ENSURE(mantissa16 < 1024);
193
0
  const uint32_t bits16 = (sign << 15) | (biased_exp16 << 10) | mantissa16;
194
0
  JXL_ENSURE(bits16 < 0x10000);
195
0
  writer->Write(16, bits16);
196
0
  return true;
197
0
}
198
199
Status WriteCodestreamHeaders(CodecMetadata* metadata, BitWriter* writer,
200
0
                              AuxOut* aux_out) {
201
  // Marker/signature
202
0
  JXL_RETURN_IF_ERROR(writer->WithMaxBits(16, LayerType::Header, aux_out, [&] {
203
0
    writer->Write(8, 0xFF);
204
0
    writer->Write(8, kCodestreamMarker);
205
0
    return true;
206
0
  }));
207
208
0
  JXL_RETURN_IF_ERROR(
209
0
      WriteSizeHeader(metadata->size, writer, LayerType::Header, aux_out));
210
211
0
  JXL_RETURN_IF_ERROR(
212
0
      WriteImageMetadata(metadata->m, writer, LayerType::Header, aux_out));
213
214
0
  metadata->transform_data.nonserialized_xyb_encoded = metadata->m.xyb_encoded;
215
0
  JXL_RETURN_IF_ERROR(Bundle::Write(metadata->transform_data, writer,
216
0
                                    LayerType::Header, aux_out));
217
218
0
  return true;
219
0
}
220
221
Status WriteFrameHeader(const FrameHeader& frame,
222
0
                        BitWriter* JXL_RESTRICT writer, AuxOut* aux_out) {
223
0
  return Bundle::Write(frame, writer, LayerType::Header, aux_out);
224
0
}
225
226
Status WriteImageMetadata(const ImageMetadata& metadata,
227
                          BitWriter* JXL_RESTRICT writer, LayerType layer,
228
0
                          AuxOut* aux_out) {
229
0
  return Bundle::Write(metadata, writer, layer, aux_out);
230
0
}
231
232
Status WriteQuantizerParams(const QuantizerParams& params,
233
                            BitWriter* JXL_RESTRICT writer, LayerType layer,
234
0
                            AuxOut* aux_out) {
235
0
  return Bundle::Write(params, writer, layer, aux_out);
236
0
}
237
238
Status WriteSizeHeader(const SizeHeader& size, BitWriter* JXL_RESTRICT writer,
239
0
                       LayerType layer, AuxOut* aux_out) {
240
0
  return Bundle::Write(size, writer, layer, aux_out);
241
0
}
242
243
}  // namespace jxl