1#![forbid(unsafe_code)]
66#![allow(dead_code)]
67#![allow(clippy::doc_markdown)]
68
69pub mod cache;
70pub mod diamond;
71pub mod hierarchical;
72pub mod partition;
73pub mod predictor;
74pub mod search;
75pub mod subpel;
76pub mod types;
77
78pub use cache::{CacheManager, CoLocatedMvLookup, MvCache, MvCacheEntry, RefFrameMvs};
80pub use diamond::{
81 AdaptiveDiamond, CrossDiamond, ExtendedDiamond, HexagonalSearch, LargeDiamond,
82 PredictorDiamond, SmallDiamond, UMHexSearch,
83};
84pub use hierarchical::{
85 CoarseToFineRefiner, HierarchicalConfig, HierarchicalSearch, ImagePyramid, PyramidLevel,
86};
87pub use partition::{
88 InterMode, MergeCandidate, MergeCandidateList, PartitionContext, PartitionDecider,
89 PartitionDecision, PartitionType, SkipDetector, SplitDecision,
90};
91pub use predictor::{
92 MvCandidate, MvCostCalculator, MvPredContext, MvPredictor, MvPredictorList, MvpMode,
93 NeighborInfo, NeighborPosition, SpatialPredictor, TemporalPredictor,
94};
95pub use search::{
96 AdaptiveSearch, DiamondSearch, FullSearch, HexagonSearch, MotionSearch, SearchConfig,
97 SearchContext, ThreeStepSearch, UmhSearch,
98};
99pub use subpel::{
100 HadamardTransform, HalfPelFilter, HalfPelInterpolator, QuarterPelFilter,
101 QuarterPelInterpolator, SatdCalculator, SubpelConfig, SubpelPatterns, SubpelRefiner,
102};
103pub use types::{BlockMatch, BlockSize, MotionVector, MvCost, MvPrecision, SearchRange};
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_module_imports() {
111 let mv = MotionVector::new(10, 20);
113 assert_eq!(mv.dx, 10);
114 assert_eq!(mv.dy, 20);
115
116 let range = SearchRange::symmetric(32);
117 assert_eq!(range.horizontal, 32);
118
119 let block_match = BlockMatch::zero_mv(100);
120 assert_eq!(block_match.sad, 100);
121 }
122
123 #[test]
124 fn test_search_algorithm_creation() {
125 let _full = FullSearch::new();
126 let _diamond = DiamondSearch::new();
127 let _hexagon = HexagonSearch::new();
128 let _umh = UmhSearch::new();
129 let _adaptive = AdaptiveSearch::new();
130 let _three_step = ThreeStepSearch::new();
131 }
132
133 #[test]
134 fn test_diamond_patterns() {
135 let small = SmallDiamond::new();
136 let large = LargeDiamond::new();
137
138 assert_eq!(small.size(), 4);
139 assert_eq!(large.size(), 8);
140 }
141
142 #[test]
143 fn test_predictor_creation() {
144 let predictor = MvPredictor::new();
145 let mvp = predictor.best_mvp();
146 assert!(mvp.is_zero());
147 }
148
149 #[test]
150 fn test_cache_creation() {
151 let cache = MvCache::new();
152 assert_eq!(cache.mi_cols(), 0);
153 assert_eq!(cache.mi_rows(), 0);
154 }
155
156 #[test]
157 fn test_partition_types() {
158 assert_eq!(PartitionType::None.num_parts(), 1);
159 assert_eq!(PartitionType::Split.num_parts(), 4);
160 }
161
162 #[test]
163 fn test_subpel_components() {
164 let _satd = SatdCalculator::new();
165 let identical = vec![128u8; 16];
166 let result = SatdCalculator::satd_4x4(&identical, 4, &identical, 4);
167 assert_eq!(result, 0);
168 }
169
170 #[test]
171 fn test_hierarchical_components() {
172 let pyramid = ImagePyramid::new();
173 assert_eq!(pyramid.num_levels(), 0);
174
175 let config = HierarchicalConfig::new(3);
176 assert_eq!(config.levels, 3);
177 }
178
179 #[test]
180 fn test_mv_precision() {
181 assert_eq!(MvPrecision::FullPel.fractional_bits(), 0);
182 assert_eq!(MvPrecision::HalfPel.fractional_bits(), 1);
183 assert_eq!(MvPrecision::QuarterPel.fractional_bits(), 2);
184 assert_eq!(MvPrecision::EighthPel.fractional_bits(), 3);
185 }
186
187 #[test]
188 fn test_block_sizes() {
189 assert_eq!(BlockSize::Block4x4.width(), 4);
190 assert_eq!(BlockSize::Block8x8.width(), 8);
191 assert_eq!(BlockSize::Block16x16.width(), 16);
192 assert_eq!(BlockSize::Block64x64.width(), 64);
193 assert_eq!(BlockSize::Block128x128.width(), 128);
194 }
195
196 #[test]
197 fn test_integration_search_workflow() {
198 let src = vec![100u8; 64]; let mut reference = vec![50u8; 256]; for row in 0..8 {
204 for col in 0..8 {
205 reference[(row + 4) * 16 + col + 4] = 100;
206 }
207 }
208
209 let ctx = SearchContext::new(&src, 8, &reference, 16, BlockSize::Block8x8, 0, 0, 16, 16);
211
212 let config = SearchConfig::default().range(SearchRange::symmetric(8));
214
215 let full_result = FullSearch::new().search(&ctx, &config);
217 let diamond_result = DiamondSearch::new().search(&ctx, &config);
218 let hex_result = HexagonSearch::new().search(&ctx, &config);
219
220 assert!(full_result.sad < 1000);
222 assert!(diamond_result.sad < 1000);
223 assert!(hex_result.sad < 1000);
224
225 assert_eq!(full_result.mv.full_pel_x(), 4);
227 assert_eq!(full_result.mv.full_pel_y(), 4);
228 }
229}