| 1 | use nihav_core::frame::NASimpleVideoFrame; |
| 2 | use super::types::SliceState; |
| 3 | use super::dsp::*; |
| 4 | |
| 5 | const ALPHA: [i16; 52] = [ |
| 6 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 7 | 4, 4, 5, 6, 7, 8, 9, 10, 12, 13, 15, 17, 20, 22, 25, 28, |
| 8 | 32, 36, 40, 45, 50, 56, 63, 71, 80, 90, 100, 113, 127, 144, 162, 182, |
| 9 | 203, 226, 255, 255 |
| 10 | ]; |
| 11 | const BETA: [i16; 52] = [ |
| 12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 13 | 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 6, 6, 7, 7, 8, 8, |
| 14 | 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, |
| 15 | 17, 17, 18, 18 |
| 16 | ]; |
| 17 | |
| 18 | const TC0: [[u8; 3]; 52] = [ |
| 19 | [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], |
| 20 | [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], |
| 21 | [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], |
| 22 | [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], [ 0, 0, 0], |
| 23 | [ 0, 0, 0], [ 0, 0, 1], [ 0, 0, 1], [ 0, 0, 1], |
| 24 | [ 0, 0, 1], [ 0, 1, 1], [ 0, 1, 1], [ 1, 1, 1], |
| 25 | [ 1, 1, 1], [ 1, 1, 1], [ 1, 1, 1], [ 1, 1, 2], |
| 26 | [ 1, 1, 2], [ 1, 1, 2], [ 1, 1, 2], [ 1, 2, 3], |
| 27 | [ 1, 2, 3], [ 2, 2, 3], [ 2, 2, 4], [ 2, 3, 4], |
| 28 | [ 2, 3, 4], [ 3, 3, 5], [ 3, 4, 6], [ 3, 4, 6], |
| 29 | [ 4, 5, 7], [ 4, 5, 8], [ 4, 6, 9], [ 5, 7, 10], |
| 30 | [ 6, 8, 11], [ 6, 8, 13], [ 7, 10, 14], [ 8, 11, 16], |
| 31 | [ 9, 12, 18], [10, 13, 20], [11, 15, 23], [13, 17, 25] |
| 32 | ]; |
| 33 | |
| 34 | fn get_lf_idx(qp0: u8, qp1: u8, off: i8) -> usize { |
| 35 | (i16::from((qp0 + qp1 + 1) >> 1) + i16::from(off)).max(0).min(51) as usize |
| 36 | } |
| 37 | |
| 38 | fn filter_mb_row4_y(dst: &mut [u8], off: usize, stride: usize, dmodes: [u8; 4], quants: [u8; 3], alpha_off: i8, beta_off: i8) { |
| 39 | let q = quants[0]; |
| 40 | let qleft = quants[1]; |
| 41 | let dmode = dmodes[0] & 0xF; |
| 42 | if dmode != 0 { |
| 43 | let index_a_y = get_lf_idx(q, qleft, alpha_off); |
| 44 | let alpha_y = ALPHA[index_a_y]; |
| 45 | let beta_y = BETA[get_lf_idx(q, qleft, beta_off)]; |
| 46 | if dmode == 4 { |
| 47 | loop_filter_lumaedge_v(dst, off, stride, alpha_y, beta_y); |
| 48 | } else { |
| 49 | let tc0 = i16::from(TC0[index_a_y][(dmode - 1) as usize]); |
| 50 | loop_filter_lumanormal_v(dst, off, stride, alpha_y, beta_y, tc0); |
| 51 | } |
| 52 | } |
| 53 | let index_a_y = get_lf_idx(q, q, alpha_off); |
| 54 | let alpha_y = ALPHA[index_a_y]; |
| 55 | let beta_y = BETA[get_lf_idx(q, q, beta_off)]; |
| 56 | |
| 57 | for i in 1..4 { |
| 58 | let dmode = dmodes[i] & 0xF; |
| 59 | if dmode != 0 { |
| 60 | let tc0 = i16::from(TC0[index_a_y][(dmode - 1) as usize]); |
| 61 | loop_filter_lumanormal_v(dst, off + i * 4, stride, alpha_y, beta_y, tc0); |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | let qtop = quants[2]; |
| 66 | let index_a_y = get_lf_idx(q, qtop, alpha_off); |
| 67 | let alpha_y = ALPHA[index_a_y]; |
| 68 | let beta_y = BETA[get_lf_idx(q, qtop, beta_off)]; |
| 69 | for i in 0..4 { |
| 70 | let dmode = dmodes[i] >> 4; |
| 71 | if dmode == 4 { |
| 72 | loop_filter_lumaedge_h(dst, off + i * 4, stride, alpha_y, beta_y); |
| 73 | } else if dmode != 0 { |
| 74 | let tc0 = i16::from(TC0[index_a_y][(dmode - 1) as usize]); |
| 75 | loop_filter_lumanormal_h(dst, off + i * 4, stride, alpha_y, beta_y, tc0); |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | fn filter_mb_row4_c(dst: &mut [u8], off: usize, stride: usize, dmodes: [u8; 4], quants: [u8; 3], alpha_off: i8, beta_off: i8) { |
| 81 | let q = quants[0]; |
| 82 | let qleft = quants[1]; |
| 83 | |
| 84 | let dmode = dmodes[0] & 0xF; |
| 85 | if dmode != 0 { |
| 86 | let index_a_c = get_lf_idx(q, qleft, alpha_off); |
| 87 | let alpha_c = ALPHA[index_a_c]; |
| 88 | let beta_c = BETA[get_lf_idx(q, qleft, beta_off)]; |
| 89 | if dmode == 4 { |
| 90 | loop_filter_chromaedge_v(dst, off, stride, alpha_c, beta_c); |
| 91 | } else { |
| 92 | let tc0 = i16::from(TC0[index_a_c][(dmode - 1) as usize]); |
| 93 | loop_filter_chromanormal_v(dst, off, stride, alpha_c, beta_c, tc0); |
| 94 | } |
| 95 | } |
| 96 | let dmode = dmodes[2] & 0xF; |
| 97 | if dmode != 0 { |
| 98 | let index_a_c = get_lf_idx(q, q, alpha_off); |
| 99 | let alpha_c = ALPHA[index_a_c]; |
| 100 | let beta_c = BETA[get_lf_idx(q, q, beta_off)]; |
| 101 | let tc0 = i16::from(TC0[index_a_c][(dmode - 1) as usize]); |
| 102 | loop_filter_chromanormal_v(dst, off + 4, stride, alpha_c, beta_c, tc0); |
| 103 | } |
| 104 | |
| 105 | let qtop = quants[2]; |
| 106 | let index_a_c = get_lf_idx(q, qtop, alpha_off); |
| 107 | let alpha_c = ALPHA[index_a_c]; |
| 108 | let beta_c = BETA[get_lf_idx(q, qtop, beta_off)]; |
| 109 | for i in 0..2 { |
| 110 | let dmode = dmodes[i * 2] >> 4; |
| 111 | if dmode == 4 { |
| 112 | loop_filter_chromaedge_h(dst, off + i * 4, stride, alpha_c, beta_c); |
| 113 | } else if dmode != 0 { |
| 114 | let tc0 = i16::from(TC0[index_a_c][(dmode - 1) as usize]); |
| 115 | loop_filter_chromanormal_h(dst, off + i * 4, stride, alpha_c, beta_c, tc0); |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | pub fn loop_filter_row(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, alpha_off: i8, beta_off: i8) { |
| 121 | let mut db_idx = sstate.deblock.xpos - sstate.deblock.stride; |
| 122 | let mut yoff = frm.offset[0] + sstate.mb_y * 16 * frm.stride[0]; |
| 123 | let mut uoff = frm.offset[1] + sstate.mb_y * 8 * frm.stride[1]; |
| 124 | let mut voff = frm.offset[2] + sstate.mb_y * 8 * frm.stride[2]; |
| 125 | let mut tlq = [0; 3]; |
| 126 | let mut lq = [0; 3]; |
| 127 | let mut mb_idx = sstate.mb.xpos; |
| 128 | for _mb_x in 0..sstate.mb_w { |
| 129 | let mut tqy = sstate.mb.data[mb_idx - sstate.mb.stride].qp_y; |
| 130 | let tqu = sstate.mb.data[mb_idx - sstate.mb.stride].qp_u; |
| 131 | let tqv = sstate.mb.data[mb_idx - sstate.mb.stride].qp_v; |
| 132 | if sstate.mb_y > 0 { |
| 133 | let dmodes = [sstate.deblock.data[db_idx], |
| 134 | sstate.deblock.data[db_idx + 1], |
| 135 | sstate.deblock.data[db_idx + 2], |
| 136 | sstate.deblock.data[db_idx + 3]]; |
| 137 | |
| 138 | filter_mb_row4_y(frm.data, yoff - frm.stride[0] * 4, frm.stride[0], dmodes, [tqy, tlq[0], tqy], alpha_off, beta_off); |
| 139 | filter_mb_row4_c(frm.data, uoff - frm.stride[1] * 4, frm.stride[1], dmodes, [tqu, tlq[1], tqu], alpha_off, beta_off); |
| 140 | filter_mb_row4_c(frm.data, voff - frm.stride[2] * 4, frm.stride[2], dmodes, [tqv, tlq[2], tqv], alpha_off, beta_off); |
| 141 | |
| 142 | tlq = [tqy, tqu, tqv]; |
| 143 | } |
| 144 | |
| 145 | let qy = sstate.mb.data[mb_idx].qp_y; |
| 146 | let qu = sstate.mb.data[mb_idx].qp_u; |
| 147 | let qv = sstate.mb.data[mb_idx].qp_v; |
| 148 | |
| 149 | for y in 0..3 { |
| 150 | db_idx += sstate.deblock.stride; |
| 151 | let dmodes = [sstate.deblock.data[db_idx], |
| 152 | sstate.deblock.data[db_idx + 1], |
| 153 | sstate.deblock.data[db_idx + 2], |
| 154 | sstate.deblock.data[db_idx + 3]]; |
| 155 | |
| 156 | filter_mb_row4_y(frm.data, yoff + frm.stride[0] * 4 * y, frm.stride[0], dmodes, [qy, lq[0], tqy], alpha_off, beta_off); |
| 157 | if y == 0 { |
| 158 | filter_mb_row4_c(frm.data, uoff + frm.stride[1] * 2 * y, frm.stride[1], dmodes, [qu, lq[1], tqu], alpha_off, beta_off); |
| 159 | filter_mb_row4_c(frm.data, voff + frm.stride[2] * 2 * y, frm.stride[2], dmodes, [qv, lq[2], tqv], alpha_off, beta_off); |
| 160 | } |
| 161 | tqy = qy; |
| 162 | } |
| 163 | db_idx -= sstate.deblock.stride * 3; |
| 164 | lq = [qy, qu, qv]; |
| 165 | |
| 166 | mb_idx += 1; |
| 167 | db_idx += 4; |
| 168 | yoff += 16; |
| 169 | uoff += 8; |
| 170 | voff += 8; |
| 171 | } |
| 172 | } |
| 173 | pub fn loop_filter_last(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, alpha_off: i8, beta_off: i8) { |
| 174 | let mut db_idx = sstate.deblock.xpos + 3 * sstate.deblock.stride; |
| 175 | let mut yoff = frm.offset[0] + (sstate.mb_y * 16 + 12) * frm.stride[0]; |
| 176 | let mut uoff = frm.offset[1] + (sstate.mb_y * 8 + 4) * frm.stride[1]; |
| 177 | let mut voff = frm.offset[2] + (sstate.mb_y * 8 + 4) * frm.stride[2]; |
| 178 | |
| 179 | let mut lq = [0; 3]; |
| 180 | let mut mb_idx = sstate.mb.xpos; |
| 181 | if sstate.mb_y != 0 && sstate.mb_x == 0 { |
| 182 | db_idx -= 4 * sstate.deblock.stride; |
| 183 | mb_idx -= sstate.mb.stride; |
| 184 | yoff -= 16 * frm.stride[0]; |
| 185 | uoff -= 8 * frm.stride[1]; |
| 186 | voff -= 8 * frm.stride[2]; |
| 187 | } |
| 188 | for _mb_x in 0..sstate.mb_w { |
| 189 | let qy = sstate.mb.data[mb_idx].qp_y; |
| 190 | let qu = sstate.mb.data[mb_idx].qp_u; |
| 191 | let qv = sstate.mb.data[mb_idx].qp_v; |
| 192 | |
| 193 | let dmodes = [sstate.deblock.data[db_idx], |
| 194 | sstate.deblock.data[db_idx + 1], |
| 195 | sstate.deblock.data[db_idx + 2], |
| 196 | sstate.deblock.data[db_idx + 3]]; |
| 197 | |
| 198 | filter_mb_row4_y(frm.data, yoff, frm.stride[0], dmodes, [qy, lq[0], qy], alpha_off, beta_off); |
| 199 | filter_mb_row4_c(frm.data, uoff, frm.stride[1], dmodes, [qu, lq[1], qu], alpha_off, beta_off); |
| 200 | filter_mb_row4_c(frm.data, voff, frm.stride[2], dmodes, [qv, lq[2], qv], alpha_off, beta_off); |
| 201 | |
| 202 | lq = [qy, qu, qv]; |
| 203 | mb_idx += 1; |
| 204 | db_idx += 4; |
| 205 | yoff += 16; |
| 206 | uoff += 8; |
| 207 | voff += 8; |
| 208 | } |
| 209 | } |
| 210 | |