1 use nihav_core::frame::{FrameType, NAVideoBuffer};
2 use nihav_codec_support::codecs::MV;
3 use nihav_codec_support::codecs::blockdsp::edge_emu;
4 use super::rv3040::{RV34DSP, RV34MBInfo};
6 fn clip8(a: i16) -> u8 {
8 else if a > 255 { 255 }
12 fn rv3_filter_h(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, bsize: usize, c1: i16, c2: i16) {
15 dst[didx + x] = clip8((-((src[sidx + x - 1] as i16) + (src[sidx + x + 2] as i16)) + (src[sidx + x + 0] as i16) * c1 + (src[sidx + x + 1] as i16) * c2 + 8) >> 4);
22 fn rv3_filter_v(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, bsize: usize, c1: i16, c2: i16) {
25 dst[didx + x] = clip8((-((src[sidx + x - 1 * sstride] as i16) + (src[sidx + x + 2 * sstride] as i16)) + (src[sidx + x + 0 * sstride] as i16) * c1 + (src[sidx + x + 1 * sstride] as i16) * c2 + 8) >> 4);
32 macro_rules! mc_matrix {
33 ($s: ident, $o: expr, $c1: expr) => (
34 ($c1 * 6) * ($s[$o] as i32) + ($c1 * 9) * ($s[$o + 1] as i32) + ($c1) * ($s[$o + 2] as i32)
36 ($s: ident, $o: expr, $c1: expr, $d1: expr, $d2: expr) => (
37 -($c1) * ($s[$o - 1] as i32) + ($c1 * $d1) * ($s[$o] as i32) + ($c1 * $d2) * ($s[$o + 1] as i32) + -($c1) * ($s[$o + 2] as i32)
39 ($s: ident, $o: expr, $ss: expr, $c1: expr, $c2: expr, $d1: expr, $d2: expr) => (
40 ((mc_matrix!($s, $o - $ss, -1, $d1, $d2) +
41 mc_matrix!($s, $o , $c1, $d1, $d2) +
42 mc_matrix!($s, $o + $ss, $c2, $d1, $d2) +
43 mc_matrix!($s, $o + 2 * $ss, -1, $d1, $d2) + 128) >> 8) as i16
45 (m22; $s: ident, $o: expr, $ss: expr) => (
46 ((mc_matrix!($s, $o + 0 * $ss, 6) +
47 mc_matrix!($s, $o + 1 * $ss, 9) +
48 mc_matrix!($s, $o + 2 * $ss, 1) + 128) >> 8) as i16
52 macro_rules! mc_func {
53 (copy; $name: ident, $size: expr) => (
54 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
56 let d = &mut dst[didx..][..$size];
57 let s = &src[sidx..][..$size];
58 for x in 0..$size { d[x] = s[x]; }
64 (hor; $name: ident, $c1: expr, $c2: expr, $size: expr) => (
65 fn $name (dst: &mut [u8], didx: usize, dstride: usize, src: &[u8], sidx: usize, sstride: usize) {
66 rv3_filter_h(dst, didx, dstride, src, sidx, sstride, $size, $c1, $c2);
69 (ver; $name: ident, $c1: expr, $c2: expr, $size: expr) => (
70 fn $name (dst: &mut [u8], didx: usize, dstride: usize, src: &[u8], sidx: usize, sstride: usize) {
71 rv3_filter_v(dst, didx, dstride, src, sidx, sstride, $size, $c1, $c2);
74 (m11; $name: ident, $size: expr) => (
75 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
78 dst[didx + x] = clip8(mc_matrix!(src, sidx + x, sstride, 12, 6, 12, 6));
85 (m12; $name: ident, $size: expr) => (
86 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
89 dst[didx + x] = clip8(mc_matrix!(src, sidx + x, sstride, 6, 12, 12, 6));
96 (m21; $name: ident, $size: expr) => (
97 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
100 dst[didx + x] = clip8(mc_matrix!(src, sidx + x, sstride, 12, 6, 6, 12));
107 (m22; $name: ident, $size: expr) => (
108 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
111 dst[didx + x] = clip8(mc_matrix!(m22; src, sidx + x, sstride));
119 mc_func!(copy; copy_16, 16);
120 mc_func!(copy; copy_8, 8);
121 mc_func!(hor; luma_mc_10_16, 12, 6, 16);
122 mc_func!(hor; luma_mc_20_16, 6, 12, 16);
123 mc_func!(hor; luma_mc_10_8, 12, 6, 8);
124 mc_func!(hor; luma_mc_20_8, 6, 12, 8);
125 mc_func!(ver; luma_mc_01_16, 12, 6, 16);
126 mc_func!(ver; luma_mc_02_16, 6, 12, 16);
127 mc_func!(ver; luma_mc_01_8, 12, 6, 8);
128 mc_func!(ver; luma_mc_02_8, 6, 12, 8);
129 mc_func!(m11; luma_mc_11_16, 16);
130 mc_func!(m11; luma_mc_11_8, 8);
131 mc_func!(m21; luma_mc_21_16, 16);
132 mc_func!(m21; luma_mc_21_8, 8);
133 mc_func!(m12; luma_mc_12_16, 16);
134 mc_func!(m12; luma_mc_12_8, 8);
135 mc_func!(m22; luma_mc_22_16, 16);
136 mc_func!(m22; luma_mc_22_8, 8);
138 const RV30_CHROMA_FRAC1: [u16; 3] = [ 8, 5, 3 ];
139 const RV30_CHROMA_FRAC2: [u16; 3] = [ 0, 3, 5 ];
140 fn rv30_chroma_mc(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, size: usize, x: usize, y: usize) {
141 if (x == 0) && (y == 0) {
143 dst[didx..][..size].copy_from_slice(&src[sidx..][..size]);
149 let a = RV30_CHROMA_FRAC1[x] * RV30_CHROMA_FRAC1[y];
150 let b = RV30_CHROMA_FRAC2[x] * RV30_CHROMA_FRAC1[y];
151 let c = RV30_CHROMA_FRAC1[x] * RV30_CHROMA_FRAC2[y];
152 let d = RV30_CHROMA_FRAC2[x] * RV30_CHROMA_FRAC2[y];
155 dst[didx + x] = ((a * (src[sidx + x] as u16)
156 + b * (src[sidx + x + 1] as u16)
157 + c * (src[sidx + x + sstride] as u16)
158 + d * (src[sidx + x + 1 + sstride] as u16) + 32) >> 6) as u8;
165 #[allow(clippy::type_complexity)]
167 luma_mc: [[fn (&mut [u8], usize, usize, &[u8], usize, usize); 9]; 2],
171 pub fn new() -> Self {
174 [ copy_16, luma_mc_10_16, luma_mc_20_16,
175 luma_mc_01_16, luma_mc_11_16, luma_mc_21_16,
176 luma_mc_02_16, luma_mc_12_16, luma_mc_22_16 ],
177 [ copy_8, luma_mc_10_8, luma_mc_20_8,
178 luma_mc_01_8, luma_mc_11_8, luma_mc_21_8,
179 luma_mc_02_8, luma_mc_12_8, luma_mc_22_8 ] ],
185 ($src: ident, $o: expr) => ($src[$o] as i16);
188 fn clip_symm(a: i16, lim: i16) -> i16 {
198 const RV30_LOOP_FILTER_STRENGTH: [i16; 32] = [
199 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
200 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5
203 macro_rules! test_bit {
204 ($pat: expr, $x: expr) => ( (($pat >> $x) & 1) != 0 )
207 fn rv30_loop_filter4(pix: &mut [u8], mut off: usize, step: usize, stride: usize, lim: i16) {
209 let a = el!(pix, off - 2*step);
210 let b = el!(pix, off - step);
211 let c = el!(pix, off);
212 let d = el!(pix, off + step);
213 let diff0 = ((a - d) - (b - c) * 4) >> 3;
214 let diff = clip_symm(diff0, lim);
215 pix[off - step] = clip8(b + diff);
216 pix[off ] = clip8(c - diff);
221 fn rv30_div_mv(mv: i16) -> (i16, usize) {
225 (i - 1, (f + 3) as usize)
231 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 {
232 let xn = (x as isize) + (dx as isize);
233 let yn = (y as isize) + (dy as isize);
235 (xn - e0 >= 0) && (xn + (size as isize) + e1 <= (w as isize)) && (yn - e2 >= 0) && (yn + (size as isize) + e3 <= (h as isize))
238 const RV30_EDGE1: [isize; 3] = [ 0, 1, 1 ];
239 const RV30_EDGE2: [isize; 3] = [ 0, 2, 2 ];
241 impl RV34DSP for RV30DSP {
242 #[allow(clippy::cognitive_complexity)]
243 fn loop_filter(&self, frame: &mut NAVideoBuffer<u8>, _ftype: FrameType, mbinfo: &[RV34MBInfo], mb_w: usize, _mb_h: usize, row: usize) {
244 let mut offs: [usize; 3] = [0; 3];
245 let mut stride: [usize; 3] = [0; 3];
248 stride[comp] = frame.get_stride(comp);
249 let start = if comp == 0 { row * 16 } else { row * 8 };
250 offs[comp] = frame.get_offset(comp) + start * stride[comp];
253 let data = frame.get_data_mut().unwrap();
254 let dst: &mut [u8] = data.as_mut_slice();
257 let mut left_cbp = 0;
258 let mut left_lim = 0;
259 let mut left_dbk = 0;
260 let mut mb_pos: usize = row * mb_w;
261 for mb_x in 0..mb_w {
262 let cur_lim = RV30_LOOP_FILTER_STRENGTH[mbinfo[mb_pos].q as usize];
263 let cur_dbk = mbinfo[mb_pos].deblock;
264 let cur_cbp = mbinfo[mb_pos].cbp_c;
265 let xstart = if mb_x == 0 { 1 } else { 0 };
267 let yoff = offs[0] + mb_x * 16 + y * 4 * stride[0];
272 if test_bit!(cur_dbk, cs) {
274 } else if (x == 0) && test_bit!(left_dbk, cs + 3) {
276 } else if (x != 0) && test_bit!(cur_dbk, cs - 1) {
282 rv30_loop_filter4(dst, yoff + x * 4, 1, stride[0], loc_lim);
289 let coff = offs[comp] + mb_x * 8 + y * 4 * stride[comp];
291 let cs = x + y * 2 + (comp - 1) * 4;
294 if test_bit!(cur_cbp, cs) {
296 } else if (x == 0) && test_bit!(left_cbp, cs + 1) {
298 } else if (x != 0) && test_bit!(cur_cbp, cs - 1) {
304 rv30_loop_filter4(dst, coff + x * 4, 1, stride[comp], loc_lim);
317 let mut mb_pos: usize = row * mb_w;
318 for mb_x in 0..mb_w {
319 let cur_lim = RV30_LOOP_FILTER_STRENGTH[mbinfo[mb_pos].q as usize];
320 let cur_dbk = mbinfo[mb_pos].deblock;
321 let cur_cbp = mbinfo[mb_pos].cbp_c;
322 let ystart = if row == 0 { 1 } else { 0 };
327 top_lim = RV30_LOOP_FILTER_STRENGTH[mbinfo[mb_pos - mb_w].q as usize];
328 top_dbk = mbinfo[mb_pos - mb_w].deblock;
329 top_cbp = mbinfo[mb_pos - mb_w].cbp_c;
336 let yoff = offs[0] + mb_x * 16 + y * 4 * stride[0];
341 if test_bit!(cur_dbk, cs) {
343 } else if (y == 0) && test_bit!(top_dbk, cs + 12) {
345 } else if (y != 0) && test_bit!(cur_dbk, cs - 4) {
351 rv30_loop_filter4(dst, yoff + x * 4, stride[0], 1, loc_lim);
358 let coff = offs[comp] + mb_x * 8 + y * 4 * stride[comp];
360 let cs = x + y * 2 + (comp - 1) * 4;
363 if test_bit!(cur_cbp, cs) {
365 } else if (y == 0) && test_bit!(top_cbp, cs + 2) {
367 } else if (y != 0) && test_bit!(cur_cbp, cs - 2) {
373 rv30_loop_filter4(dst, coff + x * 4, stride[comp], 1, loc_lim);
382 fn do_luma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, mv: MV, use16: bool, avg: bool) {
383 let size: usize = if use16 { 16 } else { 8 };
384 let dstride = frame.get_stride(0);
385 let doffset = frame.get_offset(0) + (if !avg { x + y * dstride } else { 0 });
386 let data = frame.get_data_mut().unwrap();
387 let dst: &mut [u8] = data.as_mut_slice();
389 let (w_, h_) = prev_frame.get_dimensions(0);
390 let w = (w_ + 15) & !15;
391 let h = (h_ + 15) & !15;
393 let (dx, cx) = rv30_div_mv(mv.x);
394 let (dy, cy) = rv30_div_mv(mv.y);
395 let mode = cx + cy * 3;
397 if check_pos(x, y, size, w, h, dx, dy, RV30_EDGE1[cx], RV30_EDGE2[cx], RV30_EDGE1[cy], RV30_EDGE2[cy]) {
398 let sstride = prev_frame.get_stride(0);
399 let mut soffset = prev_frame.get_offset(0) + x + y * sstride;
400 let data = prev_frame.get_data();
401 let src: &[u8] = data.as_slice();
402 soffset = ((soffset as isize) + (dx as isize) + (dy as isize) * (sstride as isize)) as usize;
403 self.luma_mc[if use16 { 0 } else { 1 }][mode](dst, doffset, dstride, src, soffset, sstride);
405 let mut ebuf: [u8; 32*20] = [0; 32*20];
406 edge_emu(prev_frame, (x as isize) + (dx as isize) - 1, (y as isize) + (dy as isize) - 1, 16+3, 16+3, &mut ebuf, 32, 0, 4);
407 self.luma_mc[if use16 { 0 } else { 1 }][mode](dst, doffset, dstride, &ebuf, 32 + 1, 32);
410 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) {
411 let size: usize = if use8 { 8 } else { 4 };
412 let dstride = frame.get_stride(comp);
413 let doffset = frame.get_offset(comp) + (if !avg { x + y * dstride } else { 0 });
414 let data = frame.get_data_mut().unwrap();
415 let dst: &mut [u8] = data.as_mut_slice();
417 let (w_, h_) = prev_frame.get_dimensions(comp);
418 let w = (w_ + 7) & !7;
419 let h = (h_ + 7) & !7;
421 let (dx, cx) = rv30_div_mv(mv.x / 2);
422 let (dy, cy) = rv30_div_mv(mv.y / 2);
424 if check_pos(x, y, size, w, h, dx, dy, 0, 1, 0, 1) {
425 let sstride = prev_frame.get_stride(comp);
426 let mut soffset = prev_frame.get_offset(comp) + x + y * sstride;
427 let data = prev_frame.get_data();
428 let src: &[u8] = data.as_slice();
429 soffset = ((soffset as isize) + (dx as isize) + (dy as isize) * (sstride as isize)) as usize;
430 rv30_chroma_mc(dst, doffset, dstride, src, soffset, sstride, size, cx, cy);
432 let mut ebuf: [u8; 16*10] = [0; 16*10];
433 edge_emu(prev_frame, (x as isize) + (dx as isize), (y as isize) + (dy as isize), 8+1, 8+1, &mut ebuf, 16, comp, 4);
434 rv30_chroma_mc(dst, doffset, dstride, &ebuf, 0, 16, size, cx, cy);