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