h263-based codecs: use proper motion compensation
[nihav.git] / nihav-codec-support / src / codecs / h263 / code.rs
1 use nihav_core::frame::{NAVideoBuffer, NAVideoBufferRef, NASimpleVideoFrame};
2 use super::{BlockDSP, CBPInfo, MV};
3 use super::super::blockdsp;
4 use super::data::H263_CHROMA_ROUND;
5
6 /*const W1: i32 = 22725;
7 const W2: i32 = 21407;
8 const W3: i32 = 19266;
9 const W4: i32 = 16383;
10 const W5: i32 = 12873;
11 const W6: i32 = 8867;
12 const W7: i32 = 4520;
13
14 const ROW_SHIFT: u8 = 11;
15 const COL_SHIFT: u8 = 20;
16
17 fn idct_row(row: &mut [i16]) {
18 let in0 = row[0] as i32;
19 let in1 = row[1] as i32;
20 let in2 = row[2] as i32;
21 let in3 = row[3] as i32;
22 let in4 = row[4] as i32;
23 let in5 = row[5] as i32;
24 let in6 = row[6] as i32;
25 let in7 = row[7] as i32;
26
27 let mut a0 = in0 * W1 + (1 << (ROW_SHIFT - 1));
28 let mut a1 = a0;
29 let mut a2 = a0;
30 let mut a3 = a0;
31
32 a0 += W2 * in2;
33 a1 += W6 * in2;
34 a2 -= W6 * in2;
35 a3 -= W2 * in2;
36
37 let mut b0 = W1 * in1 + W3 * in3;
38 let mut b1 = W3 * in1 - W7 * in3;
39 let mut b2 = W5 * in1 - W1 * in3;
40 let mut b3 = W7 * in1 - W5 * in3;
41
42 a0 += W4 * in4 + W6 * in6;
43 a1 -= W4 * in4 + W2 * in6;
44 a2 -= W4 * in4 - W2 * in6;
45 a3 += W4 * in4 - W6 * in6;
46
47 b0 += W5 * in5 + W7 * in7;
48 b1 -= W1 * in5 + W5 * in7;
49 b2 += W7 * in5 + W3 * in7;
50 b3 += W3 * in5 - W1 * in7;
51
52 row[0] = ((a0 + b0) >> ROW_SHIFT) as i16;
53 row[7] = ((a0 - b0) >> ROW_SHIFT) as i16;
54 row[1] = ((a1 + b1) >> ROW_SHIFT) as i16;
55 row[6] = ((a1 - b1) >> ROW_SHIFT) as i16;
56 row[2] = ((a2 + b2) >> ROW_SHIFT) as i16;
57 row[5] = ((a2 - b2) >> ROW_SHIFT) as i16;
58 row[3] = ((a3 + b3) >> ROW_SHIFT) as i16;
59 row[4] = ((a3 - b3) >> ROW_SHIFT) as i16;
60 }
61
62 fn idct_col(blk: &mut [i16; 64], off: usize) {
63 let in0 = blk[off + 0*8] as i32;
64 let in1 = blk[off + 1*8] as i32;
65 let in2 = blk[off + 2*8] as i32;
66 let in3 = blk[off + 3*8] as i32;
67 let in4 = blk[off + 4*8] as i32;
68 let in5 = blk[off + 5*8] as i32;
69 let in6 = blk[off + 6*8] as i32;
70 let in7 = blk[off + 7*8] as i32;
71
72 let mut a0 = in0 * W1 + (1 << (COL_SHIFT - 1));
73 let mut a1 = a0;
74 let mut a2 = a0;
75 let mut a3 = a0;
76
77 a0 += W2 * in2;
78 a1 += W6 * in2;
79 a2 -= W6 * in2;
80 a3 -= W2 * in2;
81
82 let mut b0 = W1 * in1 + W3 * in3;
83 let mut b1 = W3 * in1 - W7 * in3;
84 let mut b2 = W5 * in1 - W1 * in3;
85 let mut b3 = W7 * in1 - W5 * in3;
86
87 a0 += W4 * in4 + W6 * in6;
88 a1 -= W4 * in4 + W2 * in6;
89 a2 -= W4 * in4 - W2 * in6;
90 a3 += W4 * in4 - W6 * in6;
91
92 b0 += W5 * in5 + W7 * in7;
93 b1 -= W1 * in5 + W5 * in7;
94 b2 += W7 * in5 + W3 * in7;
95 b3 += W3 * in5 - W1 * in7;
96
97 blk[off + 0*8] = ((a0 + b0) >> COL_SHIFT) as i16;
98 blk[off + 7*8] = ((a0 - b0) >> COL_SHIFT) as i16;
99 blk[off + 1*8] = ((a1 + b1) >> COL_SHIFT) as i16;
100 blk[off + 6*8] = ((a1 - b1) >> COL_SHIFT) as i16;
101 blk[off + 2*8] = ((a2 + b2) >> COL_SHIFT) as i16;
102 blk[off + 5*8] = ((a2 - b2) >> COL_SHIFT) as i16;
103 blk[off + 3*8] = ((a3 + b3) >> COL_SHIFT) as i16;
104 blk[off + 4*8] = ((a3 - b3) >> COL_SHIFT) as i16;
105 }
106
107 #[allow(dead_code)]
108 pub fn h263_idct(blk: &mut [i16; 64]) {
109 for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); }
110 for i in 0..8 { idct_col(blk, i); }
111 }*/
112
113 const W1: i32 = 2841;
114 const W2: i32 = 2676;
115 const W3: i32 = 2408;
116 const W5: i32 = 1609;
117 const W6: i32 = 1108;
118 const W7: i32 = 565;
119 const W8: i32 = 181;
120
121 const ROW_SHIFT: u8 = 8;
122 const COL_SHIFT: u8 = 14;
123
124 #[allow(clippy::erasing_op)]
125 fn idct_row(row: &mut [i16]) {
126 let in0 = ((i32::from(row[0])) << 11) + (1 << (ROW_SHIFT - 1));
127 let in1 = (i32::from(row[4])) << 11;
128 let in2 = i32::from(row[6]);
129 let in3 = i32::from(row[2]);
130 let in4 = i32::from(row[1]);
131 let in5 = i32::from(row[7]);
132 let in6 = i32::from(row[5]);
133 let in7 = i32::from(row[3]);
134
135 let tmp = W7 * (in4 + in5);
136 let a4 = tmp + (W1 - W7) * in4;
137 let a5 = tmp - (W1 + W7) * in5;
138
139 let tmp = W3 * (in6 + in7);
140 let a6 = tmp - (W3 - W5) * in6;
141 let a7 = tmp - (W3 + W5) * in7;
142
143 let tmp = in0 + in1;
144
145 let a0 = in0 - in1;
146 let t1 = W6 * (in2 + in3);
147 let a2 = t1 - (W2 + W6) * in2;
148 let a3 = t1 + (W2 - W6) * in3;
149 let b1 = a4 + a6;
150
151 let b4 = a4 - a6;
152 let t2 = a5 - a7;
153 let b6 = a5 + a7;
154 let b7 = tmp + a3;
155 let b5 = tmp - a3;
156 let b3 = a0 + a2;
157 let b0 = a0 - a2;
158 let b2 = (W8 * (b4 + t2) + 128) >> 8;
159 let b4 = (W8 * (b4 - t2) + 128) >> 8;
160
161 row[0] = ((b7 + b1) >> ROW_SHIFT) as i16;
162 row[7] = ((b7 - b1) >> ROW_SHIFT) as i16;
163 row[1] = ((b3 + b2) >> ROW_SHIFT) as i16;
164 row[6] = ((b3 - b2) >> ROW_SHIFT) as i16;
165 row[2] = ((b0 + b4) >> ROW_SHIFT) as i16;
166 row[5] = ((b0 - b4) >> ROW_SHIFT) as i16;
167 row[3] = ((b5 + b6) >> ROW_SHIFT) as i16;
168 row[4] = ((b5 - b6) >> ROW_SHIFT) as i16;
169 }
170
171 #[allow(clippy::erasing_op)]
172 fn idct_col(blk: &mut [i16; 64], off: usize) {
173 let in0 = ((i32::from(blk[off + 0*8])) << 8) + (1 << (COL_SHIFT - 1));
174 let in1 = (i32::from(blk[off + 4*8])) << 8;
175 let in2 = i32::from(blk[off + 6*8]);
176 let in3 = i32::from(blk[off + 2*8]);
177 let in4 = i32::from(blk[off + 1*8]);
178 let in5 = i32::from(blk[off + 7*8]);
179 let in6 = i32::from(blk[off + 5*8]);
180 let in7 = i32::from(blk[off + 3*8]);
181
182 let tmp = W7 * (in4 + in5);
183 let a4 = (tmp + (W1 - W7) * in4) >> 3;
184 let a5 = (tmp - (W1 + W7) * in5) >> 3;
185
186 let tmp = W3 * (in6 + in7);
187 let a6 = (tmp - (W3 - W5) * in6) >> 3;
188 let a7 = (tmp - (W3 + W5) * in7) >> 3;
189
190 let tmp = in0 + in1;
191
192 let a0 = in0 - in1;
193 let t1 = W6 * (in2 + in3);
194 let a2 = (t1 - (W2 + W6) * in2) >> 3;
195 let a3 = (t1 + (W2 - W6) * in3) >> 3;
196 let b1 = a4 + a6;
197
198 let b4 = a4 - a6;
199 let t2 = a5 - a7;
200 let b6 = a5 + a7;
201 let b7 = tmp + a3;
202 let b5 = tmp - a3;
203 let b3 = a0 + a2;
204 let b0 = a0 - a2;
205 let b2 = (W8 * (b4 + t2) + 128) >> 8;
206 let b4 = (W8 * (b4 - t2) + 128) >> 8;
207
208 blk[off + 0*8] = ((b7 + b1) >> COL_SHIFT) as i16;
209 blk[off + 7*8] = ((b7 - b1) >> COL_SHIFT) as i16;
210 blk[off + 1*8] = ((b3 + b2) >> COL_SHIFT) as i16;
211 blk[off + 6*8] = ((b3 - b2) >> COL_SHIFT) as i16;
212 blk[off + 2*8] = ((b0 + b4) >> COL_SHIFT) as i16;
213 blk[off + 5*8] = ((b0 - b4) >> COL_SHIFT) as i16;
214 blk[off + 3*8] = ((b5 + b6) >> COL_SHIFT) as i16;
215 blk[off + 4*8] = ((b5 - b6) >> COL_SHIFT) as i16;
216 }
217
218 #[allow(dead_code)]
219 pub fn h263_idct(blk: &mut [i16; 64]) {
220 for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); }
221 for i in 0..8 { idct_col(blk, i); }
222 }
223
224 fn h263_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
225 {
226 let mut didx = 0;
227 let mut sidx = 0;
228 for _ in 0..bh {
229 for x in 0..bw { dst[didx + x] = src[sidx + x]; }
230 didx += dstride;
231 sidx += sstride;
232 }
233 }
234
235 fn h263_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
236 {
237 let mut didx = 0;
238 let mut sidx = 0;
239 for _ in 0..bh {
240 for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + 1] as u16) + 1) >> 1) as u8; }
241 didx += dstride;
242 sidx += sstride;
243 }
244 }
245
246 fn h263_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
247 {
248 let mut didx = 0;
249 let mut sidx = 0;
250 for _ in 0..bh {
251 for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16) + 1) >> 1) as u8; }
252 didx += dstride;
253 sidx += sstride;
254 }
255 }
256
257 fn h263_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
258 {
259 let mut didx = 0;
260 let mut sidx = 0;
261 for _ in 0..bh {
262 for x in 0..bw {
263 dst[didx + x] = (((src[sidx + x] as u16) +
264 (src[sidx + x + 1] as u16) +
265 (src[sidx + x + sstride] as u16) +
266 (src[sidx + x + sstride + 1] as u16) + 2) >> 2) as u8;
267 }
268 didx += dstride;
269 sidx += sstride;
270 }
271 }
272
273 pub const H263_INTERP_FUNCS: &[blockdsp::BlkInterpFunc] = &[
274 h263_interp00, h263_interp01, h263_interp10, h263_interp11 ];
275
276 fn h263_interp00_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
277 {
278 let mut didx = 0;
279 let mut sidx = 0;
280 for _ in 0..bh {
281 for x in 0..bw {
282 let a = dst[didx + x] as u16;
283 let b = src[sidx + x] as u16;
284 dst[didx + x] = ((a + b + 1) >> 1) as u8;
285 }
286 didx += dstride;
287 sidx += sstride;
288 }
289 }
290
291 fn h263_interp01_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
292 {
293 let mut didx = 0;
294 let mut sidx = 0;
295 for _ in 0..bh {
296 for x in 0..bw {
297 let a = dst[didx + x] as u16;
298 let b = ((src[sidx + x] as u16) + (src[sidx + x + 1] as u16) + 1) >> 1;
299 dst[didx + x] = ((a + b + 1) >> 1) as u8;
300 }
301 didx += dstride;
302 sidx += sstride;
303 }
304 }
305
306 fn h263_interp10_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
307 {
308 let mut didx = 0;
309 let mut sidx = 0;
310 for _ in 0..bh {
311 for x in 0..bw {
312 let a = dst[didx + x] as u16;
313 let b = ((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16) + 1) >> 1;
314 dst[didx + x] = ((a + b + 1) >> 1) as u8;
315 }
316 didx += dstride;
317 sidx += sstride;
318 }
319 }
320
321 fn h263_interp11_avg(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize)
322 {
323 let mut didx = 0;
324 let mut sidx = 0;
325 for _ in 0..bh {
326 for x in 0..bw {
327 let a = dst[didx + x] as u16;
328 let b = ((src[sidx + x] as u16) +
329 (src[sidx + x + 1] as u16) +
330 (src[sidx + x + sstride] as u16) +
331 (src[sidx + x + sstride + 1] as u16) + 2) >> 2;
332 dst[didx + x] = ((a + b + 1) >> 1) as u8;
333 }
334 didx += dstride;
335 sidx += sstride;
336 }
337 }
338
339 pub const H263_INTERP_AVG_FUNCS: &[blockdsp::BlkInterpFunc] = &[
340 h263_interp00_avg, h263_interp01_avg, h263_interp10_avg, h263_interp11_avg ];
341
342 pub struct H263BlockDSP { }
343
344 impl H263BlockDSP {
345 pub fn new() -> Self {
346 H263BlockDSP { }
347 }
348 }
349
350 #[allow(clippy::erasing_op)]
351 fn deblock_hor(buf: &mut NAVideoBuffer<u8>, comp: usize, strength: u8, off: usize) {
352 let stride = buf.get_stride(comp);
353 let dptr = buf.get_data_mut().unwrap();
354 let buf = dptr.as_mut_slice();
355 for x in 0..8 {
356 let a = buf[off - 2 * stride + x] as i16;
357 let b = buf[off - 1 * stride + x] as i16;
358 let c = buf[off + 0 * stride + x] as i16;
359 let d = buf[off + 1 * stride + x] as i16;
360 let diff = ((a - d) + (c - b) * 4) / 8;
361 if (diff != 0) && (diff > -24) && (diff < 24) {
362 let d1a = (diff.abs() - 2 * (diff.abs() - (strength as i16)).max(0)).max(0);
363 let d1 = if d1a < 0 { 0 } else { d1a };
364 let hd1 = d1a / 2;
365 let d2 = ((a - d) / 4).max(-hd1).min(hd1);
366
367 buf[off - 2 * stride + x] = (a - d2) as u8;
368 buf[off - 1 * stride + x] = (b + d1).max(0).min(255) as u8;
369 buf[off + 0 * stride + x] = (c - d1).max(0).min(255) as u8;
370 buf[off + 1 * stride + x] = (d + d2) as u8;
371 }
372 }
373 }
374
375 fn deblock_ver(buf: &mut NAVideoBuffer<u8>, comp: usize, strength: u8, off: usize) {
376 let stride = buf.get_stride(comp);
377 let dptr = buf.get_data_mut().unwrap();
378 let buf = dptr.as_mut_slice();
379 for y in 0..8 {
380 let a = buf[off - 2 + y * stride] as i16;
381 let b = buf[off - 1 + y * stride] as i16;
382 let c = buf[off + 0 + y * stride] as i16;
383 let d = buf[off + 1 + y * stride] as i16;
384 let diff = (a - d + (c - b) * 4) / 8;
385 if (diff != 0) && (diff > -24) && (diff < 24) {
386 let d1a = (diff.abs() - 2 * (diff.abs() - (strength as i16)).max(0)).max(0);
387 let d1 = if d1a < 0 { 0 } else { d1a };
388 let hd1 = d1a / 2;
389 let d2 = ((a - d) / 4).max(-hd1).min(hd1);
390
391 buf[off - 2 + y * stride] = (a - d2) as u8;
392 buf[off - 1 + y * stride] = (b + d1).max(0).min(255) as u8;
393 buf[off + y * stride] = (c - d1).max(0).min(255) as u8;
394 buf[off + 1 + y * stride] = (d + d2) as u8;
395 }
396 }
397 }
398
399 const FILTER_STRENGTH: [u8; 32] = [
400 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7,
401 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12
402 ];
403
404 pub fn h263_filter_row(buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
405 let stride = buf.get_stride(0);
406 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
407 for mb_x in 0..mb_w {
408 let coff = off;
409 let coded0 = cbpi.is_coded(mb_x, 0);
410 let coded1 = cbpi.is_coded(mb_x, 1);
411 let q = cbpi.get_q(mb_w + mb_x);
412 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
413 if mb_y != 0 {
414 if coded0 && cbpi.is_coded_top(mb_x, 0) { deblock_hor(buf, 0, str, coff); }
415 if coded1 && cbpi.is_coded_top(mb_x, 1) { deblock_hor(buf, 0, str, coff + 8); }
416 }
417 let coff = off + 8 * stride;
418 if cbpi.is_coded(mb_x, 2) && coded0 { deblock_hor(buf, 0, q, coff); }
419 if cbpi.is_coded(mb_x, 3) && coded1 { deblock_hor(buf, 0, q, coff + 8); }
420 off += 16;
421 }
422 let mut leftt = false;
423 let mut leftc = false;
424 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
425 for mb_x in 0..mb_w {
426 let ctop0 = cbpi.is_coded_top(mb_x, 0);
427 let ctop1 = cbpi.is_coded_top(mb_x, 0);
428 let ccur0 = cbpi.is_coded(mb_x, 0);
429 let ccur1 = cbpi.is_coded(mb_x, 1);
430 let q = cbpi.get_q(mb_w + mb_x);
431 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
432 if mb_y != 0 {
433 let coff = off - 8 * stride;
434 let qtop = cbpi.get_q(mb_x);
435 let strtop = if qtop < 32 { FILTER_STRENGTH[qtop as usize] } else { 0 };
436 if leftt && ctop0 { deblock_ver(buf, 0, strtop, coff); }
437 if ctop0 && ctop1 { deblock_ver(buf, 0, strtop, coff + 8); }
438 }
439 if leftc && ccur0 { deblock_ver(buf, 0, str, off); }
440 if ccur0 && ccur1 { deblock_ver(buf, 0, str, off + 8); }
441 leftt = ctop1;
442 leftc = ccur1;
443 off += 16;
444 }
445 let strideu = buf.get_stride(1);
446 let stridev = buf.get_stride(2);
447 let offu = buf.get_offset(1) + mb_y * 8 * strideu;
448 let offv = buf.get_offset(2) + mb_y * 8 * stridev;
449 if mb_y != 0 {
450 for mb_x in 0..mb_w {
451 let ctu = cbpi.is_coded_top(mb_x, 4);
452 let ccu = cbpi.is_coded(mb_x, 4);
453 let ctv = cbpi.is_coded_top(mb_x, 5);
454 let ccv = cbpi.is_coded(mb_x, 5);
455 let q = cbpi.get_q(mb_w + mb_x);
456 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
457 if ctu && ccu { deblock_hor(buf, 1, str, offu + mb_x * 8); }
458 if ctv && ccv { deblock_hor(buf, 2, str, offv + mb_x * 8); }
459 }
460 let mut leftu = false;
461 let mut leftv = false;
462 let offu = buf.get_offset(1) + (mb_y - 1) * 8 * strideu;
463 let offv = buf.get_offset(2) + (mb_y - 1) * 8 * stridev;
464 for mb_x in 0..mb_w {
465 let ctu = cbpi.is_coded_top(mb_x, 4);
466 let ctv = cbpi.is_coded_top(mb_x, 5);
467 let qt = cbpi.get_q(mb_x);
468 let strt = if qt < 32 { FILTER_STRENGTH[qt as usize] } else { 0 };
469 if leftu && ctu { deblock_ver(buf, 1, strt, offu + mb_x * 8); }
470 if leftv && ctv { deblock_ver(buf, 2, strt, offv + mb_x * 8); }
471 leftu = ctu;
472 leftv = ctv;
473 }
474 }
475 }
476
477 impl BlockDSP for H263BlockDSP {
478 fn idct(&self, blk: &mut [i16; 64]) {
479 h263_idct(blk)
480 }
481 fn copy_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
482 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
483 let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
484
485 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
486
487 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_FUNCS);
488 blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS);
489 blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS);
490 }
491 fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
492 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
493
494 for i in 0..4 {
495 let xadd = (i & 1) * 8;
496 let yadd = (i & 2) * 4;
497 let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
498
499 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
500 }
501
502 let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
503 let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
504 let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
505 let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
506 for plane in 1..3 {
507 blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
508 }
509 }
510 fn avg_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
511 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
512 let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
513
514 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
515
516 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_AVG_FUNCS);
517 blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS);
518 blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS);
519 }
520 fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
521 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
522
523 for i in 0..4 {
524 let xadd = (i & 1) * 8;
525 let yadd = (i & 2) * 4;
526 let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
527
528 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS);
529 }
530
531 let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
532 let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
533 let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
534 let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
535 for plane in 1..3 {
536 blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS);
537 }
538 }
539 fn filter_row(&self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
540 h263_filter_row(buf, mb_y, mb_w, cbpi)
541 }
542 }