]>
Commit | Line | Data |
---|---|---|
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 | macro_rules! filter_edge_func { | |
39 | ($funcname: ident, $edgefilter: ident, $normfilter: ident) => { | |
40 | fn $funcname(dst: &mut [u8], off: usize, stride: usize, dmode: u8, quants: [u8; 2], alpha_off: i8, beta_off: i8) { | |
41 | let q = quants[0]; | |
42 | let qleft = quants[1]; | |
43 | if dmode != 0 { | |
44 | let index_a = get_lf_idx(q, qleft, alpha_off); | |
45 | let alpha = ALPHA[index_a]; | |
46 | let beta = BETA[get_lf_idx(q, qleft, beta_off)]; | |
47 | if dmode == 4 { | |
48 | $edgefilter(dst, off, stride, alpha, beta); | |
49 | } else { | |
50 | let tc0 = i16::from(TC0[index_a][(dmode - 1) as usize]); | |
51 | $normfilter(dst, off, stride, alpha, beta, tc0); | |
52 | } | |
53 | } | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
58 | filter_edge_func!(filter_edge_y_v, loop_filter_lumaedge_v, loop_filter_lumanormal_v); | |
59 | filter_edge_func!(filter_edge_y_h, loop_filter_lumaedge_h, loop_filter_lumanormal_h); | |
60 | filter_edge_func!(filter_edge_c_v, loop_filter_chromaedge_v, loop_filter_chromanormal_v); | |
61 | filter_edge_func!(filter_edge_c_h, loop_filter_chromaedge_h, loop_filter_chromanormal_h); | |
62 | ||
63 | pub fn loop_filter_mb(frm: &mut NASimpleVideoFrame<u8>, sstate: &SliceState, alpha_off: i8, beta_off: i8) { | |
64 | let yoff = frm.offset[0] + sstate.mb_x * 16 + sstate.mb_y * 16 * frm.stride[0]; | |
65 | let uoff = frm.offset[1] + sstate.mb_x * 8 + sstate.mb_y * 8 * frm.stride[1]; | |
66 | let voff = frm.offset[2] + sstate.mb_x * 8 + sstate.mb_y * 8 * frm.stride[2]; | |
67 | let mb_idx = sstate.mb.xpos + sstate.mb_x; | |
68 | ||
69 | let lqy = sstate.mb.data[mb_idx - 1].qp_y; | |
70 | let lqu = sstate.mb.data[mb_idx - 1].qp_u; | |
71 | let lqv = sstate.mb.data[mb_idx - 1].qp_v; | |
72 | let qy = sstate.mb.data[mb_idx].qp_y; | |
73 | let qu = sstate.mb.data[mb_idx].qp_u; | |
74 | let qv = sstate.mb.data[mb_idx].qp_v; | |
75 | ||
76 | for (y, dmodes) in sstate.deblock.chunks(4).enumerate() { | |
77 | filter_edge_y_v(frm.data, yoff + y * 4 * frm.stride[0], frm.stride[0], dmodes[0] & 0xF, [qy, lqy], alpha_off, beta_off); | |
78 | for x in 1..4 { | |
79 | filter_edge_y_v(frm.data, yoff + x * 4 + y * 4 * frm.stride[0], frm.stride[0], dmodes[x] & 0xF, [qy, qy], alpha_off, beta_off); | |
80 | } | |
81 | filter_edge_c_v(frm.data, uoff + y * 2 * frm.stride[1], frm.stride[1], dmodes[0] & 0xF, [qu, lqu], alpha_off, beta_off); | |
82 | filter_edge_c_v(frm.data, uoff + y * 2 * frm.stride[1] + 4, frm.stride[1], dmodes[2] & 0xF, [qu, qu], alpha_off, beta_off); | |
83 | filter_edge_c_v(frm.data, voff + y * 2 * frm.stride[2], frm.stride[2], dmodes[0] & 0xF, [qv, lqv], alpha_off, beta_off); | |
84 | filter_edge_c_v(frm.data, voff + y * 2 * frm.stride[2] + 4, frm.stride[2], dmodes[2] & 0xF, [qv, qv], alpha_off, beta_off); | |
85 | } | |
86 | ||
87 | let tqy = sstate.mb.data[mb_idx - sstate.mb.stride].qp_y; | |
88 | let tqu = sstate.mb.data[mb_idx - sstate.mb.stride].qp_u; | |
89 | let tqv = sstate.mb.data[mb_idx - sstate.mb.stride].qp_v; | |
90 | ||
91 | let dmodes = &sstate.deblock; | |
92 | for x in 0..4 { | |
93 | filter_edge_y_h(frm.data, yoff + x * 4, frm.stride[0], dmodes[x] >> 4, [qy, tqy], alpha_off, beta_off); | |
94 | } | |
95 | for x in 0..4 { | |
96 | filter_edge_c_h(frm.data, uoff + x * 2, frm.stride[1], dmodes[x] >> 4, [qu, tqu], alpha_off, beta_off); | |
97 | filter_edge_c_h(frm.data, voff + x * 2, frm.stride[2], dmodes[x] >> 4, [qv, tqv], alpha_off, beta_off); | |
98 | } | |
99 | ||
100 | for (y, dmodes) in sstate.deblock.chunks(4).enumerate().skip(1) { | |
101 | for x in 0..4 { | |
102 | filter_edge_y_h(frm.data, yoff + x * 4 + y * 4 * frm.stride[0], frm.stride[0], dmodes[x] >> 4, [qy, qy], alpha_off, beta_off); | |
103 | } | |
104 | } | |
105 | ||
106 | let dmodes = &sstate.deblock[4 * 2..]; | |
107 | for x in 0..4 { | |
108 | filter_edge_c_h(frm.data, uoff + x * 2 + frm.stride[1] * 4, frm.stride[1], dmodes[x] >> 4, [qu, qu], alpha_off, beta_off); | |
109 | filter_edge_c_h(frm.data, voff + x * 2 + frm.stride[2] * 4, frm.stride[2], dmodes[x] >> 4, [qv, qv], alpha_off, beta_off); | |
110 | } | |
111 | } |