dec_patch_dictionary.h (5412B)
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 #include <sys/types.h> 13 14 #include <array> 15 #include <cstddef> 16 #include <cstdint> 17 #include <cstring> 18 #include <memory> 19 #include <utility> 20 #include <vector> 21 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 ReferceFrame { 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 inline bool UsesAlpha(PatchBlendMode mode) { 74 return mode == PatchBlendMode::kBlendAbove || 75 mode == PatchBlendMode::kBlendBelow || 76 mode == PatchBlendMode::kAlphaWeightedAddAbove || 77 mode == PatchBlendMode::kAlphaWeightedAddBelow; 78 } 79 inline bool UsesClamp(PatchBlendMode mode) { 80 return UsesAlpha(mode) || mode == PatchBlendMode::kMul; 81 } 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 : memory_manager_(memory_manager) {} 109 110 void SetShared(const std::array<ReferceFrame, 4>* reference_frames) { 111 reference_frames_ = reference_frames; 112 } 113 114 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 void Clear() { 121 positions_.clear(); 122 ComputePatchTree(); 123 } 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<ReferceFrame, 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_