Coverage Report

Created: 2024-09-08 07:14

/src/libjxl/lib/jxl/coeff_order.cc
Line
Count
Source (jump to first uncovered line)
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
98.8k
uint32_t CoeffOrderContext(uint32_t val) {
28
98.8k
  uint32_t token, nbits, bits;
29
98.8k
  HybridUintConfig(0, 0, 0).Encode(val, &token, &nbits, &bits);
30
98.8k
  return std::min(token, kPermutationContexts - 1);
31
98.8k
}
32
33
namespace {
34
Status ReadPermutation(size_t skip, size_t size, coeff_order_t* order,
35
                       BitReader* br, ANSSymbolReader* reader,
36
30.3k
                       const std::vector<uint8_t>& context_map) {
37
30.3k
  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
30.3k
  std::vector<uint32_t> temp(size * 2);
41
30.3k
  uint32_t end =
42
30.3k
      reader->ReadHybridUint(CoeffOrderContext(size), br, context_map) + skip;
43
30.3k
  if (end > size) {
44
1.38k
    return JXL_FAILURE("Invalid permutation size");
45
1.38k
  }
46
28.9k
  uint32_t last = 0;
47
97.1k
  for (size_t i = skip; i < end; ++i) {
48
68.5k
    lehmer[i] =
49
68.5k
        reader->ReadHybridUint(CoeffOrderContext(last), br, context_map);
50
68.5k
    last = lehmer[i];
51
68.5k
    if (lehmer[i] >= size - i) {
52
365
      return JXL_FAILURE("Invalid lehmer code");
53
365
    }
54
68.5k
  }
55
28.5k
  if (order == nullptr) return true;
56
16.1k
  JXL_RETURN_IF_ERROR(
57
16.1k
      DecodeLehmerCode(lehmer.data(), temp.data(), size, order));
58
16.1k
  return true;
59
16.1k
}
60
61
}  // namespace
62
63
Status DecodePermutation(JxlMemoryManager* memory_manager, size_t skip,
64
18.0k
                         size_t size, coeff_order_t* order, BitReader* br) {
65
18.0k
  std::vector<uint8_t> context_map;
66
18.0k
  ANSCode code;
67
18.0k
  JXL_RETURN_IF_ERROR(DecodeHistograms(memory_manager, br, kPermutationContexts,
68
18.0k
                                       &code, &context_map));
69
25.1k
  JXL_ASSIGN_OR_RETURN(ANSSymbolReader reader,
70
25.1k
                       ANSSymbolReader::Create(&code, br));
71
25.1k
  JXL_RETURN_IF_ERROR(
72
25.1k
      ReadPermutation(skip, size, order, br, &reader, context_map));
73
10.8k
  if (!reader.CheckANSFinalState()) {
74
0
    return JXL_FAILURE("Invalid ANS stream");
75
0
  }
76
10.8k
  return true;
77
10.8k
}
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
17.7k
                        const std::vector<uint8_t>& context_map) {
85
17.7k
  const size_t llf = acs.covered_blocks_x() * acs.covered_blocks_y();
86
17.7k
  const size_t size = kDCTBlockSize * llf;
87
88
17.7k
  JXL_RETURN_IF_ERROR(
89
17.7k
      ReadPermutation(llf, size, order, br, reader, context_map));
90
17.6k
  if (order == nullptr) return true;
91
543k
  for (size_t k = 0; k < size; ++k) {
92
538k
    order[k] = natural_order[order[k]];
93
538k
  }
94
5.32k
  return true;
95
17.6k
}
96
97
}  // namespace
98
99
Status DecodeCoeffOrders(JxlMemoryManager* memory_manager, uint16_t used_orders,
100
                         uint32_t used_acs, coeff_order_t* order,
101
7.71k
                         BitReader* br) {
102
7.71k
  uint16_t computed = 0;
103
7.71k
  std::vector<uint8_t> context_map;
104
7.71k
  ANSCode code;
105
7.71k
  ANSSymbolReader reader;
106
7.71k
  std::vector<coeff_order_t> natural_order;
107
  // Bitstream does not have histograms if no coefficient order is used.
108
7.71k
  if (used_orders != 0) {
109
1.41k
    JXL_RETURN_IF_ERROR(DecodeHistograms(
110
1.41k
        memory_manager, br, kPermutationContexts, &code, &context_map));
111
2.75k
    JXL_ASSIGN_OR_RETURN(reader, ANSSymbolReader::Create(&code, br));
112
2.75k
  }
113
7.68k
  uint32_t acs_mask = 0;
114
215k
  for (uint8_t o = 0; o < AcStrategy::kNumValidStrategies; ++o) {
115
207k
    if ((used_acs & (1 << o)) == 0) continue;
116
13.4k
    acs_mask |= 1 << kStrategyOrder[o];
117
13.4k
  }
118
214k
  for (uint8_t o = 0; o < AcStrategy::kNumValidStrategies; ++o) {
119
207k
    uint8_t ord = kStrategyOrder[o];
120
207k
    if (computed & (1 << ord)) continue;
121
99.7k
    computed |= 1 << ord;
122
99.7k
    AcStrategy acs = AcStrategy::FromRawStrategy(o);
123
99.7k
    bool used = (acs_mask & (1 << ord)) != 0;
124
125
99.7k
    const size_t llf = acs.covered_blocks_x() * acs.covered_blocks_y();
126
99.7k
    const size_t size = kDCTBlockSize * llf;
127
128
99.7k
    if (used || (used_orders & (1 << ord))) {
129
16.0k
      if (natural_order.size() < size) natural_order.resize(size);
130
16.0k
      acs.ComputeNaturalCoeffOrder(natural_order.data());
131
16.0k
    }
132
133
99.7k
    if ((used_orders & (1 << ord)) == 0) {
134
      // No need to set the default order if no ACS uses this order.
135
93.8k
      if (used) {
136
40.6k
        for (size_t c = 0; c < 3; c++) {
137
30.4k
          memcpy(&order[CoeffOrderOffset(ord, c)], natural_order.data(),
138
30.4k
                 size * sizeof(*order));
139
30.4k
        }
140
10.1k
      }
141
93.8k
    } else {
142
23.6k
      for (size_t c = 0; c < 3; c++) {
143
17.7k
        coeff_order_t* dest = used ? &order[CoeffOrderOffset(ord, c)] : nullptr;
144
17.7k
        JXL_RETURN_IF_ERROR(DecodeCoeffOrder(acs, dest, br, &reader,
145
17.7k
                                             natural_order, context_map));
146
17.7k
      }
147
5.91k
    }
148
99.7k
  }
149
7.66k
  if (used_orders && !reader.CheckANSFinalState()) {
150
0
    return JXL_FAILURE("Invalid ANS stream");
151
0
  }
152
7.66k
  return true;
153
7.66k
}
154
155
}  // namespace jxl