tor-browser

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

coeff_order.cc (5293B)


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