]>
Commit | Line | Data |
---|---|---|
5641dccf KS |
1 | use frame::NAVideoBuffer; |
2 | use codecs::MV; | |
3 | use codecs::blockdsp::edge_emu; | |
4 | use super::rv3040::{RV34DSP, RV34MBInfo}; | |
5 | ||
6 | fn clip8(a: i16) -> u8 { | |
7 | if a < 0 { 0 } | |
8 | else if a > 255 { 255 } | |
9 | else { a as u8 } | |
10 | } | |
11 | ||
12 | macro_rules! el { | |
13 | ($s: ident, $o: expr) => ( $s[$o] as i16 ) | |
14 | } | |
15 | ||
16 | macro_rules! filter { | |
17 | (01; $s: ident, $o: expr, $step: expr) => ( | |
18 | clip8((( el!($s, $o - 2 * $step) | |
19 | -5 * el!($s, $o - 1 * $step) | |
20 | +52 * el!($s, $o - 0 * $step) | |
21 | +20 * el!($s, $o + 1 * $step) | |
22 | -5 * el!($s, $o + 2 * $step) | |
23 | + el!($s, $o + 3 * $step) + 32) >> 6) as i16) | |
24 | ); | |
25 | (02; $s: ident, $o: expr, $step: expr) => ( | |
26 | clip8((( el!($s, $o - 2 * $step) | |
27 | -5 * el!($s, $o - 1 * $step) | |
28 | +20 * el!($s, $o - 0 * $step) | |
29 | +20 * el!($s, $o + 1 * $step) | |
30 | -5 * el!($s, $o + 2 * $step) | |
31 | + el!($s, $o + 3 * $step) + 16) >> 5) as i16) | |
32 | ); | |
33 | (03; $s: ident, $o: expr, $step: expr) => ( | |
34 | clip8((( el!($s, $o - 2 * $step) | |
35 | -5 * el!($s, $o - 1 * $step) | |
36 | +20 * el!($s, $o - 0 * $step) | |
37 | +52 * el!($s, $o + 1 * $step) | |
38 | -5 * el!($s, $o + 2 * $step) | |
39 | + el!($s, $o + 3 * $step) + 32) >> 6) as i16) | |
40 | ); | |
41 | } | |
42 | ||
43 | trait HFilt { | |
44 | const HMODE: usize; | |
45 | fn filter_h(src: &[u8], idx: usize) -> u8 { | |
46 | match Self::HMODE { | |
47 | 1 => filter!(01; src, idx, 1), | |
48 | 2 => filter!(02; src, idx, 1), | |
49 | 3 => filter!(03; src, idx, 1), | |
50 | _ => src[idx], | |
51 | } | |
52 | } | |
53 | } | |
54 | trait VFilt { | |
55 | const VMODE: usize; | |
56 | fn filter_v(src: &[u8], idx: usize, stride: usize) -> u8 { | |
57 | match Self::VMODE { | |
58 | 1 => filter!(01; src, idx, stride), | |
59 | 2 => filter!(02; src, idx, stride), | |
60 | 3 => filter!(03; src, idx, stride), | |
61 | _ => src[idx], | |
62 | } | |
63 | } | |
64 | } | |
65 | trait MC: HFilt+VFilt { | |
66 | const SIZE: usize; | |
67 | fn mc(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) { | |
68 | if (Self::HMODE != 0) && (Self::VMODE != 0) { | |
69 | let mut buf: [u8; (16 + 5) * 16] = [0; (16 + 5) * 16]; | |
70 | let mut bidx = 0; | |
71 | let bstride = Self::SIZE; | |
72 | sidx -= sstride * 2; | |
73 | for _ in 0..Self::SIZE+5 { | |
74 | for x in 0..Self::SIZE { buf[bidx + x] = Self::filter_h(src, sidx + x); } | |
75 | bidx += bstride; | |
76 | sidx += sstride; | |
77 | } | |
78 | bidx = bstride * 2; | |
79 | for _ in 0..Self::SIZE { | |
80 | for x in 0..Self::SIZE { dst[didx + x] = Self::filter_v(&buf, bidx + x, bstride); } | |
81 | didx += dstride; | |
82 | bidx += bstride; | |
83 | } | |
84 | } else if Self::HMODE != 0 { | |
85 | for _ in 0..Self::SIZE { | |
86 | for x in 0..Self::SIZE { | |
87 | dst[didx + x] = Self::filter_h(src, sidx + x); | |
88 | } | |
89 | didx += dstride; | |
90 | sidx += sstride; | |
91 | } | |
92 | } else if Self::VMODE != 0 { | |
93 | for _ in 0..Self::SIZE { | |
94 | for x in 0..Self::SIZE { | |
95 | dst[didx + x] = Self::filter_v(src, sidx + x, sstride); | |
96 | } | |
97 | didx += dstride; | |
98 | sidx += sstride; | |
99 | } | |
100 | } else { | |
101 | for _ in 0..Self::SIZE { | |
102 | for x in 0..Self::SIZE { | |
103 | dst[didx + x] = src[sidx + x]; | |
104 | } | |
105 | didx += dstride; | |
106 | sidx += sstride; | |
107 | } | |
108 | } | |
109 | } | |
110 | } | |
111 | ||
112 | macro_rules! mc { | |
113 | ($name: ident, $size: expr, $vf: expr, $hf: expr) => { | |
114 | struct $name; | |
115 | impl HFilt for $name { const HMODE: usize = $hf; } | |
116 | impl VFilt for $name { const VMODE: usize = $vf; } | |
117 | impl MC for $name { const SIZE: usize = $size; } | |
118 | }; | |
119 | } | |
120 | ||
121 | mc!(MC00_16, 16, 0, 0); | |
122 | mc!(MC01_16, 16, 0, 1); | |
123 | mc!(MC02_16, 16, 0, 2); | |
124 | mc!(MC03_16, 16, 0, 3); | |
125 | mc!(MC10_16, 16, 1, 0); | |
126 | mc!(MC11_16, 16, 1, 1); | |
127 | mc!(MC12_16, 16, 1, 2); | |
128 | mc!(MC13_16, 16, 1, 3); | |
129 | mc!(MC20_16, 16, 2, 0); | |
130 | mc!(MC21_16, 16, 2, 1); | |
131 | mc!(MC22_16, 16, 2, 2); | |
132 | mc!(MC23_16, 16, 2, 3); | |
133 | mc!(MC30_16, 16, 3, 1); | |
134 | mc!(MC31_16, 16, 3, 1); | |
135 | mc!(MC32_16, 16, 3, 2); | |
136 | mc!(MC33_16, 16, 3, 3); | |
137 | ||
138 | mc!(MC00_8, 8, 0, 0); | |
139 | mc!(MC01_8, 8, 0, 1); | |
140 | mc!(MC02_8, 8, 0, 2); | |
141 | mc!(MC03_8, 8, 0, 3); | |
142 | mc!(MC10_8, 8, 1, 0); | |
143 | mc!(MC11_8, 8, 1, 1); | |
144 | mc!(MC12_8, 8, 1, 2); | |
145 | mc!(MC13_8, 8, 1, 3); | |
146 | mc!(MC20_8, 8, 2, 0); | |
147 | mc!(MC21_8, 8, 2, 1); | |
148 | mc!(MC22_8, 8, 2, 2); | |
149 | mc!(MC23_8, 8, 2, 3); | |
150 | mc!(MC30_8, 8, 3, 1); | |
151 | mc!(MC31_8, 8, 3, 1); | |
152 | mc!(MC32_8, 8, 3, 2); | |
153 | mc!(MC33_8, 8, 3, 3); | |
154 | ||
155 | ||
156 | const RV40_CHROMA_BIAS: [[u16; 4]; 4] = [ | |
157 | [ 0, 4, 8, 4 ], | |
158 | [ 8, 7, 8, 7 ], | |
159 | [ 0, 8, 4, 8 ], | |
160 | [ 8, 7, 8, 7 ] | |
161 | ]; | |
162 | ||
163 | fn rv40_chroma_mc(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, size: usize, x: usize, y: usize) { | |
164 | if (x == 0) && (y == 0) { | |
165 | for _ in 0..size { | |
166 | for x in 0..size { dst[didx + x] = src[sidx + x]; } | |
167 | didx += dstride; | |
168 | sidx += sstride; | |
169 | } | |
170 | return; | |
171 | } | |
172 | let bias = RV40_CHROMA_BIAS[y >> 1][x >> 1]; | |
173 | if (x > 0) && (y > 0) { | |
174 | let a = ((4 - x) * (4 - y)) as u16; | |
175 | let b = (( x) * (4 - y)) as u16; | |
176 | let c = ((4 - x) * ( y)) as u16; | |
177 | let d = (( x) * ( y)) as u16; | |
178 | for _ in 0..size { | |
179 | for x in 0..size { | |
180 | dst[didx + x] = ((a * (src[sidx + x] as u16) | |
181 | + b * (src[sidx + x + 1] as u16) | |
182 | + c * (src[sidx + x + sstride] as u16) | |
183 | + d * (src[sidx + x + 1 + sstride] as u16) + bias) >> 4) as u8; | |
184 | } | |
185 | didx += dstride; | |
186 | sidx += sstride; | |
187 | } | |
188 | } else { | |
189 | let a = ((4 - x) * (4 - y)) as u16; | |
190 | let e = (( x) * (4 - y) + (4 - x) * ( y)) as u16; | |
191 | let step = if y > 0 { sstride } else { 1 }; | |
192 | for _ in 0..size { | |
193 | for x in 0..size { | |
194 | dst[didx + x] = ((a * (src[sidx + x] as u16) | |
195 | + e * (src[sidx + x + step] as u16) + bias) >> 4) as u8; | |
196 | } | |
197 | didx += dstride; | |
198 | sidx += sstride; | |
199 | } | |
200 | } | |
201 | } | |
202 | ||
203 | pub struct RV40DSP { | |
204 | luma_mc: [[fn (&mut [u8], usize, usize, &[u8], usize, usize); 16]; 2], | |
205 | } | |
206 | ||
207 | impl RV40DSP { | |
208 | pub fn new() -> Self { | |
209 | RV40DSP { | |
210 | luma_mc: [ | |
211 | [ MC00_16::mc, MC01_16::mc, MC02_16::mc, MC03_16::mc, | |
212 | MC10_16::mc, MC11_16::mc, MC12_16::mc, MC13_16::mc, | |
213 | MC20_16::mc, MC21_16::mc, MC22_16::mc, MC23_16::mc, | |
214 | MC30_16::mc, MC31_16::mc, MC32_16::mc, MC33_16::mc ], | |
215 | [ MC00_8::mc, MC01_8::mc, MC02_8::mc, MC03_8::mc, | |
216 | MC10_8::mc, MC11_8::mc, MC12_8::mc, MC13_8::mc, | |
217 | MC20_8::mc, MC21_8::mc, MC22_8::mc, MC23_8::mc, | |
218 | MC30_8::mc, MC31_8::mc, MC32_8::mc, MC33_8::mc ] ], | |
219 | } | |
220 | } | |
221 | } | |
222 | ||
223 | fn check_pos(x: usize, y: usize, size: usize, w: usize, h: usize, dx: i16, dy: i16, e0: isize, e1: isize, e2: isize, e3: isize) -> bool { | |
224 | let xn = (x as isize) + (dx as isize); | |
225 | let yn = (y as isize) + (dy as isize); | |
226 | ||
227 | (xn - e0 >= 0) && (xn + (size as isize) + e1 <= (w as isize)) && (yn - e2 >= 0) && (yn + (size as isize) + e3 <= (h as isize)) | |
228 | } | |
229 | ||
230 | const RV40_EDGE1: [isize; 4] = [ 0, 2, 2, 2 ]; | |
231 | const RV40_EDGE2: [isize; 4] = [ 0, 3, 3, 3 ]; | |
232 | ||
233 | impl RV34DSP for RV40DSP { | |
234 | fn loop_filter(&self, _frame: &mut NAVideoBuffer<u8>, _mbinfo: &[RV34MBInfo], _mb_w: usize, _mb_h: usize) { | |
235 | } | |
236 | fn do_luma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, mv: MV, use16: bool, avg: bool) { | |
237 | let size: usize = if use16 { 16 } else { 8 }; | |
238 | let dstride = frame.get_stride(0); | |
239 | let doffset = frame.get_offset(0) + (if !avg { x + y * dstride } else { 0 }); | |
240 | let mut data = frame.get_data_mut(); | |
241 | let dst: &mut [u8] = data.as_mut_slice(); | |
242 | ||
243 | let (w_, h_) = prev_frame.get_dimensions(0); | |
244 | let w = (w_ + 15) & !15; | |
245 | let h = (h_ + 15) & !15; | |
246 | ||
247 | let dx = mv.x >> 2; | |
248 | let cx = (mv.x & 3) as usize; | |
249 | let dy = mv.y >> 2; | |
250 | let cy = (mv.y & 3) as usize; | |
251 | let mode = cx + cy * 4; | |
252 | ||
253 | if check_pos(x, y, size, w, h, dx, dy, RV40_EDGE1[cx], RV40_EDGE2[cx], RV40_EDGE1[cy], RV40_EDGE2[cy]) { | |
254 | let sstride = prev_frame.get_stride(0); | |
255 | let mut soffset = prev_frame.get_offset(0) + x + y * sstride; | |
256 | let data = prev_frame.get_data(); | |
257 | let src: &[u8] = data.as_slice(); | |
258 | soffset = ((soffset as isize) + (dx as isize) + (dy as isize) * (sstride as isize)) as usize; | |
259 | self.luma_mc[if use16 { 0 } else { 1 }][mode](dst, doffset, dstride, src, soffset, sstride); | |
260 | } else { | |
261 | let mut ebuf: [u8; 32*22] = [0; 32*22]; | |
262 | edge_emu(prev_frame, (x as isize) + (dx as isize) - 2, (y as isize) + (dy as isize) - 2, 16+5, 16+5, &mut ebuf, 32, 0); | |
263 | self.luma_mc[if use16 { 0 } else { 1 }][mode](dst, doffset, dstride, &ebuf, 32*2 + 2, 32); | |
264 | } | |
265 | } | |
266 | fn do_chroma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, comp: usize, mv: MV, use8: bool, avg: bool) { | |
267 | let size: usize = if use8 { 8 } else { 4 }; | |
268 | let dstride = frame.get_stride(comp); | |
269 | let doffset = frame.get_offset(comp) + (if !avg { x + y * dstride } else { 0 }); | |
270 | let mut data = frame.get_data_mut(); | |
271 | let dst: &mut [u8] = data.as_mut_slice(); | |
272 | ||
273 | let (w_, h_) = prev_frame.get_dimensions(comp); | |
274 | let w = (w_ + 7) & !7; | |
275 | let h = (h_ + 7) & !7; | |
276 | ||
277 | let mvx = mv.x / 2; | |
278 | let mvy = mv.y / 2; | |
279 | let dx = mvx >> 2; | |
280 | let mut cx = (mvx & 3) as usize; | |
281 | let dy = mvy >> 2; | |
282 | let mut cy = (mvy & 3) as usize; | |
283 | ||
284 | if (cx == 3) && (cy == 3) { | |
285 | cx = 2; | |
286 | cy = 2; | |
287 | } | |
288 | ||
289 | if check_pos(x, y, size, w, h, dx, dy, 0, 0, 1, 1) { | |
290 | let sstride = prev_frame.get_stride(comp); | |
291 | let mut soffset = prev_frame.get_offset(comp) + x + y * sstride; | |
292 | let data = prev_frame.get_data(); | |
293 | let src: &[u8] = data.as_slice(); | |
294 | soffset = ((soffset as isize) + (dx as isize) + (dy as isize) * (sstride as isize)) as usize; | |
295 | rv40_chroma_mc(dst, doffset, dstride, src, soffset, sstride, size, cx, cy); | |
296 | } else { | |
297 | let mut ebuf: [u8; 16*10] = [0; 16*10]; | |
298 | edge_emu(prev_frame, (x as isize) + (dx as isize), (y as isize) + (dy as isize), 8+1, 8+1, &mut ebuf, 16, comp); | |
299 | rv40_chroma_mc(dst, doffset, dstride, &ebuf, 0, 16, size, cx, cy); | |
300 | } | |
301 | } | |
302 | } |