tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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