1const CONST_BITS: i32 = 13;
75const PASS1_BITS: i32 = 2;
76
77const FIX_0_298631336: i32 = 2446;
78const FIX_0_390180644: i32 = 3196;
79const FIX_0_541196100: i32 = 4433;
80const FIX_0_765366865: i32 = 6270;
81const FIX_0_899976223: i32 = 7373;
82const FIX_1_175875602: i32 = 9633;
83const FIX_1_501321110: i32 = 12299;
84const FIX_1_847759065: i32 = 15137;
85const FIX_1_961570560: i32 = 16069;
86const FIX_2_053119869: i32 = 16819;
87const FIX_2_562915447: i32 = 20995;
88const FIX_3_072711026: i32 = 25172;
89
90const DCT_SIZE: usize = 8;
91
92#[inline(always)]
93fn descale(x: i32, n: i32) -> i32 {
94 (x + (1 << (n - 1))) >> n
96}
97
98#[inline(always)]
99fn into_el(v: i32) -> i16 {
100 v as i16
101}
102
103#[allow(clippy::erasing_op)]
104#[allow(clippy::identity_op)]
105pub fn fdct(data: &mut [i16; 64]) {
106 let mut data2 = [0i32; 64];
111
112 for y in 0..8 {
113 let offset = y * 8;
114
115 let tmp0 = i32::from(data[offset + 0]) + i32::from(data[offset + 7]);
116 let tmp7 = i32::from(data[offset + 0]) - i32::from(data[offset + 7]);
117 let tmp1 = i32::from(data[offset + 1]) + i32::from(data[offset + 6]);
118 let tmp6 = i32::from(data[offset + 1]) - i32::from(data[offset + 6]);
119 let tmp2 = i32::from(data[offset + 2]) + i32::from(data[offset + 5]);
120 let tmp5 = i32::from(data[offset + 2]) - i32::from(data[offset + 5]);
121 let tmp3 = i32::from(data[offset + 3]) + i32::from(data[offset + 4]);
122 let tmp4 = i32::from(data[offset + 3]) - i32::from(data[offset + 4]);
123
124 let tmp10 = tmp0 + tmp3;
129 let tmp13 = tmp0 - tmp3;
130 let tmp11 = tmp1 + tmp2;
131 let tmp12 = tmp1 - tmp2;
132
133 data2[offset + 0] = (tmp10 + tmp11) << PASS1_BITS;
134 data2[offset + 4] = (tmp10 - tmp11) << PASS1_BITS;
135
136 let z1 = (tmp12 + tmp13) * FIX_0_541196100;
137 data2[offset + 2] = descale(
138 z1 + (tmp13 * FIX_0_765366865),
139 CONST_BITS - PASS1_BITS,
140 );
141 data2[offset + 6] = descale(
142 z1 + (tmp12 * -FIX_1_847759065),
143 CONST_BITS - PASS1_BITS,
144 );
145
146 let z1 = tmp4 + tmp7;
152 let z2 = tmp5 + tmp6;
153 let z3 = tmp4 + tmp6;
154 let z4 = tmp5 + tmp7;
155 let z5 = (z3 + z4) * FIX_1_175875602; let tmp4 = tmp4 * FIX_0_298631336; let tmp5 = tmp5 * FIX_2_053119869; let tmp6 = tmp6 * FIX_3_072711026; let tmp7 = tmp7 * FIX_1_501321110; let z1 = z1 * -FIX_0_899976223; let z2 = z2 * -FIX_2_562915447; let z3 = z3 * -FIX_1_961570560; let z4 = z4 * -FIX_0_390180644; let z3 = z3 + z5;
167 let z4 = z4 + z5;
168
169 data2[offset + 7] = descale(tmp4 + z1 + z3, CONST_BITS - PASS1_BITS);
170 data2[offset + 5] = descale(tmp5 + z2 + z4, CONST_BITS - PASS1_BITS);
171 data2[offset + 3] = descale(tmp6 + z2 + z3, CONST_BITS - PASS1_BITS);
172 data2[offset + 1] = descale(tmp7 + z1 + z4, CONST_BITS - PASS1_BITS);
173 }
174
175 for x in 0..8 {
181 let tmp0 = data2[DCT_SIZE * 0 + x] + data2[DCT_SIZE * 7 + x];
182 let tmp7 = data2[DCT_SIZE * 0 + x] - data2[DCT_SIZE * 7 + x];
183 let tmp1 = data2[DCT_SIZE * 1 + x] + data2[DCT_SIZE * 6 + x];
184 let tmp6 = data2[DCT_SIZE * 1 + x] - data2[DCT_SIZE * 6 + x];
185 let tmp2 = data2[DCT_SIZE * 2 + x] + data2[DCT_SIZE * 5 + x];
186 let tmp5 = data2[DCT_SIZE * 2 + x] - data2[DCT_SIZE * 5 + x];
187 let tmp3 = data2[DCT_SIZE * 3 + x] + data2[DCT_SIZE * 4 + x];
188 let tmp4 = data2[DCT_SIZE * 3 + x] - data2[DCT_SIZE * 4 + x];
189
190 let tmp10 = tmp0 + tmp3;
195 let tmp13 = tmp0 - tmp3;
196 let tmp11 = tmp1 + tmp2;
197 let tmp12 = tmp1 - tmp2;
198
199 data[DCT_SIZE * 0 + x] = into_el(descale(tmp10 + tmp11, PASS1_BITS));
200 data[DCT_SIZE * 4 + x] = into_el(descale(tmp10 - tmp11, PASS1_BITS));
201
202 let z1 = (tmp12 + tmp13) * FIX_0_541196100;
203 data[DCT_SIZE * 2 + x] = into_el(descale(
204 z1 + tmp13 * FIX_0_765366865,
205 CONST_BITS + PASS1_BITS,
206 ));
207 data[DCT_SIZE * 6 + x] = into_el(descale(
208 z1 + tmp12 * -FIX_1_847759065,
209 CONST_BITS + PASS1_BITS,
210 ));
211
212 let z1 = tmp4 + tmp7;
218 let z2 = tmp5 + tmp6;
219 let z3 = tmp4 + tmp6;
220 let z4 = tmp5 + tmp7;
221 let z5 = (z3 + z4) * FIX_1_175875602; let tmp4 = tmp4 * FIX_0_298631336; let tmp5 = tmp5 * FIX_2_053119869; let tmp6 = tmp6 * FIX_3_072711026; let tmp7 = tmp7 * FIX_1_501321110; let z1 = z1 * -FIX_0_899976223; let z2 = z2 * -FIX_2_562915447; let z3 = z3 * -FIX_1_961570560; let z4 = z4 * -FIX_0_390180644; let z3 = z3 + z5;
233 let z4 = z4 + z5;
234
235 data[DCT_SIZE * 7 + x] = into_el(descale(tmp4 + z1 + z3, CONST_BITS + PASS1_BITS));
236 data[DCT_SIZE * 5 + x] = into_el(descale(tmp5 + z2 + z4, CONST_BITS + PASS1_BITS));
237 data[DCT_SIZE * 3 + x] = into_el(descale(tmp6 + z2 + z3, CONST_BITS + PASS1_BITS));
238 data[DCT_SIZE * 1 + x] = into_el(descale(tmp7 + z1 + z4, CONST_BITS + PASS1_BITS));
239 }
240}
241
242#[cfg(test)]
243mod tests {
244
245 use super::fdct;
248
249 const INPUT1: [i16; 64] = [
250 -70, -71, -70, -68, -67, -67, -67, -67, -72, -73, -72, -70, -69, -69, -68, -69, -75, -76,
251 -74, -73, -73, -72, -71, -70, -77, -78, -77, -75, -76, -75, -73, -71, -78, -77, -77, -76,
252 -79, -77, -76, -75, -78, -78, -77, -77, -77, -77, -78, -77, -79, -79, -78, -78, -78, -78,
253 -79, -78, -80, -79, -78, -78, -81, -80, -78, -76,
254 ];
255
256 const OUTPUT1: [i16; 64] = [
257 -4786, -66, 2, -18, 12, 12, 5, -7, 223, -37, -8, 21, 8, 5, -4, 6, 60, 6, -10, 5, 0, -2, -1,
258 5, 21, 21, -15, 12, -2, -7, 1, 0, -2, -5, 16, -15, 0, 5, -4, -8, 0, -7, -4, 6, 7, -4, 5, 4,
259 3, 0, 1, -5, 0, -1, 4, 1, -5, 7, 0, -3, -6, 1, 1, -4,
260 ];
261
262 const INPUT2: [i16; 64] = [
263 21, 28, 11, 24, -45, -37, -55, -103, 38, -8, 31, 17, -19, 49, 15, -76, 22, -48, -36, -31,
264 -23, 35, -23, -72, 13, -30, -45, -42, -44, -15, -20, -44, 13, -30, -45, -42, -44, -15, -20,
265 -44, 13, -30, -45, -42, -44, -15, -20, -44, 13, -30, -45, -42, -44, -15, -20, -44, 13, -30,
266 -45, -42, -44, -15, -20, -44,
267 ];
268
269 const OUTPUT2: [i16; 64] = [
270 -1420, 717, 187, 910, -244, 579, 222, -191, 461, 487, -497, -29, -220, 179, 63, -95, 213,
271 414, -235, -187, -108, 74, -73, -70, -63, 311, 13, -290, 17, -38, -180, -47, -254, 201,
272 116, -247, 102, -109, -185, -36, -310, 107, 73, -91, 126, -121, -99, -37, -253, 43, -15,
273 53, 101, -91, -3, -37, -136, 12, -44, 81, 53, -45, 31, -24,
274 ];
275
276 #[test]
277 pub fn test_fdct_libjpeg() {
278 let mut i1 = INPUT1.clone();
279 fdct(&mut i1);
280 assert_eq!(i1, OUTPUT1);
281
282 let mut i2 = INPUT2.clone();
283 fdct(&mut i2);
284 assert_eq!(i2, OUTPUT2);
285 }
286}