RealVideo 4 encoder
[nihav.git] / nihav-realmedia / src / codecs / rv40enc / dsp / loopfilt.rs
CommitLineData
4965a5e5
KS
1use nihav_core::frame::NASimpleVideoFrame;
2use super::super::types::DeblockInfo;
3use super::clip8;
4
5const Y_TOP_ROW_MASK: u32 = 0x000F;
6const Y_BOT_ROW_MASK: u32 = 0xF000;
7const Y_LEFT_COL_MASK: u32 = 0x1111;
8const Y_RIGHT_COL_MASK: u32 = 0x8888;
9const C_TOP_ROW_MASK: u8 = 0x3;
10const C_BOT_ROW_MASK: u8 = 0xC;
11const C_LEFT_COL_MASK: u8 = 0x5;
12const C_RIGHT_COL_MASK: u8 = 0xA;
13
14macro_rules! test_bit {
15 ($pat: expr, $x: expr) => ( (($pat >> $x) & 1) != 0 )
16}
17
18pub fn loop_filter_frame(dst: &mut NASimpleVideoFrame<u8>, dblk: &[DeblockInfo], mb_w: usize, mb_h: usize) {
19 let small_frame = dst.width[0] * dst.height[0] <= 176 * 144;
20
21 let mut mb_pos = 0;
22 for mb_y in 0..mb_h {
23 let is_last_row = mb_y == mb_h - 1;
24 let mut left_q: usize = 0;
25 let mut left_cbp_y = 0;
26 let mut left_cbp_c = 0;
27 let mut left_dbk_y = 0;
28
29 for mb_x in 0..mb_w {
30 let q = usize::from(dblk[mb_pos].q);
31 let alpha = RV40_ALPHA_TAB[q];
32 let beta = RV40_BETA_TAB[q];
33 let beta_y = if small_frame { beta * 4 } else { beta * 3 };
34 let beta_c = beta * 3;
35
36 let is_strong = dblk[mb_pos].is_strong;
37 let top_is_strong = mb_y > 0 && dblk[mb_pos - mb_w].is_strong;
38 let left_is_strong = mb_x > 0 && dblk[mb_pos - 1].is_strong;
39 let bot_is_strong = !is_last_row && dblk[mb_pos + mb_w].is_strong;
40
41 let cur_dbk_y = dblk[mb_pos].deblock_y;
42 let cur_cbp_y = if is_strong { 0xFFFF } else { u32::from(dblk[mb_pos].cbp_y) };
43
44 let (top_cbp_y, top_dbk_y) = if mb_y > 0 {
45 (if top_is_strong { 0xFFFF } else { u32::from(dblk[mb_pos - mb_w].cbp_y) }, dblk[mb_pos - mb_w].deblock_y)
46 } else {
47 (0, 0)
48 };
49 let bot_dbk_y = if !is_last_row {
50 dblk[mb_pos + mb_w].deblock_y
51 } else {
52 0
53 };
54
55 let y_to_deblock = (cur_dbk_y as u32) | ((bot_dbk_y as u32) << 16);
56 let mut y_h_deblock = y_to_deblock | ((cur_cbp_y << 4) & !Y_TOP_ROW_MASK) | ((top_cbp_y & Y_BOT_ROW_MASK) >> 12);
57 let mut y_v_deblock = y_to_deblock | ((cur_cbp_y << 1) & !Y_LEFT_COL_MASK) | ((left_cbp_y & Y_RIGHT_COL_MASK) >> 3);
58
59 if mb_x == 0 {
60 y_v_deblock &= !Y_LEFT_COL_MASK;
61 }
62 if mb_y == 0 {
63 y_h_deblock &= !Y_TOP_ROW_MASK;
64 }
65 if is_last_row || is_strong || bot_is_strong {
66 y_h_deblock &= !(Y_TOP_ROW_MASK << 16);
67 }
68
69 for y in 0..4 {
70 let yoff = dst.offset[0] + mb_x * 16 + (mb_y * 16 + y * 4) * dst.stride[0];
71 for x in 0..4 {
72 let bpos = x + y * 4;
73 let ver_strong = (x == 0) && (mb_x > 0) && (is_strong || left_is_strong);
74
75 let cur_strength: usize;
76 if is_strong {
77 cur_strength = 2;
78 } else if test_bit!(cur_dbk_y, bpos) {
79 cur_strength = 1;
80 } else {
81 cur_strength = 0;
82 }
83
84 let left_strength: usize;
85 if x > 0 {
86 if is_strong {
87 left_strength = 2;
88 } else if test_bit!(cur_dbk_y, bpos - 1) {
89 left_strength = 1;
90 } else {
91 left_strength = 0;
92 }
93 } else if mb_x > 0 {
94 if left_is_strong {
95 left_strength = 2;
96 } else if test_bit!(left_dbk_y, bpos + 3) {
97 left_strength = 1;
98 } else {
99 left_strength = 0;
100 }
101 } else {
102 left_strength = 0;
103 }
104
105 let bot_strength: usize;
106 if y < 3 {
107 if is_strong {
108 bot_strength = 2;
109 } else if test_bit!(cur_dbk_y, bpos + 4) {
110 bot_strength = 1;
111 } else {
112 bot_strength = 0;
113 }
114 } else if !is_last_row {
115 if dblk[mb_pos + mb_w].is_strong {
116 bot_strength = 2;
117 } else if test_bit!(bot_dbk_y, x) {
118 bot_strength = 1;
119 } else {
120 bot_strength = 0;
121 }
122 } else {
123 bot_strength = 0;
124 }
125
126 let top_strength: usize;
127 if y > 0 {
128 if is_strong {
129 top_strength = 2;
130 } else if test_bit!(cur_dbk_y, bpos - 4) {
131 top_strength = 1;
132 } else {
133 top_strength = 0;
134 }
135 } else if mb_y > 0 {
136 if top_is_strong {
137 top_strength = 2;
138 } else if test_bit!(top_dbk_y, bpos + 12) {
139 top_strength = 1;
140 } else {
141 top_strength = 0;
142 }
143 } else {
144 top_strength = 0;
145 }
146
147 let l_q = if x > 0 { q } else { left_q };
148 let top_q = if mb_y > 0 { usize::from(dblk[mb_pos - mb_w].q) } else { 0 };
149
150 let lim_cur = RV40_FILTER_CLIP_TBL [cur_strength][q];
151 let lim_top = RV40_FILTER_CLIP_TBL [top_strength][top_q];
152 let lim_left = RV40_FILTER_CLIP_TBL[left_strength][l_q];
153 let lim_bottom = RV40_FILTER_CLIP_TBL [bot_strength][q];
154
155 let dmode = if y > 0 { x + y * 4 } else { x * 4 };
156
157 if test_bit!(y_h_deblock, bpos + 4) {
158 rv40_loop_filter4_h(dst.data, yoff + 4 * dst.stride[0] + x * 4, dst.stride[0],
159 dmode, lim_cur, lim_bottom, alpha, beta, beta_y, false, false);
160 }
161 if test_bit!(y_v_deblock, bpos) && !ver_strong {
162 rv40_loop_filter4_v(dst.data, yoff + x * 4, dst.stride[0],
163 dmode, lim_left, lim_cur, alpha, beta, beta_y, false, false);
164 }
165 if (y == 0) && test_bit!(y_h_deblock, bpos) && (is_strong || top_is_strong) {
166 rv40_loop_filter4_h(dst.data, yoff + x * 4, dst.stride[0],
167 dmode, lim_top, lim_cur, alpha, beta, beta_y, false, true);
168 }
169 if test_bit!(y_v_deblock, bpos) && ver_strong {
170 rv40_loop_filter4_v(dst.data, yoff + x * 4, dst.stride[0],
171 dmode, lim_left, lim_cur, alpha, beta, beta_y, false, true);
172 }
173 }
174 }
175
176 let cur_cbp_c = dblk[mb_pos].cbp_c;
177 let top_cbp_c = if mb_y > 0 {
178 if top_is_strong { 0xFF } else { dblk[mb_pos - mb_w].cbp_c }
179 } else {
180 0
181 };
182 let bot_cbp_c = if !is_last_row {
183 dblk[mb_pos + mb_w].cbp_c
184 } else {
185 0
186 };
187 for comp in 1..3 {
188 let cshift = (comp - 1) * 4;
189 let c_cur_cbp = (cur_cbp_c >> cshift) & 0xF;
190 let c_top_cbp = (top_cbp_c >> cshift) & 0xF;
191 let c_left_cbp = (left_cbp_c >> cshift) & 0xF;
192 let c_bot_cbp = (bot_cbp_c >> cshift) & 0xF;
193
194 let c_deblock = c_cur_cbp | (c_bot_cbp << 4);
195 let mut c_v_deblock = c_deblock | ((c_cur_cbp << 1) & !C_LEFT_COL_MASK) | ((c_left_cbp & C_RIGHT_COL_MASK) >> 1);
196 let mut c_h_deblock = c_deblock | ((c_cur_cbp & C_TOP_ROW_MASK) << 2) | ((c_top_cbp & C_BOT_ROW_MASK) >> 2);
197 if mb_x == 0 {
198 c_v_deblock &= !C_LEFT_COL_MASK;
199 }
200 if mb_y == 0 {
201 c_h_deblock &= !C_TOP_ROW_MASK;
202 }
203 if is_last_row || is_strong || bot_is_strong {
204 c_h_deblock &= !(C_TOP_ROW_MASK << 4);
205 }
206
207 for y in 0..2 {
208 let coff = dst.offset[comp] + mb_x * 8 + (mb_y * 8 + y * 4) * dst.stride[comp];
209 for x in 0..2 {
210 let bpos = x + y * 2;
211
212 let ver_strong = (x == 0) && (is_strong || left_is_strong);
213
214 let cur_strength: usize;
215 if is_strong {
216 cur_strength = 2;
217 } else if test_bit!(c_cur_cbp, bpos) {
218 cur_strength = 1;
219 } else {
220 cur_strength = 0;
221 }
222
223 let left_strength: usize;
224 if x > 0 {
225 if is_strong {
226 left_strength = 2;
227 } else if test_bit!(c_cur_cbp, bpos - 1) {
228 left_strength = 1;
229 } else {
230 left_strength = 0;
231 }
232 } else if mb_x > 0 {
233 if left_is_strong {
234 left_strength = 2;
235 } else if test_bit!(c_left_cbp, bpos + 1) {
236 left_strength = 1;
237 } else {
238 left_strength = 0;
239 }
240 } else {
241 left_strength = 0;
242 }
243
244 let bot_strength: usize;
245 if y != 3 {
246 if is_strong {
247 bot_strength = 2;
248 } else if test_bit!(c_cur_cbp, bpos + 2) {
249 bot_strength = 1;
250 } else {
251 bot_strength = 0;
252 }
253 } else if !is_last_row {
254 if dblk[mb_pos + mb_w].is_strong {
255 bot_strength = 2;
256 } else if test_bit!(c_bot_cbp, x) {
257 bot_strength = 1;
258 } else {
259 bot_strength = 0;
260 }
261 } else {
262 bot_strength = 0;
263 }
264
265 let top_strength: usize;
266 if y > 0 {
267 if is_strong {
268 top_strength = 2;
269 } else if test_bit!(c_cur_cbp, bpos - 2) {
270 top_strength = 1;
271 } else {
272 top_strength = 0;
273 }
274 } else if mb_y > 0 {
275 if top_is_strong {
276 top_strength = 2;
277 } else if test_bit!(c_top_cbp, bpos + 2) {
278 top_strength = 1;
279 } else {
280 top_strength = 0;
281 }
282 } else {
283 top_strength = 0;
284 }
285
286 let l_q = if x > 0 { q } else { left_q };
287 let top_q = if mb_y > 0 { usize::from(dblk[mb_pos - mb_w].q) } else { 0 };
288
289 let lim_cur = RV40_FILTER_CLIP_TBL [cur_strength][q];
290 let lim_top = RV40_FILTER_CLIP_TBL [top_strength][top_q];
291 let lim_left = RV40_FILTER_CLIP_TBL[left_strength][l_q];
292 let lim_bottom = RV40_FILTER_CLIP_TBL [bot_strength][q];
293
294 if test_bit!(c_h_deblock, bpos + 2) {
295 rv40_loop_filter4_h(dst.data, coff + 4 * dst.stride[comp] + x * 4, dst.stride[comp],
296 x * 8, lim_cur, lim_bottom, alpha, beta, beta_c, true, false);
297 }
298 if test_bit!(c_v_deblock, bpos) && !ver_strong {
299 rv40_loop_filter4_v(dst.data, coff + x * 4, dst.stride[comp],
300 y * 8, lim_left, lim_cur, alpha, beta, beta_c, true, false);
301 }
302 if (y == 0) && test_bit!(c_h_deblock, bpos) && (is_strong || top_is_strong) {
303 rv40_loop_filter4_h(dst.data, coff + x * 4, dst.stride[comp],
304 x * 8, lim_top, lim_cur, alpha, beta, beta_c, true, true);
305 }
306 if test_bit!(c_v_deblock, bpos) && ver_strong {
307 rv40_loop_filter4_v(dst.data, coff + x * 4, dst.stride[comp],
308 y * 8, lim_left, lim_cur, alpha, beta, beta_c, true, true);
309 }
310 }
311 }
312 }
313
314 left_q = q;
315 left_dbk_y = cur_dbk_y;
316 left_cbp_y = cur_cbp_y;
317 left_cbp_c = cur_cbp_c;
318
319 mb_pos += 1;
320 }
321 }
322}
323
324macro_rules! el {
325 ($src: ident, $o: expr) => ($src[$o] as i16);
326}
327
328fn clip_symm(a: i16, lim: i16) -> i16 {
329 if a < -lim {
330 -lim
331 } else if a > lim {
332 lim
333 } else {
334 a
335 }
336}
337
338fn rv40_weak_loop_filter4(pix: &mut [u8], mut off: usize, step: usize, stride: usize,
339 filter_p1: bool, filter_q1: bool, alpha: i16, beta: i16,
340 lim_p0q0: i16, lim_p1: i16, lim_q1: i16) {
341 for _ in 0..4 {
342 let p0 = el!(pix, off - step);
343 let q0 = el!(pix, off);
344
345 let t = q0 - p0;
346 if t == 0 {
347 off += stride;
348 continue;
349 }
350
351 let u = (alpha * t.wrapping_abs()) >> 7;
352 if u > (if filter_p1 && filter_q1 { 2 } else { 3 }) {
353 off += stride;
354 continue;
355 }
356
357 let p2 = el!(pix, off - 3*step);
358 let p1 = el!(pix, off - 2*step);
359 let q1 = el!(pix, off + step);
360 let q2 = el!(pix, off + 2*step);
361
362 let strength;
363 if filter_p1 && filter_q1 {
364 strength = (t << 2) + (p1 - q1);
365 } else {
366 strength = t << 2;
367 }
368
369 let diff = clip_symm((strength + 4) >> 3, lim_p0q0);
370 pix[off - step] = clip8(p0 + diff);
371 pix[off ] = clip8(q0 - diff);
372
373 if filter_p1 && ((p1 - p2).wrapping_abs() <= beta) {
374 let p1_diff = ((p1 - p0) + (p1 - p2) - diff) >> 1;
375 pix[off - 2*step] = clip8(p1 - clip_symm(p1_diff, lim_p1));
376 }
377
378 if filter_q1 && ((q1 - q2).wrapping_abs() <= beta) {
379 let q1_diff = ((q1 - q0) + (q1 - q2) + diff) >> 1;
380 pix[off + step] = clip8(q1 - clip_symm(q1_diff, lim_q1));
381 }
382
383 off += stride;
384 }
385}
386
387fn rv40_weak_loop_filter4_h(pix: &mut [u8], off: usize, stride: usize,
388 filter_p1: bool, filter_q1: bool, alpha: i16, beta: i16,
389 lim_p0q0: i16, lim_p1: i16, lim_q1: i16) {
390 rv40_weak_loop_filter4(pix, off, stride, 1, filter_p1, filter_q1, alpha, beta, lim_p0q0, lim_p1, lim_q1);
391}
392#[allow(clippy::eq_op)]
393fn rv40_weak_loop_filter4_v(pix: &mut [u8], off: usize, stride: usize,
394 filter_p1: bool, filter_q1: bool, alpha: i16, beta: i16,
395 lim_p0q0: i16, lim_p1: i16, lim_q1: i16) {
396 let src = &mut pix[off - 3..][..stride * 3 + 3 + 3];
397 for ch in src.chunks_mut(stride).take(4) {
398 assert!(ch.len() >= 3 + 3);
399 let p0 = el!(ch, 3 - 1);
400 let q0 = el!(ch, 3);
401
402 let t = q0 - p0;
403 if t == 0 {
404 continue;
405 }
406
407 let u = (alpha * t.wrapping_abs()) >> 7;
408 if u > (if filter_p1 && filter_q1 { 2 } else { 3 }) {
409 continue;
410 }
411
412 let p2 = el!(ch, 3 - 3);
413 let p1 = el!(ch, 3 - 2);
414 let q1 = el!(ch, 3 + 1);
415 let q2 = el!(ch, 3 + 2);
416
417 let strength;
418 if filter_p1 && filter_q1 {
419 strength = (t << 2) + (p1 - q1);
420 } else {
421 strength = t << 2;
422 }
423
424 let diff = clip_symm((strength + 4) >> 3, lim_p0q0);
425 ch[3 - 1] = clip8(p0 + diff);
426 ch[3 ] = clip8(q0 - diff);
427
428 if filter_p1 && ((p1 - p2).wrapping_abs() <= beta) {
429 let p1_diff = ((p1 - p0) + (p1 - p2) - diff) >> 1;
430 ch[3 - 2] = clip8(p1 - clip_symm(p1_diff, lim_p1));
431 }
432
433 if filter_q1 && ((q1 - q2).wrapping_abs() <= beta) {
434 let q1_diff = ((q1 - q0) + (q1 - q2) + diff) >> 1;
435 ch[3 + 1] = clip8(q1 - clip_symm(q1_diff, lim_q1));
436 }
437 }
438}
439
440#[allow(clippy::many_single_char_names)]
441fn sfilter(a: i16, b: i16, c: i16, d: i16, e: i16, dither: i16, clip: bool, lims: i16) -> i16 {
442 let val = (25 * (a + e) + 26 * (b + c + d) + dither) >> 7;
443 if clip {
444 if val < c - lims {
445 c - lims
446 } else if val > c + lims {
447 c + lims
448 } else {
449 val
450 }
451 } else {
452 val
453 }
454}
455
456fn rv40_strong_loop_filter4(pix: &mut [u8], mut off: usize, step: usize, stride: usize,
457 alpha: i16, lims: i16, dmode: usize, chroma: bool) {
458 for i in 0..4 {
459 let p0 = el!(pix, off - step);
460 let q0 = el!(pix, off);
461
462 let t = q0 - p0;
463 if t == 0 {
464 off += stride;
465 continue;
466 }
467
468 let fmode = (alpha * t.wrapping_abs()) >> 7;
469 if fmode > 1 {
470 off += stride;
471 continue;
472 }
473
474 let p3 = el!(pix, off - 4*step);
475 let p2 = el!(pix, off - 3*step);
476 let p1 = el!(pix, off - 2*step);
477 let q1 = el!(pix, off + step);
478 let q2 = el!(pix, off + 2*step);
479 let q3 = el!(pix, off + 3*step);
480
481 let np0 = sfilter(p2, p1, p0, q0, q1, RV40_DITHER_L[dmode + i], fmode != 0, lims);
482 let nq0 = sfilter( p1, p0, q0, q1, q2, RV40_DITHER_R[dmode + i], fmode != 0, lims);
483
484 let np1 = sfilter(p3, p2, p1, np0, q0, RV40_DITHER_L[dmode + i], fmode != 0, lims);
485 let nq1 = sfilter( p0, nq0, q1, q2, q3, RV40_DITHER_R[dmode + i], fmode != 0, lims);
486
487 pix[off - 2*step] = np1 as u8;
488 pix[off - step] = np0 as u8;
489 pix[off] = nq0 as u8;
490 pix[off + step] = nq1 as u8;
491
492 if !chroma {
493 let np2 = sfilter(np0, np1, p2, p3, p2, 64, false, 0);
494 let nq2 = sfilter(nq0, nq1, q2, q3, q2, 64, false, 0);
495 pix[off - 3*step] = np2 as u8;
496 pix[off + 2*step] = nq2 as u8;
497 }
498
499 off += stride;
500 }
501}
502
503fn rv40_loop_strength(pix: &[u8], off: usize, step: usize, stride: usize,
504 beta: i16, beta2: i16, edge: bool) -> (bool, bool, bool) {
505 let mut sum_p1p0 = 0;
506 let mut sum_q1q0 = 0;
507
508 let mut off1 = off;
509 for _ in 0..4 {
510 sum_p1p0 += el!(pix, off1 - 2 * step) - el!(pix, off1 - step);
511 sum_q1q0 += el!(pix, off1 + step) - el!(pix, off1);
512 off1 += stride;
513 }
514
515 let filter_p1 = sum_p1p0.wrapping_abs() < beta * 4;
516 let filter_q1 = sum_q1q0.wrapping_abs() < beta * 4;
517
518 if (!filter_p1 || !filter_q1) || !edge {
519 return (false, filter_p1, filter_q1);
520 }
521
522 let mut sum_p1p2 = 0;
523 let mut sum_q1q2 = 0;
524
525 let mut off1 = off;
526 for _ in 0..4 {
527 sum_p1p2 += el!(pix, off1 - 2 * step) - el!(pix, off1 - 3 * step);
528 sum_q1q2 += el!(pix, off1 + step) - el!(pix, off1 + 2 * step);
529 off1 += stride;
530 }
531
532 let strong = (sum_p1p2.wrapping_abs() < beta2) && (sum_q1q2.wrapping_abs() < beta2);
533
534 (strong, filter_p1, filter_q1)
535}
536
537fn rv40_loop_strength_h(pix: &[u8], off: usize, stride: usize,
538 beta: i16, beta2: i16, edge: bool) -> (bool, bool, bool) {
539 rv40_loop_strength(pix, off, stride, 1, beta, beta2, edge)
540}
541
542#[allow(clippy::eq_op)]
543fn rv40_loop_strength_v(pix: &[u8], off: usize, stride: usize,
544 beta: i16, beta2: i16, edge: bool) -> (bool, bool, bool) {
545 let src = &pix[off - 3..][..stride * 3 + 3 + 3];
546 let mut sum_p1p0 = 0;
547 let mut sum_q1q0 = 0;
548
549 for ch in src.chunks(stride).take(4) {
550 assert!(ch.len() >= 3 + 3);
551 sum_p1p0 += el!(ch, 3 - 2) - el!(ch, 3 - 1);
552 sum_q1q0 += el!(ch, 3 + 1) - el!(ch, 3);
553 }
554
555 let filter_p1 = sum_p1p0.wrapping_abs() < beta * 4;
556 let filter_q1 = sum_q1q0.wrapping_abs() < beta * 4;
557
558 if (!filter_p1 || !filter_q1) || !edge {
559 return (false, filter_p1, filter_q1);
560 }
561
562 let mut sum_p1p2 = 0;
563 let mut sum_q1q2 = 0;
564
565 for ch in src.chunks(stride).take(4) {
566 assert!(ch.len() >= 3 + 3);
567 sum_p1p2 += el!(ch, 3 - 2) - el!(ch, 3 - 3);
568 sum_q1q2 += el!(ch, 3 + 1) - el!(ch, 3 + 2);
569 }
570
571 let strong = (sum_p1p2.wrapping_abs() < beta2) && (sum_q1q2.wrapping_abs() < beta2);
572
573 (strong, filter_p1, filter_q1)
574}
575
576fn rv40_loop_filter4_h(pix: &mut [u8], off: usize, stride: usize,
577 dmode: usize, lim_p1: i16, lim_q1: i16, alpha: i16, beta: i16, beta2: i16,
578 chroma: bool, edge: bool) {
579 let (strong, filter_p1, filter_q1) = rv40_loop_strength_h(pix, off, stride, beta, beta2, edge);
580 let lims = (filter_p1 as i16) + (filter_q1 as i16) + ((lim_p1 + lim_q1) >> 1) + 1;
581
582 if strong {
583 rv40_strong_loop_filter4(pix, off, stride, 1, alpha, lims, dmode, chroma);
584 } else if filter_p1 && filter_q1 {
585 rv40_weak_loop_filter4_h(pix, off, stride, true, true, alpha, beta,
586 lims, lim_p1, lim_q1);
587 } else if filter_p1 || filter_q1 {
588 rv40_weak_loop_filter4_h(pix, off, stride, filter_p1, filter_q1, alpha, beta,
589 lims >> 1, lim_p1 >> 1, lim_q1 >> 1);
590 }
591}
592
593fn rv40_loop_filter4_v(pix: &mut [u8], off: usize, stride: usize,
594 dmode: usize, lim_p1: i16, lim_q1: i16, alpha: i16, beta: i16, beta2: i16,
595 chroma: bool, edge: bool) {
596 let (strong, filter_p1, filter_q1) = rv40_loop_strength_v(pix, off, stride, beta, beta2, edge);
597 let lims = (filter_p1 as i16) + (filter_q1 as i16) + ((lim_p1 + lim_q1) >> 1) + 1;
598
599 if strong {
600 rv40_strong_loop_filter4(pix, off, 1, stride, alpha, lims, dmode, chroma);
601 } else if filter_p1 && filter_q1 {
602 rv40_weak_loop_filter4_v(pix, off, stride, true, true, alpha, beta,
603 lims, lim_p1, lim_q1);
604 } else if filter_p1 || filter_q1 {
605 rv40_weak_loop_filter4_v(pix, off, stride, filter_p1, filter_q1, alpha, beta,
606 lims >> 1, lim_p1 >> 1, lim_q1 >> 1);
607 }
608}
609
610const RV40_DITHER_L: [i16; 16] = [
611 0x40, 0x50, 0x20, 0x60, 0x30, 0x50, 0x40, 0x30,
612 0x50, 0x40, 0x50, 0x30, 0x60, 0x20, 0x50, 0x40
613];
614const RV40_DITHER_R: [i16; 16] = [
615 0x40, 0x30, 0x60, 0x20, 0x50, 0x30, 0x30, 0x40,
616 0x40, 0x40, 0x50, 0x30, 0x20, 0x60, 0x30, 0x40
617];
618
619const RV40_ALPHA_TAB: [i16; 32] = [
620 128, 128, 128, 128, 128, 128, 128, 128,
621 128, 128, 122, 96, 75, 59, 47, 37,
622 29, 23, 18, 15, 13, 11, 10, 9,
623 8, 7, 6, 5, 4, 3, 2, 1
624];
625
626const RV40_BETA_TAB: [i16; 32] = [
627 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 4, 4, 4, 6, 6,
628 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 13, 14, 15, 16, 17
629];
630
631const RV40_FILTER_CLIP_TBL: [[i16; 32]; 3] = [
632 [
633 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
634 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
635 ], [
636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
637 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 5, 5
638 ], [
639 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
640 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 7, 8, 9
641 ]
642];
643