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