51aa1e743145fe88f69811d81a8961b8fecb5937
[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 #[derive(Default)]
343 pub struct H263BlockDSP { }
344
345 impl H263BlockDSP {
346 pub fn new() -> Self {
347 H263BlockDSP { }
348 }
349 }
350
351 #[allow(clippy::erasing_op)]
352 fn deblock_hor(buf: &mut NAVideoBuffer<u8>, comp: usize, strength: u8, off: usize) {
353 let stride = buf.get_stride(comp);
354 let dptr = buf.get_data_mut().unwrap();
355 let buf = dptr.as_mut_slice();
356 for x in 0..8 {
357 let a = buf[off - 2 * stride + x] as i16;
358 let b = buf[off - 1 * stride + x] as i16;
359 let c = buf[off + 0 * stride + x] as i16;
360 let d = buf[off + 1 * stride + x] as i16;
361 let diff = ((a - d) + (c - b) * 4) / 8;
362 if (diff != 0) && (diff > -24) && (diff < 24) {
363 let d1a = (diff.abs() - 2 * (diff.abs() - (strength as i16)).max(0)).max(0);
364 let d1 = if diff < 0 { -d1a } else { d1a };
365 let hd1 = d1a / 2;
366 let d2 = ((a - d) / 4).max(-hd1).min(hd1);
367
368 buf[off - 2 * stride + x] = (a - d2) as u8;
369 buf[off - 1 * stride + x] = (b + d1).max(0).min(255) as u8;
370 buf[off + 0 * stride + x] = (c - d1).max(0).min(255) as u8;
371 buf[off + 1 * stride + x] = (d + d2) as u8;
372 }
373 }
374 }
375
376 fn deblock_ver(buf: &mut NAVideoBuffer<u8>, comp: usize, strength: u8, off: usize) {
377 let stride = buf.get_stride(comp);
378 let dptr = buf.get_data_mut().unwrap();
379 let buf = dptr.as_mut_slice();
380 for y in 0..8 {
381 let a = buf[off - 2 + y * stride] as i16;
382 let b = buf[off - 1 + y * stride] as i16;
383 let c = buf[off + 0 + y * stride] as i16;
384 let d = buf[off + 1 + y * stride] as i16;
385 let diff = (a - d + (c - b) * 4) / 8;
386 if (diff != 0) && (diff > -24) && (diff < 24) {
387 let d1a = (diff.abs() - 2 * (diff.abs() - (strength as i16)).max(0)).max(0);
388 let d1 = if diff < 0 { -d1a } else { d1a };
389 let hd1 = d1a / 2;
390 let d2 = ((a - d) / 4).max(-hd1).min(hd1);
391
392 buf[off - 2 + y * stride] = (a - d2) as u8;
393 buf[off - 1 + y * stride] = (b + d1).max(0).min(255) as u8;
394 buf[off + y * stride] = (c - d1).max(0).min(255) as u8;
395 buf[off + 1 + y * stride] = (d + d2) as u8;
396 }
397 }
398 }
399
400 const FILTER_STRENGTH: [u8; 32] = [
401 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7,
402 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12
403 ];
404
405 pub fn h263_filter_row(buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
406 let stride = buf.get_stride(0);
407 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
408 for mb_x in 0..mb_w {
409 let coff = off;
410 let coded0 = cbpi.is_coded(mb_x, 0);
411 let coded1 = cbpi.is_coded(mb_x, 1);
412 let q = cbpi.get_q(mb_w + mb_x);
413 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
414 if mb_y != 0 {
415 if coded0 && cbpi.is_coded_top(mb_x, 0) { deblock_hor(buf, 0, str, coff); }
416 if coded1 && cbpi.is_coded_top(mb_x, 1) { deblock_hor(buf, 0, str, coff + 8); }
417 }
418 let coff = off + 8 * stride;
419 if cbpi.is_coded(mb_x, 2) && coded0 { deblock_hor(buf, 0, q, coff); }
420 if cbpi.is_coded(mb_x, 3) && coded1 { deblock_hor(buf, 0, q, coff + 8); }
421 off += 16;
422 }
423 let mut leftt = false;
424 let mut leftc = false;
425 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
426 for mb_x in 0..mb_w {
427 let ctop0 = cbpi.is_coded_top(mb_x, 0);
428 let ctop1 = cbpi.is_coded_top(mb_x, 0);
429 let ccur0 = cbpi.is_coded(mb_x, 0);
430 let ccur1 = cbpi.is_coded(mb_x, 1);
431 let q = cbpi.get_q(mb_w + mb_x);
432 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
433 if mb_y != 0 {
434 let coff = off - 8 * stride;
435 let qtop = cbpi.get_q(mb_x);
436 let strtop = if qtop < 32 { FILTER_STRENGTH[qtop as usize] } else { 0 };
437 if leftt && ctop0 { deblock_ver(buf, 0, strtop, coff); }
438 if ctop0 && ctop1 { deblock_ver(buf, 0, strtop, coff + 8); }
439 }
440 if leftc && ccur0 { deblock_ver(buf, 0, str, off); }
441 if ccur0 && ccur1 { deblock_ver(buf, 0, str, off + 8); }
442 leftt = ctop1;
443 leftc = ccur1;
444 off += 16;
445 }
446 let strideu = buf.get_stride(1);
447 let stridev = buf.get_stride(2);
448 let offu = buf.get_offset(1) + mb_y * 8 * strideu;
449 let offv = buf.get_offset(2) + mb_y * 8 * stridev;
450 if mb_y != 0 {
451 for mb_x in 0..mb_w {
452 let ctu = cbpi.is_coded_top(mb_x, 4);
453 let ccu = cbpi.is_coded(mb_x, 4);
454 let ctv = cbpi.is_coded_top(mb_x, 5);
455 let ccv = cbpi.is_coded(mb_x, 5);
456 let q = cbpi.get_q(mb_w + mb_x);
457 let str = if q < 32 { FILTER_STRENGTH[q as usize] } else { 0 };
458 if ctu && ccu { deblock_hor(buf, 1, str, offu + mb_x * 8); }
459 if ctv && ccv { deblock_hor(buf, 2, str, offv + mb_x * 8); }
460 }
461 let mut leftu = false;
462 let mut leftv = false;
463 let offu = buf.get_offset(1) + (mb_y - 1) * 8 * strideu;
464 let offv = buf.get_offset(2) + (mb_y - 1) * 8 * stridev;
465 for mb_x in 0..mb_w {
466 let ctu = cbpi.is_coded_top(mb_x, 4);
467 let ctv = cbpi.is_coded_top(mb_x, 5);
468 let qt = cbpi.get_q(mb_x);
469 let strt = if qt < 32 { FILTER_STRENGTH[qt as usize] } else { 0 };
470 if leftu && ctu { deblock_ver(buf, 1, strt, offu + mb_x * 8); }
471 if leftv && ctv { deblock_ver(buf, 2, strt, offv + mb_x * 8); }
472 leftu = ctu;
473 leftv = ctv;
474 }
475 }
476 }
477
478 impl BlockDSP for H263BlockDSP {
479 fn idct(&self, blk: &mut [i16; 64]) {
480 h263_idct(blk)
481 }
482 fn copy_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
483 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
484 let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
485
486 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
487
488 blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_FUNCS);
489 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);
490 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);
491 }
492 fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
493 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
494
495 for i in 0..4 {
496 let xadd = (i & 1) * 8;
497 let yadd = (i & 2) * 4;
498 let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
499
500 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);
501 }
502
503 let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
504 let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
505 let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
506 let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
507 for plane in 1..3 {
508 blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS);
509 }
510 }
511 fn avg_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mv: MV) {
512 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
513 let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 });
514
515 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
516
517 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);
518 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);
519 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);
520 }
521 fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer<u8>, src: NAVideoBufferRef<u8>, xpos: usize, ypos: usize, mvs: &[MV; 4]) {
522 let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap();
523
524 for i in 0..4 {
525 let xadd = (i & 1) * 8;
526 let yadd = (i & 2) * 4;
527 let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize;
528
529 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);
530 }
531
532 let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3];
533 let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize];
534 let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize];
535 let mode = ((cmx & 1) + (cmy & 1) * 2) as usize;
536 for plane in 1..3 {
537 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);
538 }
539 }
540 fn filter_row(&self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
541 h263_filter_row(buf, mb_y, mb_w, cbpi)
542 }
543 }
544
545 macro_rules! obmc_filter {
546 ($src: expr, $base_off: expr, $off0: expr, $w0: expr, $off1: expr, $w1: expr, $off2: expr, $w2: expr) => ({
547 let a = $src[$base_off + $off0] as u16;
548 let b = $src[$base_off + $off1] as u16;
549 let c = $src[$base_off + $off2] as u16;
550 ((a * $w0 + b * $w1 + c * $w2 + 4) >> 3) as u8
551 })
552 }
553 pub fn obmc_filter(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize) {
554 let top_off = 8 + sstride * 0;
555 let left_off = 0 + sstride * 8;
556 let right_off = 16 + sstride * 8;
557 let bottom_off = 8 + sstride * 16;
558 let cur_off = 8 + sstride * 8;
559
560 let mut doff = 0;
561 let mut soff = 0;
562
563 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, top_off, 2, cur_off, 4);
564 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 1, top_off, 2, cur_off, 5);
565 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, top_off, 2, cur_off, 5);
566 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, top_off, 2, cur_off, 5);
567 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, top_off, 2, cur_off, 5);
568 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, top_off, 2, cur_off, 5);
569 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 1, top_off, 2, cur_off, 5);
570 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, top_off, 2, cur_off, 4);
571 doff += dstride;
572 soff += sstride;
573
574 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, top_off, 1, cur_off, 5);
575 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 2, top_off, 1, cur_off, 5);
576 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, top_off, 2, cur_off, 5);
577 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, top_off, 2, cur_off, 5);
578 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, top_off, 2, cur_off, 5);
579 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, top_off, 2, cur_off, 5);
580 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 2, top_off, 1, cur_off, 5);
581 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, top_off, 1, cur_off, 5);
582 doff += dstride;
583 soff += sstride;
584
585 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, top_off, 1, cur_off, 5);
586 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 2, top_off, 1, cur_off, 5);
587 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, top_off, 1, cur_off, 6);
588 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, top_off, 1, cur_off, 6);
589 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, top_off, 1, cur_off, 6);
590 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, top_off, 1, cur_off, 6);
591 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 2, top_off, 1, cur_off, 5);
592 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, top_off, 1, cur_off, 5);
593 doff += dstride;
594 soff += sstride;
595
596 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, top_off, 1, cur_off, 5);
597 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 2, top_off, 1, cur_off, 5);
598 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, top_off, 1, cur_off, 6);
599 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, top_off, 1, cur_off, 6);
600 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, top_off, 1, cur_off, 6);
601 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, top_off, 1, cur_off, 6);
602 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 2, top_off, 1, cur_off, 5);
603 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, top_off, 1, cur_off, 5);
604 doff += dstride;
605 soff += sstride;
606
607 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, bottom_off, 1, cur_off, 5);
608 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 2, bottom_off, 1, cur_off, 5);
609 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, bottom_off, 1, cur_off, 6);
610 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, bottom_off, 1, cur_off, 6);
611 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, bottom_off, 1, cur_off, 6);
612 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, bottom_off, 1, cur_off, 6);
613 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 2, bottom_off, 1, cur_off, 5);
614 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, bottom_off, 1, cur_off, 5);
615 doff += dstride;
616 soff += sstride;
617
618 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, bottom_off, 1, cur_off, 5);
619 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 2, bottom_off, 1, cur_off, 5);
620 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, bottom_off, 1, cur_off, 6);
621 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, bottom_off, 1, cur_off, 6);
622 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, bottom_off, 1, cur_off, 6);
623 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, bottom_off, 1, cur_off, 6);
624 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 2, bottom_off, 1, cur_off, 5);
625 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, bottom_off, 1, cur_off, 5);
626 doff += dstride;
627 soff += sstride;
628
629 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, bottom_off, 1, cur_off, 5);
630 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 2, bottom_off, 1, cur_off, 5);
631 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, bottom_off, 2, cur_off, 5);
632 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, bottom_off, 2, cur_off, 5);
633 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, bottom_off, 2, cur_off, 5);
634 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, bottom_off, 2, cur_off, 5);
635 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 2, bottom_off, 1, cur_off, 5);
636 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, bottom_off, 1, cur_off, 5);
637 doff += dstride;
638 soff += sstride;
639
640 dst[doff + 0] = obmc_filter!(src, soff + 0, left_off, 2, bottom_off, 2, cur_off, 4);
641 dst[doff + 1] = obmc_filter!(src, soff + 1, left_off, 1, bottom_off, 2, cur_off, 5);
642 dst[doff + 2] = obmc_filter!(src, soff + 2, left_off, 1, bottom_off, 2, cur_off, 5);
643 dst[doff + 3] = obmc_filter!(src, soff + 3, left_off, 1, bottom_off, 2, cur_off, 5);
644 dst[doff + 4] = obmc_filter!(src, soff + 4, right_off, 1, bottom_off, 2, cur_off, 5);
645 dst[doff + 5] = obmc_filter!(src, soff + 5, right_off, 1, bottom_off, 2, cur_off, 5);
646 dst[doff + 6] = obmc_filter!(src, soff + 6, right_off, 1, bottom_off, 2, cur_off, 5);
647 dst[doff + 7] = obmc_filter!(src, soff + 7, right_off, 2, bottom_off, 2, cur_off, 4);
648 }