libjxl

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

coeff_order.cc (4941B)


      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/coeff_order.h"
      7 
      8 #include <stdint.h>
      9 
     10 #include <algorithm>
     11 #include <vector>
     12 
     13 #include "lib/jxl/ans_params.h"
     14 #include "lib/jxl/base/span.h"
     15 #include "lib/jxl/coeff_order_fwd.h"
     16 #include "lib/jxl/dec_ans.h"
     17 #include "lib/jxl/dec_bit_reader.h"
     18 #include "lib/jxl/entropy_coder.h"
     19 #include "lib/jxl/lehmer_code.h"
     20 #include "lib/jxl/modular/encoding/encoding.h"
     21 #include "lib/jxl/modular/modular_image.h"
     22 
     23 namespace jxl {
     24 
     25 uint32_t CoeffOrderContext(uint32_t val) {
     26   uint32_t token, nbits, bits;
     27   HybridUintConfig(0, 0, 0).Encode(val, &token, &nbits, &bits);
     28   return std::min(token, kPermutationContexts - 1);
     29 }
     30 
     31 namespace {
     32 Status ReadPermutation(size_t skip, size_t size, coeff_order_t* order,
     33                        BitReader* br, ANSSymbolReader* reader,
     34                        const std::vector<uint8_t>& context_map) {
     35   std::vector<LehmerT> lehmer(size);
     36   // temp space needs to be as large as the next power of 2, so doubling the
     37   // allocated size is enough.
     38   std::vector<uint32_t> temp(size * 2);
     39   uint32_t end =
     40       reader->ReadHybridUint(CoeffOrderContext(size), br, context_map) + skip;
     41   if (end > size) {
     42     return JXL_FAILURE("Invalid permutation size");
     43   }
     44   uint32_t last = 0;
     45   for (size_t i = skip; i < end; ++i) {
     46     lehmer[i] =
     47         reader->ReadHybridUint(CoeffOrderContext(last), br, context_map);
     48     last = lehmer[i];
     49     if (lehmer[i] >= size - i) {
     50       return JXL_FAILURE("Invalid lehmer code");
     51     }
     52   }
     53   if (order == nullptr) return true;
     54   DecodeLehmerCode(lehmer.data(), temp.data(), size, order);
     55   return true;
     56 }
     57 
     58 }  // namespace
     59 
     60 Status DecodePermutation(size_t skip, size_t size, coeff_order_t* order,
     61                          BitReader* br) {
     62   std::vector<uint8_t> context_map;
     63   ANSCode code;
     64   JXL_RETURN_IF_ERROR(
     65       DecodeHistograms(br, kPermutationContexts, &code, &context_map));
     66   ANSSymbolReader reader(&code, br);
     67   JXL_RETURN_IF_ERROR(
     68       ReadPermutation(skip, size, order, br, &reader, context_map));
     69   if (!reader.CheckANSFinalState()) {
     70     return JXL_FAILURE("Invalid ANS stream");
     71   }
     72   return true;
     73 }
     74 
     75 namespace {
     76 
     77 Status DecodeCoeffOrder(AcStrategy acs, coeff_order_t* order, BitReader* br,
     78                         ANSSymbolReader* reader,
     79                         std::vector<coeff_order_t>& natural_order,
     80                         const std::vector<uint8_t>& context_map) {
     81   const size_t llf = acs.covered_blocks_x() * acs.covered_blocks_y();
     82   const size_t size = kDCTBlockSize * llf;
     83 
     84   JXL_RETURN_IF_ERROR(
     85       ReadPermutation(llf, size, order, br, reader, context_map));
     86   if (order == nullptr) return true;
     87   for (size_t k = 0; k < size; ++k) {
     88     order[k] = natural_order[order[k]];
     89   }
     90   return true;
     91 }
     92 
     93 }  // namespace
     94 
     95 Status DecodeCoeffOrders(uint16_t used_orders, uint32_t used_acs,
     96                          coeff_order_t* order, BitReader* br) {
     97   uint16_t computed = 0;
     98   std::vector<uint8_t> context_map;
     99   ANSCode code;
    100   std::unique_ptr<ANSSymbolReader> reader;
    101   std::vector<coeff_order_t> natural_order;
    102   // Bitstream does not have histograms if no coefficient order is used.
    103   if (used_orders != 0) {
    104     JXL_RETURN_IF_ERROR(
    105         DecodeHistograms(br, kPermutationContexts, &code, &context_map));
    106     reader = make_unique<ANSSymbolReader>(&code, br);
    107   }
    108   uint32_t acs_mask = 0;
    109   for (uint8_t o = 0; o < AcStrategy::kNumValidStrategies; ++o) {
    110     if ((used_acs & (1 << o)) == 0) continue;
    111     acs_mask |= 1 << kStrategyOrder[o];
    112   }
    113   for (uint8_t o = 0; o < AcStrategy::kNumValidStrategies; ++o) {
    114     uint8_t ord = kStrategyOrder[o];
    115     if (computed & (1 << ord)) continue;
    116     computed |= 1 << ord;
    117     AcStrategy acs = AcStrategy::FromRawStrategy(o);
    118     bool used = (acs_mask & (1 << ord)) != 0;
    119 
    120     const size_t llf = acs.covered_blocks_x() * acs.covered_blocks_y();
    121     const size_t size = kDCTBlockSize * llf;
    122 
    123     if (used || (used_orders & (1 << ord))) {
    124       if (natural_order.size() < size) natural_order.resize(size);
    125       acs.ComputeNaturalCoeffOrder(natural_order.data());
    126     }
    127 
    128     if ((used_orders & (1 << ord)) == 0) {
    129       // No need to set the default order if no ACS uses this order.
    130       if (used) {
    131         for (size_t c = 0; c < 3; c++) {
    132           memcpy(&order[CoeffOrderOffset(ord, c)], natural_order.data(),
    133                  size * sizeof(*order));
    134         }
    135       }
    136     } else {
    137       for (size_t c = 0; c < 3; c++) {
    138         coeff_order_t* dest = used ? &order[CoeffOrderOffset(ord, c)] : nullptr;
    139         JXL_RETURN_IF_ERROR(DecodeCoeffOrder(acs, dest, br, reader.get(),
    140                                              natural_order, context_map));
    141       }
    142     }
    143   }
    144   if (used_orders && !reader->CheckANSFinalState()) {
    145     return JXL_FAILURE("Invalid ANS stream");
    146   }
    147   return true;
    148 }
    149 
    150 }  // namespace jxl