]> git.nihav.org Git - nihav.git/blame_incremental - nihav-realmedia/src/codecs/rv30dsp.rs
avi: fix handling of palette change chunk with 256 colours
[nihav.git] / nihav-realmedia / src / codecs / rv30dsp.rs
... / ...
CommitLineData
1use nihav_core::frame::{FrameType, NAVideoBuffer};
2use nihav_codec_support::codecs::MV;
3use nihav_codec_support::codecs::blockdsp::edge_emu;
4use super::rv3040::{RV34DSP, RV34MBInfo};
5
6fn clip8(a: i16) -> u8 {
7 if a < 0 { 0 }
8 else if a > 255 { 255 }
9 else { a as u8 }
10}
11
12fn rv3_filter_h(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, bsize: usize, c1: i16, c2: i16) {
13 for _ in 0..bsize {
14 for x in 0..bsize {
15 dst[didx + x] = clip8((-((src[sidx + x - 1] as i16) + (src[sidx + x + 2] as i16)) + (src[sidx + x + 0] as i16) * c1 + (src[sidx + x + 1] as i16) * c2 + 8) >> 4);
16 }
17 sidx += sstride;
18 didx += dstride;
19 }
20}
21
22fn rv3_filter_v(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, bsize: usize, c1: i16, c2: i16) {
23 for _ in 0..bsize {
24 for x in 0..bsize {
25 dst[didx + x] = clip8((-((src[sidx + x - 1 * sstride] as i16) + (src[sidx + x + 2 * sstride] as i16)) + (src[sidx + x + 0 * sstride] as i16) * c1 + (src[sidx + x + 1 * sstride] as i16) * c2 + 8) >> 4);
26 }
27 sidx += sstride;
28 didx += dstride;
29 }
30}
31
32macro_rules! mc_matrix {
33 ($s: ident, $o: expr, $c1: expr) => (
34 ($c1 * 6) * ($s[$o] as i32) + ($c1 * 9) * ($s[$o + 1] as i32) + ($c1) * ($s[$o + 2] as i32)
35 );
36 ($s: ident, $o: expr, $c1: expr, $d1: expr, $d2: expr) => (
37 -($c1) * ($s[$o - 1] as i32) + ($c1 * $d1) * ($s[$o] as i32) + ($c1 * $d2) * ($s[$o + 1] as i32) + -($c1) * ($s[$o + 2] as i32)
38 );
39 ($s: ident, $o: expr, $ss: expr, $c1: expr, $c2: expr, $d1: expr, $d2: expr) => (
40 ((mc_matrix!($s, $o - $ss, -1, $d1, $d2) +
41 mc_matrix!($s, $o , $c1, $d1, $d2) +
42 mc_matrix!($s, $o + $ss, $c2, $d1, $d2) +
43 mc_matrix!($s, $o + 2 * $ss, -1, $d1, $d2) + 128) >> 8) as i16
44 );
45 (m22; $s: ident, $o: expr, $ss: expr) => (
46 ((mc_matrix!($s, $o + 0 * $ss, 6) +
47 mc_matrix!($s, $o + 1 * $ss, 9) +
48 mc_matrix!($s, $o + 2 * $ss, 1) + 128) >> 8) as i16
49 );
50}
51
52macro_rules! mc_func {
53 (copy; $name: ident, $size: expr) => (
54 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
55 for _ in 0..$size {
56 let d = &mut dst[didx..][..$size];
57 let s = &src[sidx..][..$size];
58 for x in 0..$size { d[x] = s[x]; }
59 didx += dstride;
60 sidx += sstride;
61 }
62 }
63 );
64 (hor; $name: ident, $c1: expr, $c2: expr, $size: expr) => (
65 fn $name (dst: &mut [u8], didx: usize, dstride: usize, src: &[u8], sidx: usize, sstride: usize) {
66 rv3_filter_h(dst, didx, dstride, src, sidx, sstride, $size, $c1, $c2);
67 }
68 );
69 (ver; $name: ident, $c1: expr, $c2: expr, $size: expr) => (
70 fn $name (dst: &mut [u8], didx: usize, dstride: usize, src: &[u8], sidx: usize, sstride: usize) {
71 rv3_filter_v(dst, didx, dstride, src, sidx, sstride, $size, $c1, $c2);
72 }
73 );
74 (m11; $name: ident, $size: expr) => (
75 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
76 for _ in 0..$size {
77 for x in 0..$size {
78 dst[didx + x] = clip8(mc_matrix!(src, sidx + x, sstride, 12, 6, 12, 6));
79 }
80 didx += dstride;
81 sidx += sstride;
82 }
83 }
84 );
85 (m12; $name: ident, $size: expr) => (
86 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
87 for _ in 0..$size {
88 for x in 0..$size {
89 dst[didx + x] = clip8(mc_matrix!(src, sidx + x, sstride, 6, 12, 12, 6));
90 }
91 didx += dstride;
92 sidx += sstride;
93 }
94 }
95 );
96 (m21; $name: ident, $size: expr) => (
97 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
98 for _ in 0..$size {
99 for x in 0..$size {
100 dst[didx + x] = clip8(mc_matrix!(src, sidx + x, sstride, 12, 6, 6, 12));
101 }
102 didx += dstride;
103 sidx += sstride;
104 }
105 }
106 );
107 (m22; $name: ident, $size: expr) => (
108 fn $name (dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize) {
109 for _ in 0..$size {
110 for x in 0..$size {
111 dst[didx + x] = clip8(mc_matrix!(m22; src, sidx + x, sstride));
112 }
113 didx += dstride;
114 sidx += sstride;
115 }
116 }
117 );
118}
119mc_func!(copy; copy_16, 16);
120mc_func!(copy; copy_8, 8);
121mc_func!(hor; luma_mc_10_16, 12, 6, 16);
122mc_func!(hor; luma_mc_20_16, 6, 12, 16);
123mc_func!(hor; luma_mc_10_8, 12, 6, 8);
124mc_func!(hor; luma_mc_20_8, 6, 12, 8);
125mc_func!(ver; luma_mc_01_16, 12, 6, 16);
126mc_func!(ver; luma_mc_02_16, 6, 12, 16);
127mc_func!(ver; luma_mc_01_8, 12, 6, 8);
128mc_func!(ver; luma_mc_02_8, 6, 12, 8);
129mc_func!(m11; luma_mc_11_16, 16);
130mc_func!(m11; luma_mc_11_8, 8);
131mc_func!(m21; luma_mc_21_16, 16);
132mc_func!(m21; luma_mc_21_8, 8);
133mc_func!(m12; luma_mc_12_16, 16);
134mc_func!(m12; luma_mc_12_8, 8);
135mc_func!(m22; luma_mc_22_16, 16);
136mc_func!(m22; luma_mc_22_8, 8);
137
138const RV30_CHROMA_FRAC1: [u16; 3] = [ 8, 5, 3 ];
139const RV30_CHROMA_FRAC2: [u16; 3] = [ 0, 3, 5 ];
140fn rv30_chroma_mc(dst: &mut [u8], mut didx: usize, dstride: usize, src: &[u8], mut sidx: usize, sstride: usize, size: usize, x: usize, y: usize) {
141 if (x == 0) && (y == 0) {
142 for _ in 0..size {
143 dst[didx..][..size].copy_from_slice(&src[sidx..][..size]);
144 didx += dstride;
145 sidx += sstride;
146 }
147 return;
148 }
149 let a = RV30_CHROMA_FRAC1[x] * RV30_CHROMA_FRAC1[y];
150 let b = RV30_CHROMA_FRAC2[x] * RV30_CHROMA_FRAC1[y];
151 let c = RV30_CHROMA_FRAC1[x] * RV30_CHROMA_FRAC2[y];
152 let d = RV30_CHROMA_FRAC2[x] * RV30_CHROMA_FRAC2[y];
153 for _ in 0..size {
154 for x in 0..size {
155 dst[didx + x] = ((a * (src[sidx + x] as u16)
156 + b * (src[sidx + x + 1] as u16)
157 + c * (src[sidx + x + sstride] as u16)
158 + d * (src[sidx + x + 1 + sstride] as u16) + 32) >> 6) as u8;
159 }
160 didx += dstride;
161 sidx += sstride;
162 }
163}
164
165#[allow(clippy::type_complexity)]
166pub struct RV30DSP {
167 luma_mc: [[fn (&mut [u8], usize, usize, &[u8], usize, usize); 9]; 2],
168}
169
170impl RV30DSP {
171 pub fn new() -> Self {
172 RV30DSP {
173 luma_mc: [
174 [ copy_16, luma_mc_10_16, luma_mc_20_16,
175 luma_mc_01_16, luma_mc_11_16, luma_mc_21_16,
176 luma_mc_02_16, luma_mc_12_16, luma_mc_22_16 ],
177 [ copy_8, luma_mc_10_8, luma_mc_20_8,
178 luma_mc_01_8, luma_mc_11_8, luma_mc_21_8,
179 luma_mc_02_8, luma_mc_12_8, luma_mc_22_8 ] ],
180 }
181 }
182}
183
184macro_rules! el {
185 ($src: ident, $o: expr) => ($src[$o] as i16);
186}
187
188fn clip_symm(a: i16, lim: i16) -> i16 {
189 if a < -lim {
190 -lim
191 } else if a > lim {
192 lim
193 } else {
194 a
195 }
196}
197
198const RV30_LOOP_FILTER_STRENGTH: [i16; 32] = [
199 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
200 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5
201];
202
203macro_rules! test_bit {
204 ($pat: expr, $x: expr) => ( (($pat >> $x) & 1) != 0 )
205}
206
207fn rv30_loop_filter4(pix: &mut [u8], mut off: usize, step: usize, stride: usize, lim: i16) {
208 for _ in 0..4 {
209 let a = el!(pix, off - 2*step);
210 let b = el!(pix, off - step);
211 let c = el!(pix, off);
212 let d = el!(pix, off + step);
213 let diff0 = ((a - d) - (b - c) * 4) >> 3;
214 let diff = clip_symm(diff0, lim);
215 pix[off - step] = clip8(b + diff);
216 pix[off ] = clip8(c - diff);
217 off += stride;
218 }
219}
220
221fn rv30_div_mv(mv: i16) -> (i16, usize) {
222 let i = mv / 3;
223 let f = mv - i * 3;
224 if f < 0 {
225 (i - 1, (f + 3) as usize)
226 } else {
227 (i, f as usize)
228 }
229}
230
231fn check_pos(x: usize, y: usize, size: usize, w: usize, h: usize, dx: i16, dy: i16, e0: isize, e1: isize, e2: isize, e3: isize) -> bool {
232 let xn = (x as isize) + (dx as isize);
233 let yn = (y as isize) + (dy as isize);
234
235 (xn - e0 >= 0) && (xn + (size as isize) + e1 <= (w as isize)) && (yn - e2 >= 0) && (yn + (size as isize) + e3 <= (h as isize))
236}
237
238const RV30_EDGE1: [isize; 3] = [ 0, 1, 1 ];
239const RV30_EDGE2: [isize; 3] = [ 0, 2, 2 ];
240
241impl RV34DSP for RV30DSP {
242 #[allow(clippy::cognitive_complexity)]
243 fn loop_filter(&self, frame: &mut NAVideoBuffer<u8>, _ftype: FrameType, mbinfo: &[RV34MBInfo], mb_w: usize, _mb_h: usize, row: usize) {
244 let mut offs: [usize; 3] = [0; 3];
245 let mut stride: [usize; 3] = [0; 3];
246
247 for comp in 0..3 {
248 stride[comp] = frame.get_stride(comp);
249 let start = if comp == 0 { row * 16 } else { row * 8 };
250 offs[comp] = frame.get_offset(comp) + start * stride[comp];
251 }
252
253 let data = frame.get_data_mut().unwrap();
254 let dst: &mut [u8] = data.as_mut_slice();
255
256 // vertical filter
257 let mut left_cbp = 0;
258 let mut left_lim = 0;
259 let mut left_dbk = 0;
260 let mut mb_pos: usize = row * mb_w;
261 for mb_x in 0..mb_w {
262 let cur_lim = RV30_LOOP_FILTER_STRENGTH[mbinfo[mb_pos].q as usize];
263 let cur_dbk = mbinfo[mb_pos].deblock;
264 let cur_cbp = mbinfo[mb_pos].cbp_c;
265 let xstart = if mb_x == 0 { 1 } else { 0 };
266 for y in 0..4 {
267 let yoff = offs[0] + mb_x * 16 + y * 4 * stride[0];
268 for x in xstart..4 {
269 let cs = x + y*4;
270 let loc_lim;
271
272 if test_bit!(cur_dbk, cs) {
273 loc_lim = cur_lim;
274 } else if (x == 0) && test_bit!(left_dbk, cs + 3) {
275 loc_lim = left_lim;
276 } else if (x != 0) && test_bit!(cur_dbk, cs - 1) {
277 loc_lim = cur_lim;
278 } else {
279 loc_lim = 0;
280 }
281 if loc_lim != 0 {
282 rv30_loop_filter4(dst, yoff + x * 4, 1, stride[0], loc_lim);
283 }
284 }
285 }
286
287 for comp in 1..3 {
288 for y in 0..2 {
289 let coff = offs[comp] + mb_x * 8 + y * 4 * stride[comp];
290 for x in xstart..2 {
291 let cs = x + y * 2 + (comp - 1) * 4;
292 let loc_lim;
293
294 if test_bit!(cur_cbp, cs) {
295 loc_lim = cur_lim;
296 } else if (x == 0) && test_bit!(left_cbp, cs + 1) {
297 loc_lim = left_lim;
298 } else if (x != 0) && test_bit!(cur_cbp, cs - 1) {
299 loc_lim = cur_lim;
300 } else {
301 loc_lim = 0;
302 }
303 if loc_lim != 0 {
304 rv30_loop_filter4(dst, coff + x * 4, 1, stride[comp], loc_lim);
305 }
306 }
307 }
308 }
309
310 left_lim = cur_lim;
311 left_dbk = cur_dbk;
312 left_cbp = cur_cbp;
313 mb_pos += 1;
314 }
315
316 // horizontal filter
317 let mut mb_pos: usize = row * mb_w;
318 for mb_x in 0..mb_w {
319 let cur_lim = RV30_LOOP_FILTER_STRENGTH[mbinfo[mb_pos].q as usize];
320 let cur_dbk = mbinfo[mb_pos].deblock;
321 let cur_cbp = mbinfo[mb_pos].cbp_c;
322 let ystart = if row == 0 { 1 } else { 0 };
323 let top_lim;
324 let top_dbk;
325 let top_cbp;
326 if row > 0 {
327 top_lim = RV30_LOOP_FILTER_STRENGTH[mbinfo[mb_pos - mb_w].q as usize];
328 top_dbk = mbinfo[mb_pos - mb_w].deblock;
329 top_cbp = mbinfo[mb_pos - mb_w].cbp_c;
330 } else {
331 top_lim = 0;
332 top_dbk = 0;
333 top_cbp = 0;
334 }
335 for y in ystart..4 {
336 let yoff = offs[0] + mb_x * 16 + y * 4 * stride[0];
337 for x in 0..4 {
338 let cs = x + y*4;
339 let loc_lim;
340
341 if test_bit!(cur_dbk, cs) {
342 loc_lim = cur_lim;
343 } else if (y == 0) && test_bit!(top_dbk, cs + 12) {
344 loc_lim = top_lim;
345 } else if (y != 0) && test_bit!(cur_dbk, cs - 4) {
346 loc_lim = cur_lim;
347 } else {
348 loc_lim = 0;
349 }
350 if loc_lim != 0 {
351 rv30_loop_filter4(dst, yoff + x * 4, stride[0], 1, loc_lim);
352 }
353 }
354 }
355
356 for comp in 1..3 {
357 for y in ystart..2 {
358 let coff = offs[comp] + mb_x * 8 + y * 4 * stride[comp];
359 for x in 0..2 {
360 let cs = x + y * 2 + (comp - 1) * 4;
361 let loc_lim;
362
363 if test_bit!(cur_cbp, cs) {
364 loc_lim = cur_lim;
365 } else if (y == 0) && test_bit!(top_cbp, cs + 2) {
366 loc_lim = top_lim;
367 } else if (y != 0) && test_bit!(cur_cbp, cs - 2) {
368 loc_lim = cur_lim;
369 } else {
370 loc_lim = 0;
371 }
372 if loc_lim != 0 {
373 rv30_loop_filter4(dst, coff + x * 4, stride[comp], 1, loc_lim);
374 }
375 }
376 }
377 }
378
379 mb_pos += 1;
380 }
381 }
382 fn do_luma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, mv: MV, use16: bool, avg: bool) {
383 let size: usize = if use16 { 16 } else { 8 };
384 let dstride = frame.get_stride(0);
385 let doffset = frame.get_offset(0) + (if !avg { x + y * dstride } else { 0 });
386 let data = frame.get_data_mut().unwrap();
387 let dst: &mut [u8] = data.as_mut_slice();
388
389 let (w_, h_) = prev_frame.get_dimensions(0);
390 let w = (w_ + 15) & !15;
391 let h = (h_ + 15) & !15;
392
393 let (dx, cx) = rv30_div_mv(mv.x);
394 let (dy, cy) = rv30_div_mv(mv.y);
395 let mode = cx + cy * 3;
396
397 if check_pos(x, y, size, w, h, dx, dy, RV30_EDGE1[cx], RV30_EDGE2[cx], RV30_EDGE1[cy], RV30_EDGE2[cy]) {
398 let sstride = prev_frame.get_stride(0);
399 let mut soffset = prev_frame.get_offset(0) + x + y * sstride;
400 let data = prev_frame.get_data();
401 let src: &[u8] = data.as_slice();
402 soffset = ((soffset as isize) + (dx as isize) + (dy as isize) * (sstride as isize)) as usize;
403 self.luma_mc[if use16 { 0 } else { 1 }][mode](dst, doffset, dstride, src, soffset, sstride);
404 } else {
405 let mut ebuf: [u8; 32*20] = [0; 32*20];
406 edge_emu(prev_frame, (x as isize) + (dx as isize) - 1, (y as isize) + (dy as isize) - 1, 16+3, 16+3, &mut ebuf, 32, 0, 4);
407 self.luma_mc[if use16 { 0 } else { 1 }][mode](dst, doffset, dstride, &ebuf, 32 + 1, 32);
408 }
409 }
410 fn do_chroma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, comp: usize, mv: MV, use8: bool, avg: bool) {
411 let size: usize = if use8 { 8 } else { 4 };
412 let dstride = frame.get_stride(comp);
413 let doffset = frame.get_offset(comp) + (if !avg { x + y * dstride } else { 0 });
414 let data = frame.get_data_mut().unwrap();
415 let dst: &mut [u8] = data.as_mut_slice();
416
417 let (w_, h_) = prev_frame.get_dimensions(comp);
418 let w = (w_ + 7) & !7;
419 let h = (h_ + 7) & !7;
420
421 let (dx, cx) = rv30_div_mv(mv.x / 2);
422 let (dy, cy) = rv30_div_mv(mv.y / 2);
423
424 if check_pos(x, y, size, w, h, dx, dy, 0, 1, 0, 1) {
425 let sstride = prev_frame.get_stride(comp);
426 let mut soffset = prev_frame.get_offset(comp) + x + y * sstride;
427 let data = prev_frame.get_data();
428 let src: &[u8] = data.as_slice();
429 soffset = ((soffset as isize) + (dx as isize) + (dy as isize) * (sstride as isize)) as usize;
430 rv30_chroma_mc(dst, doffset, dstride, src, soffset, sstride, size, cx, cy);
431 } else {
432 let mut ebuf: [u8; 16*10] = [0; 16*10];
433 edge_emu(prev_frame, (x as isize) + (dx as isize), (y as isize) + (dy as isize), 8+1, 8+1, &mut ebuf, 16, comp, 4);
434 rv30_chroma_mc(dst, doffset, dstride, &ebuf, 0, 16, size, cx, cy);
435 }
436 }
437}