Coverage Report

Created: 2025-11-14 07:32

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