libjxl

FORK: libjxl patches used on blog
git clone https://git.neptards.moe/blog/libjxl.git
Log | Files | Refs | Submodules | README | LICENSE

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