summaryrefslogtreecommitdiffstats
path: root/third_party/jpeg-xl/lib/jxl/enc_progressive_split.h
blob: ef25944bb7ef9664209c0b86e61e1e404d73cf06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#ifndef LIB_JXL_PROGRESSIVE_SPLIT_H_
#define LIB_JXL_PROGRESSIVE_SPLIT_H_

#include <stddef.h>
#include <stdint.h>

#include <limits>
#include <memory>
#include <vector>

#include "lib/jxl/ac_strategy.h"
#include "lib/jxl/base/compiler_specific.h"
#include "lib/jxl/base/status.h"
#include "lib/jxl/chroma_from_luma.h"
#include "lib/jxl/common.h"
#include "lib/jxl/dct_util.h"
#include "lib/jxl/frame_header.h"
#include "lib/jxl/image.h"
#include "lib/jxl/image_ops.h"
#include "lib/jxl/splines.h"

// Functions to split DCT coefficients in multiple passes. All the passes of a
// single frame are added together.

namespace jxl {

constexpr size_t kNoDownsamplingFactor = std::numeric_limits<size_t>::max();

struct PassDefinition {
  // Side of the square of the coefficients that should be kept in each 8x8
  // block. Must be greater than 1, and at most 8. Should be in non-decreasing
  // order.
  size_t num_coefficients;

  // How much to shift the encoded values by, with rounding.
  size_t shift;

  // If specified, this indicates that if the requested downsampling factor is
  // sufficiently high, then it is fine to stop decoding after this pass.
  // By default, passes are not marked as being suitable for any downsampling.
  size_t suitable_for_downsampling_of_at_least;
};

struct ProgressiveMode {
  size_t num_passes = 1;
  PassDefinition passes[kMaxNumPasses] = {
      PassDefinition{/*num_coefficients=*/8, /*shift=*/0,
                     /*suitable_for_downsampling_of_at_least=*/1}};

  ProgressiveMode() = default;

  template <size_t nump>
  explicit ProgressiveMode(const PassDefinition (&p)[nump]) {
    JXL_ASSERT(nump <= kMaxNumPasses);
    num_passes = nump;
    PassDefinition previous_pass{
        /*num_coefficients=*/1, /*shift=*/0,
        /*suitable_for_downsampling_of_at_least=*/kNoDownsamplingFactor};
    size_t last_downsampling_factor = kNoDownsamplingFactor;
    for (size_t i = 0; i < nump; i++) {
      JXL_ASSERT(p[i].num_coefficients > previous_pass.num_coefficients ||
                 (p[i].num_coefficients == previous_pass.num_coefficients &&
                  p[i].shift < previous_pass.shift));
      JXL_ASSERT(p[i].suitable_for_downsampling_of_at_least ==
                     kNoDownsamplingFactor ||
                 p[i].suitable_for_downsampling_of_at_least <=
                     last_downsampling_factor);
      // Only used inside assert.
      (void)last_downsampling_factor;
      if (p[i].suitable_for_downsampling_of_at_least != kNoDownsamplingFactor) {
        last_downsampling_factor = p[i].suitable_for_downsampling_of_at_least;
      }
      previous_pass = passes[i] = p[i];
    }
  }
};

class ProgressiveSplitter {
 public:
  void SetProgressiveMode(ProgressiveMode mode) { mode_ = mode; }

  size_t GetNumPasses() const { return mode_.num_passes; }

  void InitPasses(Passes* JXL_RESTRICT passes) const {
    passes->num_passes = static_cast<uint32_t>(GetNumPasses());
    passes->num_downsample = 0;
    JXL_ASSERT(passes->num_passes != 0);
    passes->shift[passes->num_passes - 1] = 0;
    if (passes->num_passes == 1) return;  // Done, arrays are empty

    for (uint32_t i = 0; i < mode_.num_passes - 1; ++i) {
      const size_t min_downsampling_factor =
          mode_.passes[i].suitable_for_downsampling_of_at_least;
      passes->shift[i] = mode_.passes[i].shift;
      if (1 < min_downsampling_factor &&
          min_downsampling_factor != kNoDownsamplingFactor) {
        passes->downsample[passes->num_downsample] = min_downsampling_factor;
        passes->last_pass[passes->num_downsample] = i;
        if (mode_.passes[i + 1].suitable_for_downsampling_of_at_least <
            min_downsampling_factor) {
          passes->num_downsample += 1;
        }
      }
    }
  }

  template <typename T>
  void SplitACCoefficients(const T* JXL_RESTRICT block, const AcStrategy& acs,
                           size_t bx, size_t by,
                           T* JXL_RESTRICT output[kMaxNumPasses]);

 private:
  ProgressiveMode mode_;
};

extern template void ProgressiveSplitter::SplitACCoefficients<int32_t>(
    const int32_t* JXL_RESTRICT, const AcStrategy&, size_t, size_t,
    int32_t* JXL_RESTRICT[kMaxNumPasses]);

extern template void ProgressiveSplitter::SplitACCoefficients<int16_t>(
    const int16_t* JXL_RESTRICT, const AcStrategy&, size_t, size_t,
    int16_t* JXL_RESTRICT[kMaxNumPasses]);

}  // namespace jxl

#endif  // LIB_JXL_PROGRESSIVE_SPLIT_H_