add LinePack decoder
[nihav.git] / nihav-itu / src / codecs / h264 / loopfilter.rs
CommitLineData
696e4e20
KS
1use nihav_core::frame::NASimpleVideoFrame;
2use super::types::SliceState;
3use super::dsp::*;
4
5const 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];
11const 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
18const 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
34fn 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
22de733b
KS
38macro_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 }
696e4e20
KS
54 }
55 }
22de733b 56}
696e4e20 57
22de733b
KS
58filter_edge_func!(filter_edge_y_v, loop_filter_lumaedge_v, loop_filter_lumanormal_v);
59filter_edge_func!(filter_edge_y_h, loop_filter_lumaedge_h, loop_filter_lumanormal_h);
60filter_edge_func!(filter_edge_c_v, loop_filter_chromaedge_v, loop_filter_chromanormal_v);
61filter_edge_func!(filter_edge_c_h, loop_filter_chromaedge_h, loop_filter_chromanormal_h);
62
63pub 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);
696e4e20 80 }
22de733b
KS
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);
696e4e20 85 }
696e4e20 86
22de733b
KS
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;
696e4e20 90
22de733b
KS
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);
696e4e20 94 }
22de733b
KS
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);
696e4e20
KS
98 }
99
22de733b
KS
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);
696e4e20
KS
103 }
104 }
696e4e20 105
22de733b
KS
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);
696e4e20
KS
110 }
111}