Coverage Report

Created: 2025-06-16 07:00

/src/libjxl/lib/jxl/dec_patch_dictionary.h
Line
Count
Source
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
#ifndef LIB_JXL_DEC_PATCH_DICTIONARY_H_
7
#define LIB_JXL_DEC_PATCH_DICTIONARY_H_
8
9
// Chooses reference patches, and avoids encoding them once per occurrence.
10
11
#include <jxl/memory_manager.h>
12
13
#include <array>
14
#include <cstddef>
15
#include <cstdint>
16
#include <cstring>
17
#include <memory>
18
#include <utility>
19
#include <vector>
20
21
#include "lib/jxl/base/compiler_specific.h"  // ssize_t
22
#include "lib/jxl/base/status.h"
23
#include "lib/jxl/dec_bit_reader.h"
24
#include "lib/jxl/image_bundle.h"
25
#include "lib/jxl/image_metadata.h"
26
27
namespace jxl {
28
29
struct ReferenceFrame {
30
  std::unique_ptr<ImageBundle> frame;
31
  // ImageBundle doesn't yet have a simple way to state it is in XYB.
32
  bool ib_is_in_xyb = false;
33
};
34
35
enum class PatchBlendMode : uint8_t {
36
  // The new values are the old ones. Useful to skip some channels.
37
  kNone = 0,
38
  // The new values (in the crop) replace the old ones: sample = new
39
  kReplace = 1,
40
  // The new values (in the crop) get added to the old ones: sample = old + new
41
  kAdd = 2,
42
  // The new values (in the crop) get multiplied by the old ones:
43
  // sample = old * new
44
  // This blend mode is only supported if BlendColorSpace is kEncoded. The
45
  // range of the new value matters for multiplication purposes, and its
46
  // nominal range of 0..1 is computed the same way as this is done for the
47
  // alpha values in kBlend and kAlphaWeightedAdd.
48
  kMul = 3,
49
  // The new values (in the crop) replace the old ones if alpha>0:
50
  // For first alpha channel:
51
  // alpha = old + new * (1 - old)
52
  // For other channels if !alpha_associated:
53
  // sample = ((1 - new_alpha) * old * old_alpha + new_alpha * new) / alpha
54
  // For other channels if alpha_associated:
55
  // sample = (1 - new_alpha) * old + new
56
  // The alpha formula applies to the alpha used for the division in the other
57
  // channels formula, and applies to the alpha channel itself if its
58
  // blend_channel value matches itself.
59
  // If using kBlendAbove, new is the patch and old is the original image; if
60
  // using kBlendBelow, the meaning is inverted.
61
  kBlendAbove = 4,
62
  kBlendBelow = 5,
63
  // The new values (in the crop) are added to the old ones if alpha>0:
64
  // For first alpha channel: sample = sample = old + new * (1 - old)
65
  // For other channels: sample = old + alpha * new
66
  kAlphaWeightedAddAbove = 6,
67
  kAlphaWeightedAddBelow = 7,
68
};
69
70
constexpr uint8_t kNumPatchBlendModes =
71
    static_cast<uint8_t>(PatchBlendMode::kAlphaWeightedAddBelow) + 1;
72
73
1.52M
inline bool UsesAlpha(PatchBlendMode mode) {
74
1.52M
  return mode == PatchBlendMode::kBlendAbove ||
75
1.52M
         mode == PatchBlendMode::kBlendBelow ||
76
1.52M
         mode == PatchBlendMode::kAlphaWeightedAddAbove ||
77
1.52M
         mode == PatchBlendMode::kAlphaWeightedAddBelow;
78
1.52M
}
79
756k
inline bool UsesClamp(PatchBlendMode mode) {
80
756k
  return UsesAlpha(mode) || mode == PatchBlendMode::kMul;
81
756k
}
82
83
struct PatchBlending {
84
  PatchBlendMode mode;
85
  uint32_t alpha_channel;
86
  bool clamp;
87
};
88
89
// Position and size of the patch in the reference frame.
90
struct PatchReferencePosition {
91
  size_t ref, x0, y0, xsize, ysize;
92
};
93
94
struct PatchPosition {
95
  // Position of top-left corner of the patch in the image.
96
  size_t x, y;
97
  size_t ref_pos_idx;
98
};
99
100
struct PassesSharedState;
101
102
// Encoder-side helper class to encode the PatchesDictionary.
103
class PatchDictionaryEncoder;
104
105
class PatchDictionary {
106
 public:
107
  explicit PatchDictionary(JxlMemoryManager* memory_manager)
108
10.3k
      : memory_manager_(memory_manager) {}
109
110
26.2k
  void SetShared(const std::array<ReferenceFrame, 4>* reference_frames) {
111
26.2k
    reference_frames_ = reference_frames;
112
26.2k
  }
113
114
938
  bool HasAny() const { return !positions_.empty(); }
115
116
  Status Decode(JxlMemoryManager* memory_manager, BitReader* br, size_t xsize,
117
                size_t ysize, size_t num_extra_channels,
118
                bool* uses_extra_channels);
119
120
25.0k
  void Clear() {
121
25.0k
    positions_.clear();
122
25.0k
    ComputePatchTree();
123
25.0k
  }
124
125
  // Adds patches to a segment of `xsize` pixels, starting at `inout`, assumed
126
  // to be located at position (x0, y) in the frame.
127
  Status AddOneRow(
128
      float* const* inout, size_t y, size_t x0, size_t xsize,
129
      const std::vector<ExtraChannelInfo>& extra_channel_info) const;
130
131
  // Returns dependencies of this patch dictionary on reference frame ids as a
132
  // bit mask: bits 0-3 indicate reference frame 0-3.
133
  int GetReferences() const;
134
135
  std::vector<size_t> GetPatchesForRow(size_t y) const;
136
137
 private:
138
  friend class PatchDictionaryEncoder;
139
140
  JxlMemoryManager* memory_manager_;
141
  const std::array<ReferenceFrame, 4>* reference_frames_;
142
  std::vector<PatchPosition> positions_;
143
  std::vector<PatchReferencePosition> ref_positions_;
144
  std::vector<PatchBlending> blendings_;
145
  size_t blendings_stride_;
146
147
  // Interval tree on the y coordinates of the patches.
148
  struct PatchTreeNode {
149
    ssize_t left_child;
150
    ssize_t right_child;
151
    size_t y_center;
152
    // Range of patches in sorted_patches_y0_ and sorted_patches_y1_ that
153
    // contain the row y_center.
154
    size_t start;
155
    size_t num;
156
  };
157
  std::vector<PatchTreeNode> patch_tree_;
158
  // Number of patches for each row.
159
  std::vector<size_t> num_patches_;
160
  std::vector<std::pair<size_t, size_t>> sorted_patches_y0_;
161
  std::vector<std::pair<size_t, size_t>> sorted_patches_y1_;
162
163
  void ComputePatchTree();
164
};
165
166
}  // namespace jxl
167
168
#endif  // LIB_JXL_DEC_PATCH_DICTIONARY_H_