]>
Commit | Line | Data |
---|---|---|
1 | use nihav_codec_support::codecs::{MV, ZERO_MV}; | |
2 | ||
3 | pub fn pix_dist(a: u8, b: u8) -> u32 { | |
4 | ((i32::from(a) - (i32::from(b))) * (i32::from(a) - (i32::from(b)))) as u32 | |
5 | } | |
6 | ||
7 | pub fn calc_diff(src1: &[u8], stride1: usize, src2: &[u8], stride2: usize) -> u32 { | |
8 | src1.chunks(stride1).zip(src2.chunks(stride2)).take(8).fold(0u32, | |
9 | |acc, (line1, line2)| acc + line1[..8].iter().zip(line2.iter()).fold(0u32, | |
10 | |acc2, (&a, &b)| acc2 + pix_dist(a, b))) | |
11 | } | |
12 | ||
13 | const DIA_LARGE: [MV; 4] = [MV{x: 2, y: 0}, MV{x: 0, y: 2}, MV{x: -2, y: 0}, MV{x: 0, y: -2}]; | |
14 | const DIA_SMALL: [MV; 4] = [MV{x: 1, y: 0}, MV{x: 0, y: 1}, MV{x: -1, y: 0}, MV{x: 0, y: -1}]; | |
15 | fn check_mv(x: usize, y: usize, width: usize, height: usize, mv: MV) -> bool { | |
16 | let xpos = (x as isize) + isize::from(mv.x); | |
17 | let ypos = (y as isize) + isize::from(mv.y); | |
18 | ||
19 | mv.x.abs() <= 15 && mv.y.abs() <= 15 && | |
20 | xpos >= 0 && (xpos + 8 <= (width as isize)) && | |
21 | ypos >= 0 && (ypos + 8 <= (height as isize)) | |
22 | } | |
23 | ||
24 | pub fn mv_search(src: &[u8], stride: usize, width: usize, height: usize, | |
25 | x: usize, y: usize, skip_diff: u32, | |
26 | ref_blk: &[u8; 64], tmp: &mut [u8; 64]) -> (MV, u32) { | |
27 | let mut best_diff = skip_diff; | |
28 | let mut best_mv = ZERO_MV; | |
29 | loop { | |
30 | let last_mv = best_mv; | |
31 | for &off_mv in DIA_LARGE.iter() { | |
32 | let mv = best_mv + off_mv; | |
33 | if !check_mv(x, y, width, height, mv) { | |
34 | continue; | |
35 | } | |
36 | get_block(src, stride, x, y, mv, tmp); | |
37 | let diff = calc_diff(ref_blk, 8, tmp, 8); | |
38 | if diff < best_diff { | |
39 | best_diff = diff; | |
40 | best_mv = mv; | |
41 | } | |
42 | } | |
43 | if best_mv == last_mv { | |
44 | break; | |
45 | } | |
46 | } | |
47 | loop { | |
48 | let last_mv = best_mv; | |
49 | for &off_mv in DIA_SMALL.iter() { | |
50 | let mv = best_mv + off_mv; | |
51 | if !check_mv(x, y, width, height, mv) { | |
52 | continue; | |
53 | } | |
54 | get_block(src, stride, x, y, mv, tmp); | |
55 | let diff = calc_diff(ref_blk, 8, tmp, 8); | |
56 | if diff < best_diff { | |
57 | best_diff = diff; | |
58 | best_mv = mv; | |
59 | } | |
60 | } | |
61 | if best_mv == last_mv { | |
62 | break; | |
63 | } | |
64 | } | |
65 | (best_mv, best_diff) | |
66 | } | |
67 | ||
68 | pub fn get_block(src: &[u8], stride: usize, x: usize, y: usize, mv: MV, dst: &mut [u8; 64]) { | |
69 | let pos = (x as isize + isize::from(mv.x) + (y as isize + isize::from(mv.y)) * (stride as isize)) as usize; | |
70 | for (dline, sline) in dst.chunks_exact_mut(8).zip(src[pos..].chunks(stride)) { | |
71 | dline.copy_from_slice(&sline[..8]); | |
72 | } | |
73 | } | |
74 | ||
75 | pub fn put_block(dst: &mut [u8], dstride: usize, cur_blk: &[u8; 64]) { | |
76 | for (dline, sline) in dst.chunks_mut(dstride).zip(cur_blk.chunks_exact(8)) { | |
77 | dline[..8].copy_from_slice(sline); | |
78 | } | |
79 | } |