libjxl

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

enc_context_map.cc (5210B)


      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 // Library to encode the context map.
      7 
      8 #include "lib/jxl/enc_context_map.h"
      9 
     10 #include <jxl/types.h>
     11 #include <stdint.h>
     12 
     13 #include <algorithm>
     14 #include <cstddef>
     15 #include <vector>
     16 
     17 #include "lib/jxl/base/bits.h"
     18 #include "lib/jxl/base/status.h"
     19 #include "lib/jxl/enc_ans.h"
     20 #include "lib/jxl/enc_aux_out.h"
     21 #include "lib/jxl/entropy_coder.h"
     22 #include "lib/jxl/fields.h"
     23 #include "lib/jxl/pack_signed.h"
     24 
     25 namespace jxl {
     26 
     27 namespace {
     28 
     29 size_t IndexOf(const std::vector<uint8_t>& v, uint8_t value) {
     30   size_t i = 0;
     31   for (; i < v.size(); ++i) {
     32     if (v[i] == value) return i;
     33   }
     34   return i;
     35 }
     36 
     37 void MoveToFront(std::vector<uint8_t>* v, size_t index) {
     38   uint8_t value = (*v)[index];
     39   for (size_t i = index; i != 0; --i) {
     40     (*v)[i] = (*v)[i - 1];
     41   }
     42   (*v)[0] = value;
     43 }
     44 
     45 std::vector<uint8_t> MoveToFrontTransform(const std::vector<uint8_t>& v) {
     46   if (v.empty()) return v;
     47   uint8_t max_value = *std::max_element(v.begin(), v.end());
     48   std::vector<uint8_t> mtf(max_value + 1);
     49   for (size_t i = 0; i <= max_value; ++i) mtf[i] = i;
     50   std::vector<uint8_t> result(v.size());
     51   for (size_t i = 0; i < v.size(); ++i) {
     52     size_t index = IndexOf(mtf, v[i]);
     53     JXL_ASSERT(index < mtf.size());
     54     result[i] = static_cast<uint8_t>(index);
     55     MoveToFront(&mtf, index);
     56   }
     57   return result;
     58 }
     59 
     60 }  // namespace
     61 
     62 void EncodeContextMap(const std::vector<uint8_t>& context_map,
     63                       size_t num_histograms, BitWriter* writer, size_t layer,
     64                       AuxOut* aux_out) {
     65   if (num_histograms == 1) {
     66     // Simple code
     67     writer->Write(1, 1);
     68     // 0 bits per entry.
     69     writer->Write(2, 0);
     70     return;
     71   }
     72 
     73   std::vector<uint8_t> transformed_symbols = MoveToFrontTransform(context_map);
     74   std::vector<std::vector<Token>> tokens(1);
     75   std::vector<std::vector<Token>> mtf_tokens(1);
     76   for (const uint8_t& ctx : context_map) {
     77     tokens[0].emplace_back(0, ctx);
     78   }
     79   for (const uint8_t& sym : transformed_symbols) {
     80     mtf_tokens[0].emplace_back(0, sym);
     81   }
     82   HistogramParams params;
     83   params.uint_method = HistogramParams::HybridUintMethod::kContextMap;
     84   size_t ans_cost;
     85   size_t mtf_cost;
     86   {
     87     EntropyEncodingData codes;
     88     std::vector<uint8_t> sink_context_map;
     89     ans_cost = BuildAndEncodeHistograms(params, 1, tokens, &codes,
     90                                         &sink_context_map, nullptr, 0, nullptr);
     91   }
     92   {
     93     EntropyEncodingData codes;
     94     std::vector<uint8_t> sink_context_map;
     95     mtf_cost = BuildAndEncodeHistograms(params, 1, mtf_tokens, &codes,
     96                                         &sink_context_map, nullptr, 0, nullptr);
     97   }
     98   bool use_mtf = mtf_cost < ans_cost;
     99   // Rebuild token list.
    100   tokens[0].clear();
    101   for (size_t i = 0; i < transformed_symbols.size(); i++) {
    102     tokens[0].emplace_back(0,
    103                            use_mtf ? transformed_symbols[i] : context_map[i]);
    104   }
    105   size_t entry_bits = CeilLog2Nonzero(num_histograms);
    106   size_t simple_cost = entry_bits * context_map.size();
    107   if (entry_bits < 4 && simple_cost < ans_cost && simple_cost < mtf_cost) {
    108     BitWriter::Allotment allotment(writer, 3 + entry_bits * context_map.size());
    109     writer->Write(1, 1);
    110     writer->Write(2, entry_bits);
    111     for (uint8_t entry : context_map) {
    112       writer->Write(entry_bits, entry);
    113     }
    114     allotment.ReclaimAndCharge(writer, layer, aux_out);
    115   } else {
    116     BitWriter::Allotment allotment(writer, 2 + tokens[0].size() * 24);
    117     writer->Write(1, 0);
    118     writer->Write(1, TO_JXL_BOOL(use_mtf));  // Use/don't use MTF.
    119     EntropyEncodingData codes;
    120     std::vector<uint8_t> sink_context_map;
    121     BuildAndEncodeHistograms(params, 1, tokens, &codes, &sink_context_map,
    122                              writer, layer, aux_out);
    123     WriteTokens(tokens[0], codes, sink_context_map, 0, writer);
    124     allotment.ReclaimAndCharge(writer, layer, aux_out);
    125   }
    126 }
    127 
    128 void EncodeBlockCtxMap(const BlockCtxMap& block_ctx_map, BitWriter* writer,
    129                        AuxOut* aux_out) {
    130   const auto& dct = block_ctx_map.dc_thresholds;
    131   const auto& qft = block_ctx_map.qf_thresholds;
    132   const auto& ctx_map = block_ctx_map.ctx_map;
    133   BitWriter::Allotment allotment(
    134       writer,
    135       (dct[0].size() + dct[1].size() + dct[2].size() + qft.size()) * 34 + 1 +
    136           4 + 4 + ctx_map.size() * 10 + 1024);
    137   if (dct[0].empty() && dct[1].empty() && dct[2].empty() && qft.empty() &&
    138       ctx_map.size() == 21 &&
    139       std::equal(ctx_map.begin(), ctx_map.end(), BlockCtxMap::kDefaultCtxMap)) {
    140     writer->Write(1, 1);  // default
    141     allotment.ReclaimAndCharge(writer, kLayerAC, aux_out);
    142     return;
    143   }
    144   writer->Write(1, 0);
    145   for (int j : {0, 1, 2}) {
    146     writer->Write(4, dct[j].size());
    147     for (int i : dct[j]) {
    148       JXL_CHECK(U32Coder::Write(kDCThresholdDist, PackSigned(i), writer));
    149     }
    150   }
    151   writer->Write(4, qft.size());
    152   for (uint32_t i : qft) {
    153     JXL_CHECK(U32Coder::Write(kQFThresholdDist, i - 1, writer));
    154   }
    155   EncodeContextMap(ctx_map, block_ctx_map.num_ctxs, writer, kLayerAC, aux_out);
    156   allotment.ReclaimAndCharge(writer, kLayerAC, aux_out);
    157 }
    158 
    159 }  // namespace jxl