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