enc_fields.cc (7790B)
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> 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_ASSERT(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, size_t 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 BitWriter::Allotment allotment(writer, total_bits); 82 WriteVisitor visitor(extension_bits, writer); 83 JXL_RETURN_IF_ERROR(visitor.VisitConst(fields)); 84 JXL_RETURN_IF_ERROR(visitor.OK()); 85 allotment.ReclaimAndCharge(writer, layer, aux_out); 86 return true; 87 } 88 89 // Returns false if the value is too large to encode. 90 Status BitsCoder::Write(const size_t bits, const uint32_t value, 91 BitWriter* JXL_RESTRICT writer) { 92 if (value >= (1ULL << bits)) { 93 return JXL_FAILURE("Value %d too large to encode in %" PRIu64 " bits", 94 value, static_cast<uint64_t>(bits)); 95 } 96 writer->Write(bits, value); 97 return true; 98 } 99 100 // Returns false if the value is too large to encode. 101 Status U32Coder::Write(const U32Enc enc, const uint32_t value, 102 BitWriter* JXL_RESTRICT writer) { 103 uint32_t selector; 104 size_t total_bits; 105 JXL_RETURN_IF_ERROR(ChooseSelector(enc, value, &selector, &total_bits)); 106 107 writer->Write(2, selector); 108 109 const U32Distr d = enc.GetDistr(selector); 110 if (!d.IsDirect()) { // Nothing more to write for direct encoding 111 const uint32_t offset = d.Offset(); 112 JXL_ASSERT(value >= offset); 113 writer->Write(total_bits - 2, value - offset); 114 } 115 116 return true; 117 } 118 119 // Returns false if the value is too large to encode. 120 Status U64Coder::Write(uint64_t value, BitWriter* JXL_RESTRICT writer) { 121 if (value == 0) { 122 // Selector: use 0 bits, value 0 123 writer->Write(2, 0); 124 } else if (value <= 16) { 125 // Selector: use 4 bits, value 1..16 126 writer->Write(2, 1); 127 writer->Write(4, value - 1); 128 } else if (value <= 272) { 129 // Selector: use 8 bits, value 17..272 130 writer->Write(2, 2); 131 writer->Write(8, value - 17); 132 } else { 133 // Selector: varint, first a 12-bit group, after that per 8-bit group. 134 writer->Write(2, 3); 135 writer->Write(12, value & 4095); 136 value >>= 12; 137 int shift = 12; 138 while (value > 0 && shift < 60) { 139 // Indicate varint not done 140 writer->Write(1, 1); 141 writer->Write(8, value & 255); 142 value >>= 8; 143 shift += 8; 144 } 145 if (value > 0) { 146 // This only could happen if shift == N - 4. 147 writer->Write(1, 1); 148 writer->Write(4, value & 15); 149 // Implicitly closed sequence, no extra stop bit is required. 150 } else { 151 // Indicate end of varint 152 writer->Write(1, 0); 153 } 154 } 155 156 return true; 157 } 158 159 Status F16Coder::Write(float value, BitWriter* JXL_RESTRICT writer) { 160 uint32_t bits32; 161 memcpy(&bits32, &value, sizeof(bits32)); 162 const uint32_t sign = bits32 >> 31; 163 const uint32_t biased_exp32 = (bits32 >> 23) & 0xFF; 164 const uint32_t mantissa32 = bits32 & 0x7FFFFF; 165 166 const int32_t exp = static_cast<int32_t>(biased_exp32) - 127; 167 if (JXL_UNLIKELY(exp > 15)) { 168 return JXL_FAILURE("Too big to encode, CanEncode should return false"); 169 } 170 171 // Tiny or zero => zero. 172 if (exp < -24) { 173 writer->Write(16, 0); 174 return true; 175 } 176 177 uint32_t biased_exp16; 178 uint32_t mantissa16; 179 180 // exp = [-24, -15] => subnormal 181 if (JXL_UNLIKELY(exp < -14)) { 182 biased_exp16 = 0; 183 const uint32_t sub_exp = static_cast<uint32_t>(-14 - exp); 184 JXL_ASSERT(1 <= sub_exp && sub_exp < 11); 185 mantissa16 = (1 << (10 - sub_exp)) + (mantissa32 >> (13 + sub_exp)); 186 } else { 187 // exp = [-14, 15] 188 biased_exp16 = static_cast<uint32_t>(exp + 15); 189 JXL_ASSERT(1 <= biased_exp16 && biased_exp16 < 31); 190 mantissa16 = mantissa32 >> 13; 191 } 192 193 JXL_ASSERT(mantissa16 < 1024); 194 const uint32_t bits16 = (sign << 15) | (biased_exp16 << 10) | mantissa16; 195 JXL_ASSERT(bits16 < 0x10000); 196 writer->Write(16, bits16); 197 return true; 198 } 199 200 Status WriteCodestreamHeaders(CodecMetadata* metadata, BitWriter* writer, 201 AuxOut* aux_out) { 202 // Marker/signature 203 BitWriter::Allotment allotment(writer, 16); 204 writer->Write(8, 0xFF); 205 writer->Write(8, kCodestreamMarker); 206 allotment.ReclaimAndCharge(writer, kLayerHeader, aux_out); 207 208 JXL_RETURN_IF_ERROR( 209 WriteSizeHeader(metadata->size, writer, kLayerHeader, aux_out)); 210 211 JXL_RETURN_IF_ERROR( 212 WriteImageMetadata(metadata->m, writer, kLayerHeader, aux_out)); 213 214 metadata->transform_data.nonserialized_xyb_encoded = metadata->m.xyb_encoded; 215 JXL_RETURN_IF_ERROR( 216 Bundle::Write(metadata->transform_data, writer, kLayerHeader, 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, kLayerHeader, aux_out); 224 } 225 226 Status WriteImageMetadata(const ImageMetadata& metadata, 227 BitWriter* JXL_RESTRICT writer, size_t 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, size_t 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 size_t layer, AuxOut* aux_out) { 240 return Bundle::Write(size, writer, layer, aux_out); 241 } 242 243 } // namespace jxl