/rust/registry/src/index.crates.io-1949cf8c6b5b557f/av-scenechange-0.14.1/src/data/satd.rs
Line | Count | Source |
1 | | #[cfg(asm_neon)] |
2 | | mod simd_neon; |
3 | | #[cfg(asm_x86_64)] |
4 | | mod simd_x86; |
5 | | #[cfg(test)] |
6 | | mod tests; |
7 | | |
8 | | #[cfg(not(any(asm_x86_64, asm_neon)))] |
9 | | use rust::*; |
10 | | #[cfg(asm_neon)] |
11 | | use simd_neon::*; |
12 | | #[cfg(asm_x86_64)] |
13 | | use simd_x86::*; |
14 | | use v_frame::pixel::Pixel; |
15 | | |
16 | | use super::{block::BlockSize, plane::PlaneRegion}; |
17 | | use crate::cpu::CpuFeatureLevel; |
18 | | |
19 | | mod rust { |
20 | | use v_frame::{ |
21 | | math::msb, |
22 | | pixel::{CastFromPrimitive, Pixel}, |
23 | | }; |
24 | | |
25 | | use crate::{ |
26 | | cpu::CpuFeatureLevel, |
27 | | data::{ |
28 | | hadamard::{hadamard4x4, hadamard8x8}, |
29 | | plane::{Area, PlaneRegion, Rect}, |
30 | | sad::get_sad, |
31 | | }, |
32 | | }; |
33 | | |
34 | | /// Sum of absolute transformed differences over a block. |
35 | | /// w and h can be at most 128, the size of the largest block. |
36 | | /// Use the sum of 4x4 and 8x8 hadamard transforms for the transform, but |
37 | | /// revert to sad on edges when these transforms do not fit into w and h. |
38 | | /// 4x4 transforms instead of 8x8 transforms when width or height < 8. |
39 | | #[cfg_attr(all(asm_x86_64, target_feature = "avx2"), cold)] |
40 | | #[cfg_attr(asm_neon, cold)] |
41 | 0 | pub(super) fn get_satd_internal<T: Pixel>( |
42 | 0 | plane_org: &PlaneRegion<'_, T>, |
43 | 0 | plane_ref: &PlaneRegion<'_, T>, |
44 | 0 | w: usize, |
45 | 0 | h: usize, |
46 | 0 | bit_depth: usize, |
47 | 0 | cpu: CpuFeatureLevel, |
48 | 0 | ) -> u32 { |
49 | 0 | assert!(w <= 128 && h <= 128); |
50 | 0 | assert!(plane_org.rect().width >= w && plane_org.rect().height >= h); |
51 | 0 | assert!(plane_ref.rect().width >= w && plane_ref.rect().height >= h); |
52 | | |
53 | | // Size of hadamard transform should be 4x4 or 8x8 |
54 | | // 4x* and *x4 use 4x4 and all other use 8x8 |
55 | 0 | let size: usize = w.min(h).min(8); |
56 | 0 | let tx2d = if size == 4 { hadamard4x4 } else { hadamard8x8 }; |
57 | | |
58 | 0 | let mut sum: u64 = 0; |
59 | | |
60 | | // Loop over chunks the size of the chosen transform |
61 | 0 | for chunk_y in (0..h).step_by(size) { |
62 | 0 | let chunk_h = (h - chunk_y).min(size); |
63 | 0 | for chunk_x in (0..w).step_by(size) { |
64 | 0 | let chunk_w = (w - chunk_x).min(size); |
65 | 0 | let chunk_area = Area::Rect(Rect { |
66 | 0 | x: chunk_x as isize, |
67 | 0 | y: chunk_y as isize, |
68 | 0 | width: chunk_w, |
69 | 0 | height: chunk_h, |
70 | 0 | }); |
71 | 0 | let chunk_org = plane_org.subregion(chunk_area); |
72 | 0 | let chunk_ref = plane_ref.subregion(chunk_area); |
73 | | |
74 | | // Revert to sad on edge blocks (frame edges) |
75 | 0 | if chunk_w != size || chunk_h != size { |
76 | 0 | sum += get_sad(&chunk_org, &chunk_ref, chunk_w, chunk_h, bit_depth, cpu) as u64; |
77 | 0 | continue; |
78 | 0 | } |
79 | | |
80 | 0 | let buf: &mut [i32] = &mut [0; 8 * 8][..size * size]; |
81 | | |
82 | | // Move the difference of the transforms to a buffer |
83 | 0 | for (row_diff, (row_org, row_ref)) in buf |
84 | 0 | .chunks_mut(size) |
85 | 0 | .zip(chunk_org.rows_iter().zip(chunk_ref.rows_iter())) |
86 | | { |
87 | 0 | for (diff, (a, b)) in |
88 | 0 | row_diff.iter_mut().zip(row_org.iter().zip(row_ref.iter())) |
89 | 0 | { |
90 | 0 | *diff = i32::cast_from(*a) - i32::cast_from(*b); |
91 | 0 | } |
92 | | } |
93 | | |
94 | | // Perform the hadamard transform on the differences |
95 | | // SAFETY: A sufficient number elements exist for the size of the transform. |
96 | 0 | unsafe { |
97 | 0 | tx2d(buf); |
98 | 0 | } |
99 | | |
100 | | // Sum the absolute values of the transformed differences |
101 | 0 | sum += buf.iter().map(|a| a.unsigned_abs() as u64).sum::<u64>(); Unexecuted instantiation: av_scenechange::data::satd::rust::get_satd_internal::<u16>::{closure#0}Unexecuted instantiation: av_scenechange::data::satd::rust::get_satd_internal::<u8>::{closure#0}Unexecuted instantiation: av_scenechange::data::satd::rust::get_satd_internal::<_>::{closure#0} |
102 | | } |
103 | | } |
104 | | |
105 | | // Normalize the results |
106 | 0 | let ln = msb(size as i32) as u64; |
107 | 0 | ((sum + (1 << ln >> 1)) >> ln) as u32 |
108 | 0 | } Unexecuted instantiation: av_scenechange::data::satd::rust::get_satd_internal::<u16> Unexecuted instantiation: av_scenechange::data::satd::rust::get_satd_internal::<u8> Unexecuted instantiation: av_scenechange::data::satd::rust::get_satd_internal::<_> |
109 | | } |
110 | | |
111 | | // BlockSize::BLOCK_SIZES.next_power_of_two() |
112 | | const DIST_FNS_LENGTH: usize = 32; |
113 | | |
114 | 0 | const fn to_index(bsize: BlockSize) -> usize { |
115 | 0 | bsize as usize & (DIST_FNS_LENGTH - 1) |
116 | 0 | } |
117 | | |
118 | 0 | pub(crate) fn get_satd<T: Pixel>( |
119 | 0 | src: &PlaneRegion<'_, T>, |
120 | 0 | dst: &PlaneRegion<'_, T>, |
121 | 0 | w: usize, |
122 | 0 | h: usize, |
123 | 0 | bit_depth: usize, |
124 | 0 | cpu: CpuFeatureLevel, |
125 | 0 | ) -> u32 { |
126 | 0 | get_satd_internal(src, dst, w, h, bit_depth, cpu) |
127 | 0 | } Unexecuted instantiation: av_scenechange::data::satd::get_satd::<u16> Unexecuted instantiation: av_scenechange::data::satd::get_satd::<u8> Unexecuted instantiation: av_scenechange::data::satd::get_satd::<_> |