h264: make a separate structure for motion compensation DSP
[nihav.git] / nihav-itu / src / codecs / h264 / dsp / mod.rs
1 mod mc;
2 pub use mc::H264MC;
3
4 pub const CHROMA_QUANTS: [u8; 52] = [
5 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
6 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 29, 30,
7 31, 32, 32, 33, 34, 34, 35, 35, 36, 36, 37, 37, 37, 38, 38, 38,
8 39, 39, 39, 39
9 ];
10
11 pub const CHROMA_DC_SCAN: [usize; 4] = [ 0, 1, 2, 3];
12 pub const ZIGZAG: [usize; 16] = [
13 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
14 ];
15 pub const ZIGZAG1: [usize; 15] = [
16 0, 3, 7, 4, 1, 2, 5, 8, 11, 12, 9, 6, 10, 13, 14
17 ];
18 /*pub const IL_SCAN: [usize; 16] = [
19 0, 4, 1, 8, 12, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15
20 ];*/
21 pub const ZIGZAG8X8: [usize; 64] = [
22 0, 1, 8, 16, 9, 2, 3, 10,
23 17, 24, 32, 25, 18, 11, 4, 5,
24 12, 19, 26, 33, 40, 48, 41, 34,
25 27, 20, 13, 6, 7, 14, 21, 28,
26 35, 42, 49, 56, 57, 50, 43, 36,
27 29, 22, 15, 23, 30, 37, 44, 51,
28 58, 59, 52, 45, 38, 31, 39, 46,
29 53, 60, 61, 54, 47, 55, 62, 63
30 ];
31
32 const LEVEL_SCALE: [[i16; 6]; 3] = [
33 [ 10, 11, 13, 14, 16, 18 ],
34 [ 16, 18, 20, 23, 25, 29 ],
35 [ 13, 14, 16, 18, 20, 23 ]
36 ];
37
38 pub fn chroma_dc_transform(blk: &mut [i16; 4], qp: u8) {
39 let t0 = blk[0] + blk[2];
40 let t1 = blk[0] - blk[2];
41 let t2 = blk[1] + blk[3];
42 let t3 = blk[1] - blk[3];
43 blk[0] = t0 + t2;
44 blk[1] = t0 - t2;
45 blk[2] = t1 + t3;
46 blk[3] = t1 - t3;
47 if qp < 6 {
48 let mul = LEVEL_SCALE[0][qp as usize];
49 for el in blk.iter_mut() {
50 *el = el.wrapping_mul(mul) >> 1;
51 }
52 } else {
53 let mul = LEVEL_SCALE[0][(qp % 6) as usize];
54 let shift = qp / 6 - 1;
55 for el in blk.iter_mut() {
56 *el = el.wrapping_mul(mul) << shift;
57 }
58 }
59 }
60
61 macro_rules! transform {
62 (luma_dc; $a: expr, $b: expr, $c: expr, $d: expr) => ({
63 let t0 = $a.wrapping_add($c);
64 let t1 = $a.wrapping_sub($c);
65 let t2 = $b.wrapping_add($d);
66 let t3 = $b.wrapping_sub($d);
67 $a = t0.wrapping_add(t2);
68 $b = t1.wrapping_add(t3);
69 $c = t1.wrapping_sub(t3);
70 $d = t0.wrapping_sub(t2);
71 });
72 ($a: expr, $b: expr, $c: expr, $d: expr, $shift: expr) => ({
73 let t0 = $a.wrapping_add($c);
74 let t1 = $a.wrapping_sub($c);
75 let t2 = ($b >> 1).wrapping_sub($d);
76 let t3 = $b.wrapping_add($d >> 1);
77 let bias = 1 << $shift >> 1;
78 $a = t0.wrapping_add(t3).wrapping_add(bias) >> $shift;
79 $b = t1.wrapping_add(t2).wrapping_add(bias) >> $shift;
80 $c = t1.wrapping_sub(t2).wrapping_add(bias) >> $shift;
81 $d = t0.wrapping_sub(t3).wrapping_add(bias) >> $shift;
82 });
83 ($a: expr, $b: expr, $c: expr, $d: expr, $e: expr, $f: expr, $g: expr, $h: expr) => {
84 let e0 = $a + $e;
85 let e1 = -$d + $f - $h - ($h >> 1);
86 let e2 = $a - $e;
87 let e3 = $b + $h - $d - ($d >> 1);
88 let e4 = ($c >> 1) - $g;
89 let e5 = -$b + $h + $f + ($f >> 1);
90 let e6 = $c + ($g >> 1);
91 let e7 = $d + $f + $b + ($b >> 1);
92
93 let f0 = e0 + e6;
94 let f1 = e1 + (e7 >> 2);
95 let f2 = e2 + e4;
96 let f3 = e3 + (e5 >> 2);
97 let f4 = e2 - e4;
98 let f5 = (e3 >> 2) - e5;
99 let f6 = e0 - e6;
100 let f7 = e7 - (e1 >> 2);
101
102 $a = f0 + f7;
103 $b = f2 + f5;
104 $c = f4 + f3;
105 $d = f6 + f1;
106 $e = f6 - f1;
107 $f = f4 - f3;
108 $g = f2 - f5;
109 $h = f0 - f7;
110 };
111 }
112
113 pub fn idct_luma_dc(blk: &mut [i16; 16], qp: u8) {
114 if qp < 12 {
115 let mul = LEVEL_SCALE[0][(qp % 6) as usize];
116 let shift = 2 - qp / 6;
117 let bias = 1 << shift >> 1;
118 for el in blk.iter_mut() {
119 *el = el.wrapping_mul(mul).wrapping_add(bias) >> shift;
120 }
121 } else {
122 let mul = LEVEL_SCALE[0][(qp % 6) as usize];
123 let shift = qp / 6 - 2;
124 for el in blk.iter_mut() {
125 *el = el.wrapping_mul(mul) << shift;
126 }
127 }
128 for i in 0..4 {
129 transform!(luma_dc; blk[i], blk[i + 4], blk[i + 8], blk[i + 12]);
130 }
131 for row in blk.chunks_mut(4) {
132 transform!(luma_dc; row[0], row[1], row[2], row[3]);
133 }
134 }
135
136 pub fn idct(blk: &mut [i16; 16], qp: u8, quant_dc: bool) {
137 const BLK_INDEX: [usize; 16] = [
138 0, 2, 0, 2,
139 2, 1, 2, 1,
140 0, 2, 0, 2,
141 2, 1, 2, 1
142 ];
143 let qidx = (qp % 6) as usize;
144 let shift = qp / 6;
145 let start = if quant_dc { 0 } else { 1 };
146 for (el, &idx) in blk.iter_mut().zip(BLK_INDEX.iter()).skip(start) {
147 *el = (*el * LEVEL_SCALE[idx][qidx]) << shift;
148 }
149 for row in blk.chunks_mut(4) {
150 transform!(row[0], row[1], row[2], row[3], 0);
151 }
152 for i in 0..4 {
153 transform!(blk[i], blk[i + 4], blk[i + 8], blk[i + 12], 6);
154 }
155 }
156
157 pub fn idct_dc(blk: &mut [i16; 16], qp: u8, quant_dc: bool) {
158 let dc = if quant_dc {
159 (blk[0] * LEVEL_SCALE[0][(qp % 6) as usize]) << (qp / 6)
160 } else {
161 blk[0]
162 };
163 *blk = [(dc + 0x20) >> 6; 16];
164 }
165
166 const QMAT_8X8: [[u8; 16]; 6] = [
167 [
168 20, 19, 25, 19,
169 19, 18, 24, 18,
170 25, 24, 32, 24,
171 19, 18, 24, 18
172 ], [
173 22, 21, 28, 21,
174 21, 19, 26, 19,
175 28, 26, 35, 26,
176 21, 19, 26, 19
177 ], [
178 26, 24, 33, 24,
179 24, 23, 31, 23,
180 33, 31, 42, 31,
181 24, 23, 31, 23
182 ], [
183 28, 26, 35, 26,
184 26, 25, 33, 25,
185 35, 33, 45, 33,
186 26, 25, 33, 25
187 ], [
188 32, 30, 40, 30,
189 30, 28, 38, 28,
190 40, 38, 51, 38,
191 30, 28, 38, 28
192 ], [
193 36, 34, 46, 34,
194 34, 32, 43, 32,
195 46, 43, 58, 43,
196 34, 32, 43, 32
197 ]
198 ];
199
200 pub fn dequant8x8(blk: &mut [i16; 64], slist: &[u8; 64]) {
201 for (el, &scan) in blk.iter_mut().zip(ZIGZAG8X8.iter()) {
202 if *el != 0 {
203 *el = el.wrapping_mul(i16::from(slist[scan]));
204 }
205 }
206 }
207
208 pub fn idct8x8(blk: &mut [i16; 64], qp: u8) {
209 let mut tmp = [0i32; 64];
210 let qmat = &QMAT_8X8[(qp % 6) as usize];
211 if qp >= 36 {
212 let shift = qp / 6 - 6;
213 for (i, (dst, &src)) in tmp.iter_mut().zip(blk.iter()).enumerate() {
214 let x = i & 7;
215 let y = i >> 3;
216 let idx = (x & 3) + (y & 3) * 4;
217 *dst = i32::from(src).wrapping_mul(i32::from(qmat[idx])) << shift;
218 }
219 } else {
220 let shift = 6 - qp / 6;
221 let bias = (1 << shift) >> 1;
222 for (i, (dst, &src)) in tmp.iter_mut().zip(blk.iter()).enumerate() {
223 let x = i & 7;
224 let y = i >> 3;
225 let idx = (x & 3) + (y & 3) * 4;
226 *dst = i32::from(src).wrapping_mul(i32::from(qmat[idx])).wrapping_add(bias) >> shift;
227 }
228 }
229 for row in tmp.chunks_mut(8) {
230 transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
231 }
232 for col in 0..8 {
233 transform!(tmp[col], tmp[col + 8], tmp[col + 8 * 2], tmp[col + 8 * 3],
234 tmp[col + 8 * 4], tmp[col + 8 * 5], tmp[col + 8 * 6], tmp[col + 8 * 7]);
235 }
236 for (dst, &src) in blk.iter_mut().zip(tmp.iter()) {
237 *dst = ((src + 0x20) >> 6) as i16;
238 }
239 }
240
241 pub fn add_coeffs(dst: &mut [u8], offset: usize, stride: usize, coeffs: &[i16]) {
242 let out = &mut dst[offset..][..stride * 3 + 4];
243 for (line, src) in out.chunks_mut(stride).take(4).zip(coeffs.chunks(4)) {
244 for (dst, src) in line.iter_mut().take(4).zip(src.iter()) {
245 *dst = (i32::from(*dst) + i32::from(*src)).max(0).min(255) as u8;
246 }
247 }
248 }
249
250 pub fn add_coeffs8(dst: &mut [u8], offset: usize, stride: usize, coeffs: &[i16; 64]) {
251 let out = &mut dst[offset..];
252 for (line, src) in out.chunks_mut(stride).take(8).zip(coeffs.chunks(8)) {
253 for (dst, src) in line.iter_mut().take(8).zip(src.iter()) {
254 *dst = (i32::from(*dst) + i32::from(*src)).max(0).min(255) as u8;
255 }
256 }
257 }
258
259 fn clip8(val: i16) -> u8 { val.max(0).min(255) as u8 }
260
261 fn ipred_dc128(buf: &mut [u8], stride: usize, bsize: usize) {
262 for row in buf.chunks_mut(stride).take(bsize) {
263 for el in row[..bsize].iter_mut() {
264 *el = 128;
265 }
266 }
267 }
268 fn ipred_ver(buf: &mut [u8], stride: usize, top: &[u8], bsize: usize) {
269 for row in buf.chunks_mut(stride).take(bsize) {
270 row[..bsize].copy_from_slice(&top[..bsize]);
271 }
272 }
273 fn ipred_hor(buf: &mut [u8], stride: usize, left: &[u8], bsize: usize) {
274 for (row, &left) in buf.chunks_mut(stride).zip(left[1..].iter()).take(bsize) {
275 for el in row[..bsize].iter_mut() {
276 *el = left;
277 }
278 }
279 }
280 fn ipred_dc(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8], bsize: usize, shift: u8) {
281 let mut adc: u16 = 0;
282 for i in 0..bsize { adc += u16::from(top[i]); }
283 for i in 0..bsize { adc += u16::from(left[i + 1]); }
284 let dc = ((adc + (1 << (shift - 1))) >> shift) as u8;
285
286 for row in buf.chunks_mut(stride).take(bsize) {
287 for el in row[..bsize].iter_mut() {
288 *el = dc;
289 }
290 }
291 }
292 fn ipred_left_dc(buf: &mut [u8], stride: usize, left: &[u8], bsize: usize, shift: u8) {
293 let mut adc: u16 = 0;
294 for i in 0..bsize { adc += u16::from(left[i + 1]); }
295 let dc = ((adc + (1 << (shift - 1))) >> shift) as u8;
296
297 for row in buf.chunks_mut(stride).take(bsize) {
298 for el in row[..bsize].iter_mut() {
299 *el = dc;
300 }
301 }
302 }
303 fn ipred_top_dc(buf: &mut [u8], stride: usize, top: &[u8], bsize: usize, shift: u8) {
304 let mut adc: u16 = 0;
305 for i in 0..bsize { adc += u16::from(top[i]); }
306 let dc = ((adc + (1 << (shift - 1))) >> shift) as u8;
307
308 for row in buf.chunks_mut(stride).take(bsize) {
309 for el in row[..bsize].iter_mut() {
310 *el = dc;
311 }
312 }
313 }
314
315 fn load(dst: &mut [u16], src: &[u8]) {
316 for (dst, &src) in dst.iter_mut().zip(src.iter()) {
317 *dst = u16::from(src);
318 }
319 }
320
321 fn ipred_4x4_ver(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8], _tr: &[u8]) {
322 ipred_ver(buf, stride, top, 4);
323 }
324 fn ipred_4x4_hor(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8], _tr: &[u8]) {
325 ipred_hor(buf, stride, left, 4);
326 }
327 fn ipred_4x4_diag_down_left(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8], tr: &[u8]) {
328 let mut t: [u16; 9] = [0; 9];
329 load(&mut t[..4], top);
330 load(&mut t[4..8], tr);
331 t[8] = t[7];
332
333 for i in 0..4 {
334 buf[i] = ((t[i] + 2 * t[i + 1] + t[i + 2] + 2) >> 2) as u8;
335 }
336 let dst = &mut buf[stride..];
337 for i in 0..4 {
338 dst[i] = ((t[i + 1] + 2 * t[i + 2] + t[i + 3] + 2) >> 2) as u8;
339 }
340 let dst = &mut buf[stride * 2..];
341 for i in 0..4 {
342 dst[i] = ((t[i + 2] + 2 * t[i + 3] + t[i + 4] + 2) >> 2) as u8;
343 }
344 let dst = &mut buf[stride * 3..];
345 for i in 0..4 {
346 dst[i] = ((t[i + 3] + 2 * t[i + 4] + t[i + 5] + 2) >> 2) as u8;
347 }
348 }
349 fn ipred_4x4_diag_down_right(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8], _tr: &[u8]) {
350 let mut t: [u16; 5] = [0; 5];
351 t[0] = u16::from(left[0]);
352 load(&mut t[1..], &top);
353 let mut l: [u16; 5] = [0; 5];
354 load(&mut l, left);
355 let dst = buf;
356
357 for j in 0..4 {
358 for i in 0..j {
359 dst[i + j * stride] = ((l[j - i - 1] + 2 * l[j - i] + l[j - i + 1] + 2) >> 2) as u8;
360 }
361 dst[j + j * stride] = ((l[1] + 2 * l[0] + t[1] + 2) >> 2) as u8;
362 for i in (j+1)..4 {
363 dst[i + j * stride] = ((t[i - j - 1] + 2 * t[i - j] + t[i - j + 1] + 2) >> 2) as u8;
364 }
365 }
366 }
367 fn ipred_4x4_ver_right(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8], _tr: &[u8]) {
368 let mut t: [u16; 5] = [0; 5];
369 t[0] = u16::from(left[0]);
370 load(&mut t[1..], &top);
371 let mut l: [u16; 5] = [0; 5];
372 load(&mut l, left);
373 let dst = buf;
374
375 for j in 0..4 {
376 for i in 0..4 {
377 let zvr = ((2 * i) as i8) - (j as i8);
378 let pix;
379 if zvr >= 0 {
380 if (zvr & 1) == 0 {
381 pix = (t[i - (j >> 1)] + t[i - (j >> 1) + 1] + 1) >> 1;
382 } else {
383 pix = (t[i - (j >> 1) - 1] + 2 * t[i - (j >> 1)] + t[i - (j >> 1) + 1] + 2) >> 2;
384 }
385 } else {
386 if zvr == -1 {
387 pix = (l[1] + 2 * l[0] + t[1] + 2) >> 2;
388 } else {
389 pix = (l[j] + 2 * l[j - 1] + l[j - 2] + 2) >> 2;
390 }
391 }
392 dst[i + j * stride] = pix as u8;
393 }
394 }
395 }
396 fn ipred_4x4_ver_left(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8], tr: &[u8]) {
397 let mut t: [u16; 8] = [0; 8];
398 load(&mut t[..4], &top);
399 load(&mut t[4..], tr);
400 let dst = buf;
401
402 dst[0 + 0 * stride] = ((t[0] + t[1] + 1) >> 1) as u8;
403 let pix = ((t[1] + t[2] + 1) >> 1) as u8;
404 dst[1 + 0 * stride] = pix;
405 dst[0 + 2 * stride] = pix;
406 let pix = ((t[2] + t[3] + 1) >> 1) as u8;
407 dst[2 + 0 * stride] = pix;
408 dst[1 + 2 * stride] = pix;
409 let pix = ((t[3] + t[4] + 1) >> 1) as u8;
410 dst[3 + 0 * stride] = pix;
411 dst[2 + 2 * stride] = pix;
412 dst[3 + 2 * stride] = ((t[4] + t[5] + 1) >> 1) as u8;
413 dst[0 + 1 * stride] = ((t[0] + 2*t[1] + t[2] + 2) >> 2) as u8;
414 let pix = ((t[1] + 2*t[2] + t[3] + 2) >> 2) as u8;
415 dst[1 + 1 * stride] = pix;
416 dst[0 + 3 * stride] = pix;
417 let pix = ((t[2] + 2*t[3] + t[4] + 2) >> 2) as u8;
418 dst[2 + 1 * stride] = pix;
419 dst[1 + 3 * stride] = pix;
420 let pix = ((t[3] + 2*t[4] + t[5] + 2) >> 2) as u8;
421 dst[3 + 1 * stride] = pix;
422 dst[2 + 3 * stride] = pix;
423 dst[3 + 3 * stride] = ((t[4] + 2*t[5] + t[6] + 2) >> 2) as u8;
424 }
425 fn ipred_4x4_hor_down(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8], _tr: &[u8]) {
426 let mut t: [u16; 5] = [0; 5];
427 t[0] = u16::from(left[0]);
428 load(&mut t[1..], &top);
429 let mut l: [u16; 5] = [0; 5];
430 load(&mut l, left);
431 let dst = buf;
432
433 for j in 0..4 {
434 for i in 0..4 {
435 let zhd = ((2 * j) as i8) - (i as i8);
436 let pix;
437 if zhd >= 0 {
438 if (zhd & 1) == 0 {
439 pix = (l[j - (i >> 1)] + l[j - (i >> 1) + 1] + 1) >> 1;
440 } else {
441 pix = (l[j - (i >> 1) - 1] + 2 * l[j - (i >> 1)] + l[j - (i >> 1) + 1] + 2) >> 2;
442 }
443 } else {
444 if zhd == -1 {
445 pix = (l[1] + 2 * l[0] + t[1] + 2) >> 2;
446 } else {
447 pix = (t[i - 2] + 2 * t[i - 1] + t[i] + 2) >> 2;
448 }
449 }
450 dst[i + j * stride] = pix as u8;
451 }
452 }
453 }
454 fn ipred_4x4_hor_up(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8], _tr: &[u8]) {
455 let mut l: [u16; 8] = [0; 8];
456 load(&mut l, &left[1..]);
457 let dst = buf;
458
459 dst[0 + 0 * stride] = ((l[0] + l[1] + 1) >> 1) as u8;
460 dst[1 + 0 * stride] = ((l[0] + 2*l[1] + l[2] + 2) >> 2) as u8;
461 let pix = ((l[1] + l[2] + 1) >> 1) as u8;
462 dst[2 + 0 * stride] = pix;
463 dst[0 + 1 * stride] = pix;
464 let pix = ((l[1] + 2*l[2] + l[3] + 2) >> 2) as u8;
465 dst[3 + 0 * stride] = pix;
466 dst[1 + 1 * stride] = pix;
467 let pix = ((l[2] + l[3] + 1) >> 1) as u8;
468 dst[2 + 1 * stride] = pix;
469 dst[0 + 2 * stride] = pix;
470 let pix = ((l[2] + 3*l[3] + 2) >> 2) as u8;
471 dst[3 + 1 * stride] = pix;
472 dst[1 + 2 * stride] = pix;
473 dst[3 + 2 * stride] = l[3] as u8;
474 dst[1 + 3 * stride] = l[3] as u8;
475 dst[0 + 3 * stride] = l[3] as u8;
476 dst[2 + 2 * stride] = l[3] as u8;
477 dst[2 + 3 * stride] = l[3] as u8;
478 dst[3 + 3 * stride] = l[3] as u8;
479 }
480 fn ipred_4x4_dc(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8], _tr: &[u8]) {
481 ipred_dc(buf, stride, top, left, 4, 3);
482 }
483 fn ipred_4x4_left_dc(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8], _tr: &[u8]) {
484 ipred_left_dc(buf, stride, left, 4, 2);
485 }
486 fn ipred_4x4_top_dc(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8], _tr: &[u8]) {
487 ipred_top_dc(buf, stride, top, 4, 2);
488 }
489 fn ipred_4x4_dc128(buf: &mut [u8], stride: usize, _top: &[u8], _left: &[u8], _tr: &[u8]) {
490 ipred_dc128(buf, stride, 4);
491 }
492
493 pub struct IPred8Context {
494 pub t: [u8; 16],
495 pub l: [u8; 8],
496 pub tl: u8,
497 }
498
499 impl IPred8Context {
500 pub fn new() -> Self {
501 Self {
502 t: [128; 16],
503 l: [128; 8],
504 tl: 128,
505 }
506 }
507 pub fn fill(&mut self, top: &[u8], left: &[u8], has_t: bool, has_tr: bool, has_l: bool, has_tl: bool) {
508 let mut t = [0x80u8; 19];
509 let mut l = [0x80u8; 11];
510 if has_t {
511 t[1..8 + 1].copy_from_slice(&top[..8]);
512 }
513 if has_tr {
514 t[8 + 1..16 + 1].copy_from_slice(&top[8..][..8]);
515 t[16 + 1] = t[15 + 1];
516 t[17 + 1] = t[15 + 1];
517 } else {
518 let (t0, t1) = t.split_at_mut(8 + 1);
519 for el in t1.iter_mut() {
520 *el = t0[7 + 1];
521 }
522 }
523 if has_l {
524 l[1..9].copy_from_slice(&left[1..9]);
525 l[8 + 1] = l[7 + 1];
526 l[9 + 1] = l[7 + 1];
527 }
528 if has_tl {
529 t[0] = left[0];
530 l[0] = left[0];
531 } else {
532 t[0] = t[1];
533 l[0] = l[1];
534 }
535
536 for i in 0..16 {
537 self.t[i] = ((u16::from(t[i]) + 2 * u16::from(t[i + 1]) + u16::from(t[i + 2]) + 2) >> 2) as u8;
538 }
539 for i in 0..8 {
540 self.l[i] = ((u16::from(l[i]) + 2 * u16::from(l[i + 1]) + u16::from(l[i + 2]) + 2) >> 2) as u8;
541 }
542 self.tl = if has_t && has_l {
543 ((u16::from(t[1]) + 2 * u16::from(t[0]) + u16::from(l[1]) + 2) >> 2) as u8
544 } else if has_t {
545 ((3 * u16::from(t[0]) + u16::from(t[1]) + 2) >> 2) as u8
546 } else if has_l {
547 ((3 * u16::from(l[0]) + u16::from(l[1]) + 2) >> 2) as u8
548 } else {
549 t[0]
550 };
551 }
552 }
553
554 fn ipred_y_8x8_ver(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
555 for row in buf.chunks_mut(stride).take(8) {
556 row[..8].copy_from_slice(&ctx.t[..8]);
557 }
558 }
559 fn ipred_y_8x8_hor(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
560 for (row, &l) in buf.chunks_mut(stride).zip(ctx.l.iter()).take(8) {
561 row[..8].copy_from_slice(&[l; 8]);
562 }
563 }
564 fn ipred_y_8x8_diag_down_left(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
565 let mut t = [0u16; 16];
566 load(&mut t, &ctx.t);
567
568 for (y, row) in buf.chunks_mut(stride).take(8).enumerate() {
569 for (x, pix) in row.iter_mut().take(8).enumerate() {
570 *pix = ((if (x != 7) || (y != 7) {
571 t[x + y] + 2 * t[x + y + 1] + t[x + y + 2]
572 } else {
573 t[14] + 3 * t[15]
574 } + 2) >> 2) as u8;
575 }
576 }
577 }
578 fn ipred_y_8x8_diag_down_right(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
579 let mut t = [0u16; 9];
580 t[0] = u16::from(ctx.tl);
581 load(&mut t[1..], &ctx.t);
582 let mut l = [0u16; 9];
583 l[0] = u16::from(ctx.tl);
584 load(&mut l[1..], &ctx.l);
585 let diag = t[1] + 2 * t[0] + l[1];
586
587 for (y, row) in buf.chunks_mut(stride).take(8).enumerate() {
588 for (x, pix) in row.iter_mut().take(8).enumerate() {
589 *pix = ((if x > y {
590 t[x - y - 1] + 2 * t[x - y] + t[x - y + 1]
591 } else if x < y {
592 l[y - x - 1] + 2 * l[y - x] + l[y - x + 1]
593 } else {
594 diag
595 } + 2) >> 2) as u8;
596 }
597 }
598 }
599 fn ipred_y_8x8_ver_right(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
600 let mut t = [0u16; 9];
601 t[0] = u16::from(ctx.tl);
602 load(&mut t[1..], &ctx.t);
603 let mut l = [0u16; 9];
604 l[0] = u16::from(ctx.tl);
605 load(&mut l[1..], &ctx.l);
606
607 for (y, row) in buf.chunks_mut(stride).take(8).enumerate() {
608 for (x, pix) in row.iter_mut().take(8).enumerate() {
609 let zvr = 2 * (x as i8) - (y as i8);
610 *pix = if zvr >= 0 {
611 let ix = x - (y >> 1);
612 if (zvr & 1) == 0 {
613 (t[ix] + t[ix + 1] + 1) >> 1
614 } else {
615 (t[ix - 1] + 2 * t[ix] + t[ix + 1] + 2) >> 2
616 }
617 } else if zvr == -1 {
618 (l[1] + 2 * l[0] + t[1] + 2) >> 2
619 } else {
620 let ix = y - 2 * x;
621 (l[ix] + 2 * l[ix - 1] + l[ix - 2] + 2) >> 2
622 } as u8;
623 }
624 }
625 }
626 fn ipred_y_8x8_ver_left(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
627 let mut t = [0u16; 16];
628 load(&mut t, &ctx.t);
629
630 for (y, row) in buf.chunks_mut(stride).take(8).enumerate() {
631 for (x, pix) in row.iter_mut().take(8).enumerate() {
632 let ix = x + (y >> 1);
633 *pix = if (y & 1) == 0 {
634 (t[ix] + t[ix + 1] + 1) >> 1
635 } else {
636 (t[ix] + 2 * t[ix + 1] + t[ix + 2] + 2) >> 2
637 } as u8;
638 }
639 }
640
641 }
642 fn ipred_y_8x8_hor_down(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
643 let mut t = [0u16; 9];
644 t[0] = u16::from(ctx.tl);
645 load(&mut t[1..], &ctx.t);
646 let mut l = [0u16; 9];
647 l[0] = u16::from(ctx.tl);
648 load(&mut l[1..], &ctx.l);
649
650 for (y, row) in buf.chunks_mut(stride).take(8).enumerate() {
651 for (x, pix) in row.iter_mut().take(8).enumerate() {
652 let zhd = 2 * (y as i8) - (x as i8);
653 *pix = if zhd >= 0 {
654 let ix = y - (x >> 1);
655 if (zhd & 1) == 0 {
656 (l[ix] + l[ix + 1] + 1) >> 1
657 } else {
658 (l[ix - 1] + 2 * l[ix] + l[ix + 1] + 2) >> 2
659 }
660 } else if zhd == -1 {
661 (l[1] + 2 * l[0] + t[1] + 2) >> 2
662 } else {
663 let ix = x - 2 * y;
664 (t[ix] + 2 * t[ix - 1] + t[ix - 2] + 2) >> 2
665 } as u8;
666 }
667 }
668 }
669 fn ipred_y_8x8_hor_up(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
670 let mut l = [0u16; 8];
671 load(&mut l, &ctx.l);
672
673 for (y, row) in buf.chunks_mut(stride).take(8).enumerate() {
674 for (x, pix) in row.iter_mut().take(8).enumerate() {
675 let zhu = x + 2 * y;
676 let ix = y + (x >> 1);
677 *pix = if zhu > 13 {
678 l[7]
679 } else if zhu == 13 {
680 (l[6] + 3 * l[7] + 2) >> 2
681 } else if (zhu & 1) != 0 {
682 (l[ix] + 2 * l[ix + 1] + l[ix + 2] + 2) >> 2
683 } else {
684 (l[ix] + l[ix + 1] + 1) >> 1
685 } as u8;
686 }
687 }
688 }
689 fn ipred_y_8x8_dc(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
690 let mut sum = 0u16;
691 for &t in ctx.t[..8].iter() {
692 sum += u16::from(t);
693 }
694 for &l in ctx.l[..8].iter() {
695 sum += u16::from(l);
696 }
697 let dc = ((sum + 8) >> 4) as u8;
698 for row in buf.chunks_mut(stride).take(8) {
699 for pix in row.iter_mut().take(8) {
700 *pix = dc;
701 }
702 }
703 }
704 fn ipred_y_8x8_left_dc(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
705 let mut sum = 0u16;
706 for &l in ctx.l[..8].iter() {
707 sum += u16::from(l);
708 }
709 let dc = ((sum + 4) >> 3) as u8;
710 for row in buf.chunks_mut(stride).take(8) {
711 for pix in row.iter_mut().take(8) {
712 *pix = dc;
713 }
714 }
715 }
716 fn ipred_y_8x8_top_dc(buf: &mut [u8], stride: usize, ctx: &IPred8Context) {
717 let mut sum = 0u16;
718 for &t in ctx.t[..8].iter() {
719 sum += u16::from(t);
720 }
721 let dc = ((sum + 4) >> 3) as u8;
722 for row in buf.chunks_mut(stride).take(8) {
723 for pix in row.iter_mut().take(8) {
724 *pix = dc;
725 }
726 }
727 }
728 fn ipred_y_8x8_dc128(buf: &mut [u8], stride: usize, _ctx: &IPred8Context) {
729 ipred_dc128(buf, stride, 8);
730 }
731
732 fn ipred_8x8_ver(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8]) {
733 ipred_ver(buf, stride, top, 8);
734 }
735 fn ipred_8x8_hor(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8]) {
736 ipred_hor(buf, stride, left, 8);
737 }
738 fn ipred_8x8_dc(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8]) {
739 let mut l = [0; 8];
740 load(&mut l, &left[1..]);
741 let mut t = [0; 8];
742 load(&mut t, &top);
743
744 let dc0 = ((t[0] + t[1] + t[2] + t[3] + l[0] + l[1] + l[2] + l[3] + 4) >> 3) as u8;
745 let sum1 = t[4] + t[5] + t[6] + t[7];
746 let dc1 = ((sum1 + 2) >> 2) as u8;
747 let sum2 = l[4] + l[5] + l[6] + l[7];
748 let dc2 = ((sum2 + 2) >> 2) as u8;
749 let dc3 = ((sum1 + sum2 + 4) >> 3) as u8;
750
751 for row in buf.chunks_mut(stride).take(4) {
752 row[..4].copy_from_slice(&[dc0; 4]);
753 row[4..8].copy_from_slice(&[dc1; 4]);
754 }
755 for row in buf.chunks_mut(stride).skip(4).take(4) {
756 row[..4].copy_from_slice(&[dc2; 4]);
757 row[4..8].copy_from_slice(&[dc3; 4]);
758 }
759 }
760 fn ipred_8x8_left_dc(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8]) {
761 let mut left_dc0 = 0;
762 let mut left_dc1 = 0;
763 for &el in left[1..].iter().take(4) {
764 left_dc0 += u16::from(el);
765 }
766 for &el in left[1..].iter().skip(4).take(4) {
767 left_dc1 += u16::from(el);
768 }
769 let dc0 = ((left_dc0 + 2) >> 2) as u8;
770 let dc2 = ((left_dc1 + 2) >> 2) as u8;
771 for row in buf.chunks_mut(stride).take(4) {
772 row[..8].copy_from_slice(&[dc0; 8]);
773 }
774 for row in buf.chunks_mut(stride).skip(4).take(4) {
775 row[..8].copy_from_slice(&[dc2; 8]);
776 }
777 }
778 fn ipred_8x8_top_dc(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8]) {
779 ipred_top_dc(buf, stride, top, 4, 2);
780 ipred_top_dc(&mut buf[4..], stride, &top[4..], 4, 2);
781 let mut top = [0; 8];
782 top.copy_from_slice(&buf[stride * 3..][..8]);
783 ipred_top_dc(&mut buf[4 * stride..], stride, &top, 4, 2);
784 ipred_top_dc(&mut buf[4 + 4 * stride..], stride, &top[4..], 4, 2);
785 }
786 fn ipred_8x8_dc128(buf: &mut [u8], stride: usize, _top: &[u8], _left: &[u8]) {
787 ipred_dc128(buf, stride, 8);
788 }
789 fn ipred_8x8_plane(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8]) {
790 let mut h: i32 = 4 * (i32::from(top[7]) - i32::from(left[0]));
791 let mut v: i32 = 4 * (i32::from(left[8]) - i32::from(left[0]));
792 for i in 0..3 {
793 let i1 = (i + 1) as i32;
794 h += i1 * (i32::from(top[4 + i]) - i32::from(top[2 - i]));
795 v += i1 * (i32::from(left[5 + i]) - i32::from(left[3 - i]));
796 }
797 let b = (17 * h + 16) >> 5;
798 let c = (17 * v + 16) >> 5;
799 let mut a = 16 * (i32::from(left[8]) + i32::from(top[7])) - 3 * (b + c) + 16;
800 for line in buf.chunks_mut(stride).take(8) {
801 let mut acc = a;
802 for el in line.iter_mut().take(8) {
803 *el = clip8((acc >> 5) as i16);
804 acc += b;
805 }
806 a += c;
807 }
808 }
809
810 fn ipred_16x16_ver(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8]) {
811 ipred_ver(buf, stride, top, 16);
812 }
813 fn ipred_16x16_hor(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8]) {
814 ipred_hor(buf, stride, left, 16);
815 }
816 fn ipred_16x16_dc(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8]) {
817 ipred_dc(buf, stride, top, left, 16, 5);
818 }
819 fn ipred_16x16_left_dc(buf: &mut [u8], stride: usize, _top: &[u8], left: &[u8]) {
820 ipred_left_dc(buf, stride, left, 16, 4);
821 }
822 fn ipred_16x16_top_dc(buf: &mut [u8], stride: usize, top: &[u8], _left: &[u8]) {
823 ipred_top_dc(buf, stride, top, 16, 4);
824 }
825 fn ipred_16x16_dc128(buf: &mut [u8], stride: usize, _top: &[u8], _left: &[u8]) {
826 ipred_dc128(buf, stride, 16);
827 }
828 fn ipred_16x16_plane(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8]) {
829 let mut h = 8 * (i32::from(top[15]) - i32::from(left[0]));
830 let mut v = 8 * (i32::from(left[16]) - i32::from(left[0]));
831 for k in 0..7 {
832 h += ((k as i32) + 1) * (i32::from(top[8 + k]) - i32::from(top[6 - k]));
833 v += ((k as i32) + 1) * (i32::from(left[9 + k]) - i32::from(left[7 - k]));
834 }
835
836 h = (5 * h + 32) >> 6;
837 v = (5 * v + 32) >> 6;
838
839 let mut a = 16 * (i32::from(left[16]) + i32::from(top[15]) + 1) - 7 * (v + h);
840
841 for row in buf.chunks_mut(stride).take(16) {
842 let mut b = a;
843 a += v;
844
845 for dst in row.chunks_exact_mut(4).take(4) {
846 dst[0] = clip8(((b ) >> 5) as i16);
847 dst[1] = clip8(((b + h) >> 5) as i16);
848 dst[2] = clip8(((b + 2*h) >> 5) as i16);
849 dst[3] = clip8(((b + 3*h) >> 5) as i16);
850 b += h * 4;
851 }
852 }
853 }
854
855 pub type IPred4x4Func = fn(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8], tr: &[u8]);
856 pub type IPred8x8Func = fn(buf: &mut [u8], stride: usize, top: &[u8], left: &[u8]);
857 pub type IPred8x8LumaFunc = fn(buf: &mut [u8], stride: usize, ctx: &IPred8Context);
858
859 pub const IPRED4_DC128: usize = 11;
860 pub const IPRED4_DC_TOP: usize = 10;
861 pub const IPRED4_DC_LEFT: usize = 9;
862 pub const IPRED8_DC128: usize = 6;
863 pub const IPRED8_DC_TOP: usize = 5;
864 pub const IPRED8_DC_LEFT: usize = 4;
865
866 pub const IPRED_FUNCS4X4: [IPred4x4Func; 12] = [
867 ipred_4x4_ver, ipred_4x4_hor, ipred_4x4_dc,
868 ipred_4x4_diag_down_left, ipred_4x4_diag_down_right,
869 ipred_4x4_ver_right, ipred_4x4_hor_down, ipred_4x4_ver_left, ipred_4x4_hor_up,
870 ipred_4x4_left_dc, ipred_4x4_top_dc, ipred_4x4_dc128
871 ];
872
873 pub const IPRED_FUNCS8X8_LUMA: [IPred8x8LumaFunc; 12] = [
874 ipred_y_8x8_ver, ipred_y_8x8_hor, ipred_y_8x8_dc,
875 ipred_y_8x8_diag_down_left, ipred_y_8x8_diag_down_right,
876 ipred_y_8x8_ver_right, ipred_y_8x8_hor_down,
877 ipred_y_8x8_ver_left, ipred_y_8x8_hor_up,
878 ipred_y_8x8_left_dc, ipred_y_8x8_top_dc, ipred_y_8x8_dc128
879 ];
880
881 pub const IPRED_FUNCS8X8_CHROMA: [IPred8x8Func; 7] = [
882 ipred_8x8_dc, ipred_8x8_hor, ipred_8x8_ver, ipred_8x8_plane,
883 ipred_8x8_left_dc, ipred_8x8_top_dc, ipred_8x8_dc128
884 ];
885
886 pub const IPRED_FUNCS16X16: [IPred8x8Func; 7] = [
887 ipred_16x16_ver, ipred_16x16_hor, ipred_16x16_dc, ipred_16x16_plane,
888 ipred_16x16_left_dc, ipred_16x16_top_dc, ipred_16x16_dc128
889 ];
890
891 macro_rules! loop_filter {
892 (lumaedge; $buf: expr, $off: expr, $step: expr, $alpha: expr, $beta: expr) => {
893 let p2 = i16::from($buf[$off - $step * 3]);
894 let p1 = i16::from($buf[$off - $step * 2]);
895 let p0 = i16::from($buf[$off - $step]);
896 let q0 = i16::from($buf[$off]);
897 let q1 = i16::from($buf[$off + $step]);
898 let q2 = i16::from($buf[$off + $step * 2]);
899 let a_p = (p2 - p0).abs() < $beta;
900 let a_q = (q2 - q0).abs() < $beta;
901 if a_p && (p0 - q0).abs() < (($alpha >> 2) + 2) {
902 let p3 = i16::from($buf[$off - $step * 4]);
903 $buf[$off - $step * 3] = ((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) as u8;
904 $buf[$off - $step * 2] = ((p2 + p1 + p0 + q0 + 2) >> 2) as u8;
905 $buf[$off - $step] = ((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) as u8;
906 } else {
907 $buf[$off - $step] = ((2 * p1 + p0 + q1 + 2) >> 2) as u8;
908 }
909 if a_q && (p0 - q0).abs() < (($alpha >> 2) + 2) {
910 let q3 = i16::from($buf[$off + $step * 3]);
911 $buf[$off] = ((p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3) as u8;
912 $buf[$off + $step] = ((p0 + q0 + q1 + q2 + 2) >> 2) as u8;
913 $buf[$off + $step * 2] = ((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) as u8;
914 } else {
915 $buf[$off] = ((2 * q1 + q0 + p1 + 2) >> 2) as u8;
916 }
917 };
918 (chromaedge; $buf: expr, $off: expr, $step: expr) => {
919 let p1 = i16::from($buf[$off - $step * 2]);
920 let p0 = i16::from($buf[$off - $step]);
921 let q0 = i16::from($buf[$off]);
922 let q1 = i16::from($buf[$off + $step]);
923 $buf[$off - $step] = ((2 * p1 + p0 + q1 + 2) >> 2) as u8;
924 $buf[$off] = ((2 * q1 + q0 + p1 + 2) >> 2) as u8;
925 };
926 (lumanormal; $buf: expr, $off: expr, $step: expr, $tc0: expr, $beta: expr) => {
927 let p2 = i16::from($buf[$off - $step * 3]);
928 let p1 = i16::from($buf[$off - $step * 2]);
929 let p0 = i16::from($buf[$off - $step]);
930 let q0 = i16::from($buf[$off]);
931 let q1 = i16::from($buf[$off + $step]);
932 let q2 = i16::from($buf[$off + $step * 2]);
933 let a_p = (p2 - p0).abs() < $beta;
934 let a_q = (q2 - q0).abs() < $beta;
935 let tc = $tc0 + (a_p as i16) + (a_q as i16);
936 let delta = (((q0 - p0) * 4 + (p1 - q1) + 4) >> 3).max(-tc).min(tc);
937 if a_p && ($tc0 > 0) {
938 $buf[$off - $step * 2] = clip8(p1 + ((p2 + ((p0 + q0 + 1) >> 1) - p1 * 2) >> 1).max(-$tc0).min($tc0));
939 }
940 $buf[$off - $step] = clip8(p0 + delta);
941 $buf[$off] = clip8(q0 - delta);
942 if a_q && ($tc0 > 0) {
943 $buf[$off + $step] = clip8(q1 + ((q2 + ((p0 + q0 + 1) >> 1) - q1 * 2) >> 1).max(-$tc0).min($tc0));
944 }
945 };
946 (chromanormal; $buf: expr, $off: expr, $step: expr, $tc0: expr) => {
947 let p1 = i16::from($buf[$off - $step * 2]);
948 let p0 = i16::from($buf[$off - $step]);
949 let q0 = i16::from($buf[$off]);
950 let q1 = i16::from($buf[$off + $step]);
951 let tc = $tc0 + 1;
952 let delta = (((q0 - p0) * 4 + (p1 - q1) + 4) >> 3).max(-tc).min(tc);
953 $buf[$off - $step] = clip8(p0 + delta);
954 $buf[$off] = clip8(q0 - delta);
955 }
956 }
957
958 fn check_filter(buf: &[u8], off: usize, step: usize, alpha: i16, beta: i16) -> bool {
959 let p1 = i16::from(buf[off - step * 2]);
960 let p0 = i16::from(buf[off - step]);
961 let q0 = i16::from(buf[off]);
962 let q1 = i16::from(buf[off + step]);
963 (p0 - q0).abs() < alpha && (p1 - p0).abs() < beta && (q1 - q0).abs() < beta
964 }
965
966 pub fn loop_filter_lumaedge_v(dst: &mut [u8], mut off: usize, stride: usize, alpha: i16, beta: i16) {
967 for _ in 0..4 {
968 if check_filter(dst, off, 1, alpha, beta) {
969 loop_filter!(lumaedge; dst, off, 1, alpha, beta);
970 }
971 off += stride;
972 }
973 }
974 pub fn loop_filter_lumaedge_h(dst: &mut [u8], off: usize, stride: usize, alpha: i16, beta: i16) {
975 for x in 0..4 {
976 if check_filter(dst, off + x, stride, alpha, beta) {
977 loop_filter!(lumaedge; dst, off + x, stride, alpha, beta);
978 }
979 }
980 }
981 pub fn loop_filter_lumanormal_v(dst: &mut [u8], mut off: usize, stride: usize, alpha: i16, beta: i16, tc0: i16) {
982 for _ in 0..4 {
983 if check_filter(dst, off, 1, alpha, beta) {
984 loop_filter!(lumanormal; dst, off, 1, tc0, beta);
985 }
986 off += stride;
987 }
988 }
989 pub fn loop_filter_lumanormal_h(dst: &mut [u8], off: usize, stride: usize, alpha: i16, beta: i16, tc0: i16) {
990 for x in 0..4 {
991 if check_filter(dst, off + x, stride, alpha, beta) {
992 loop_filter!(lumanormal; dst, off + x, stride, tc0, beta);
993 }
994 }
995 }
996 pub fn loop_filter_chromaedge_v(dst: &mut [u8], mut off: usize, stride: usize, alpha: i16, beta: i16) {
997 for _ in 0..2 {
998 if check_filter(dst, off, 1, alpha, beta) {
999 loop_filter!(chromaedge; dst, off, 1);
1000 }
1001 off += stride;
1002 }
1003 }
1004 pub fn loop_filter_chromaedge_h(dst: &mut [u8], off: usize, stride: usize, alpha: i16, beta: i16) {
1005 for x in 0..2 {
1006 if check_filter(dst, off + x, stride, alpha, beta) {
1007 loop_filter!(chromaedge; dst, off + x, stride);
1008 }
1009 }
1010 }
1011 pub fn loop_filter_chromanormal_v(dst: &mut [u8], mut off: usize, stride: usize, alpha: i16, beta: i16, tc0: i16) {
1012 for _ in 0..2 {
1013 if check_filter(dst, off, 1, alpha, beta) {
1014 loop_filter!(chromanormal; dst, off, 1, tc0);
1015 }
1016 off += stride;
1017 }
1018 }
1019 pub fn loop_filter_chromanormal_h(dst: &mut [u8], off: usize, stride: usize, alpha: i16, beta: i16, tc0: i16) {
1020 for x in 0..2 {
1021 if check_filter(dst, off + x, stride, alpha, beta) {
1022 loop_filter!(chromanormal; dst, off + x, stride, tc0);
1023 }
1024 }
1025 }