split nihav-codec-support crate from nihav-core
[nihav.git] / nihav-codec-support / src / codecs / h263 / code.rs
CommitLineData
b4d5b851 1use nihav_core::frame::NAVideoBuffer;
2a2aa421
KS
2use super::{BlockDSP, CBPInfo, MV};
3use super::super::blockdsp;
cf64af13
KS
4//use super::h263data::*;
5
6/*const W1: i32 = 22725;
7const W2: i32 = 21407;
8const W3: i32 = 19266;
9const W4: i32 = 16383;
10const W5: i32 = 12873;
11const W6: i32 = 8867;
12const W7: i32 = 4520;
13
14const ROW_SHIFT: u8 = 11;
15const COL_SHIFT: u8 = 20;
16
17fn 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
62fn 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)]
108pub 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
113const W1: i32 = 2841;
114const W2: i32 = 2676;
115const W3: i32 = 2408;
116const W5: i32 = 1609;
117const W6: i32 = 1108;
118const W7: i32 = 565;
119const W8: i32 = 181;
120
121const ROW_SHIFT: u8 = 8;
122const COL_SHIFT: u8 = 14;
123
e243ceb4 124#[allow(clippy::erasing_op)]
cf64af13 125fn idct_row(row: &mut [i16]) {
e243ceb4
KS
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]);
cf64af13
KS
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
e243ceb4 171#[allow(clippy::erasing_op)]
cf64af13 172fn idct_col(blk: &mut [i16; 64], off: usize) {
e243ceb4
KS
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]);
cf64af13
KS
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)]
219pub 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
224fn 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
235fn 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
246fn 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
257fn 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
fdb4b2fb 273pub const H263_INTERP_FUNCS: &[blockdsp::BlkInterpFunc] = &[
cf64af13 274 h263_interp00, h263_interp01, h263_interp10, h263_interp11 ];
21c16d5f
KS
275
276fn 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
291fn 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
306fn 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
321fn 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
fdb4b2fb 339pub const H263_INTERP_AVG_FUNCS: &[blockdsp::BlkInterpFunc] = &[
21c16d5f 340 h263_interp00_avg, h263_interp01_avg, h263_interp10_avg, h263_interp11_avg ];
2a2aa421
KS
341
342pub struct H263BlockDSP { }
343
344impl H263BlockDSP {
345 pub fn new() -> Self {
346 H263BlockDSP { }
347 }
348}
349
e243ceb4 350#[allow(clippy::erasing_op)]
2a2aa421
KS
351fn deblock_hor(buf: &mut NAVideoBuffer<u8>, comp: usize, q: u8, off: usize) {
352 let stride = buf.get_stride(comp);
1a967e6b 353 let dptr = buf.get_data_mut().unwrap();
9037cf6b 354 let buf = dptr.as_mut_slice();
2a2aa421
KS
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) * 3 + (c - b) * 8) >> 4;
361 if (diff != 0) && (diff >= -32) && (diff < 32) {
362 let d0 = diff.abs() * 2 - (q as i16);
363 let d1 = if d0 < 0 { 0 } else { d0 };
364 let d2 = diff.abs() - d1;
365 let d3 = if d2 < 0 { 0 } else { d2 };
366
367 let delta = if diff < 0 { -d3 } else { d3 };
368
369 let b1 = b + delta;
370 if b1 < 0 { buf[off - 1 * stride + x] = 0; }
371 else if b1 > 255 { buf[off - 1 * stride + x] = 0xFF; }
372 else { buf[off - 1 * stride + x] = b1 as u8; }
373 let c1 = c - delta;
374 if c1 < 0 { buf[off + x] = 0; }
375 else if c1 > 255 { buf[off + x] = 0xFF; }
376 else { buf[off + x] = c1 as u8; }
377 }
378 }
379}
380
381fn deblock_ver(buf: &mut NAVideoBuffer<u8>, comp: usize, q: u8, off: usize) {
382 let stride = buf.get_stride(comp);
1a967e6b 383 let dptr = buf.get_data_mut().unwrap();
9037cf6b 384 let buf = dptr.as_mut_slice();
2a2aa421
KS
385 for y in 0..8 {
386 let a = buf[off - 2 + y * stride] as i16;
387 let b = buf[off - 1 + y * stride] as i16;
388 let c = buf[off + 0 + y * stride] as i16;
389 let d = buf[off + 1 + y * stride] as i16;
390 let diff = ((a - d) * 3 + (c - b) * 8) >> 4;
391 if (diff != 0) && (diff >= -32) && (diff < 32) {
392 let d0 = diff.abs() * 2 - (q as i16);
393 let d1 = if d0 < 0 { 0 } else { d0 };
394 let d2 = diff.abs() - d1;
395 let d3 = if d2 < 0 { 0 } else { d2 };
396
397 let delta = if diff < 0 { -d3 } else { d3 };
398
399 let b1 = b + delta;
400 if b1 < 0 { buf[off - 1 + y * stride] = 0; }
401 else if b1 > 255 { buf[off - 1 + y * stride] = 0xFF; }
402 else { buf[off - 1 + y * stride] = b1 as u8; }
403 let c1 = c - delta;
404 if c1 < 0 { buf[off + y * stride] = 0; }
405 else if c1 > 255 { buf[off + y * stride] = 0xFF; }
406 else { buf[off + y * stride] = c1 as u8; }
407 }
408 }
409}
410
411pub fn h263_filter_row(buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
412 let stride = buf.get_stride(0);
413 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
414 for mb_x in 0..mb_w {
415 let coff = off;
416 let coded0 = cbpi.is_coded(mb_x, 0);
417 let coded1 = cbpi.is_coded(mb_x, 1);
418 let q = cbpi.get_q(mb_w + mb_x);
419 if mb_y != 0 {
420 if coded0 && cbpi.is_coded_top(mb_x, 0) { deblock_hor(buf, 0, q, coff); }
421 if coded1 && cbpi.is_coded_top(mb_x, 1) { deblock_hor(buf, 0, q, coff + 8); }
422 }
423 let coff = off + 8 * stride;
424 if cbpi.is_coded(mb_x, 2) && coded0 { deblock_hor(buf, 0, q, coff); }
425 if cbpi.is_coded(mb_x, 3) && coded1 { deblock_hor(buf, 0, q, coff + 8); }
426 off += 16;
427 }
428 let mut leftt = false;
429 let mut leftc = false;
430 let mut off = buf.get_offset(0) + mb_y * 16 * stride;
431 for mb_x in 0..mb_w {
432 let ctop0 = cbpi.is_coded_top(mb_x, 0);
433 let ctop1 = cbpi.is_coded_top(mb_x, 0);
434 let ccur0 = cbpi.is_coded(mb_x, 0);
435 let ccur1 = cbpi.is_coded(mb_x, 1);
436 let q = cbpi.get_q(mb_w + mb_x);
437 if mb_y != 0 {
438 let coff = off - 8 * stride;
439 let qtop = cbpi.get_q(mb_x);
440 if leftt && ctop0 { deblock_ver(buf, 0, qtop, coff); }
441 if ctop0 && ctop1 { deblock_ver(buf, 0, qtop, coff + 8); }
442 }
443 if leftc && ccur0 { deblock_ver(buf, 0, q, off); }
444 if ccur0 && ccur1 { deblock_ver(buf, 0, q, off + 8); }
445 leftt = ctop1;
446 leftc = ccur1;
447 off += 16;
448 }
449 let strideu = buf.get_stride(1);
450 let stridev = buf.get_stride(2);
451 let offu = buf.get_offset(1) + mb_y * 8 * strideu;
452 let offv = buf.get_offset(2) + mb_y * 8 * stridev;
453 if mb_y != 0 {
454 for mb_x in 0..mb_w {
455 let ctu = cbpi.is_coded_top(mb_x, 4);
456 let ccu = cbpi.is_coded(mb_x, 4);
457 let ctv = cbpi.is_coded_top(mb_x, 5);
458 let ccv = cbpi.is_coded(mb_x, 5);
459 let q = cbpi.get_q(mb_w + mb_x);
460 if ctu && ccu { deblock_hor(buf, 1, q, offu + mb_x * 8); }
461 if ctv && ccv { deblock_hor(buf, 2, q, offv + mb_x * 8); }
462 }
463 let mut leftu = false;
464 let mut leftv = false;
465 let offu = buf.get_offset(1) + (mb_y - 1) * 8 * strideu;
466 let offv = buf.get_offset(2) + (mb_y - 1) * 8 * stridev;
467 for mb_x in 0..mb_w {
468 let ctu = cbpi.is_coded_top(mb_x, 4);
469 let ctv = cbpi.is_coded_top(mb_x, 5);
470 let qt = cbpi.get_q(mb_x);
471 if leftu && ctu { deblock_ver(buf, 1, qt, offu + mb_x * 8); }
472 if leftv && ctv { deblock_ver(buf, 2, qt, offv + mb_x * 8); }
473 leftu = ctu;
474 leftv = ctv;
475 }
476 }
477}
478
479impl BlockDSP for H263BlockDSP {
480 fn idct(&self, blk: &mut [i16; 64]) {
481 h263_idct(blk)
482 }
483 fn copy_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) {
484 let srcx = ((mv.x >> 1) as isize) + (xpos as isize);
485 let srcy = ((mv.y >> 1) as isize) + (ypos as isize);
486 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
487
488 blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_FUNCS);
489 }
490 fn avg_blocks(&self, dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) {
491 let srcx = ((mv.x >> 1) as isize) + (xpos as isize);
492 let srcy = ((mv.y >> 1) as isize) + (ypos as isize);
493 let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
494
495 blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_AVG_FUNCS);
496 }
497 fn filter_row(&self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
498 h263_filter_row(buf, mb_y, mb_w, cbpi)
499 }
500}