fix clippy warnings
[nihav.git] / nihav-indeo / src / codecs / indeo3enc / cell.rs
CommitLineData
77c25c7b
KS
1use super::CB_SELECTORS;
2use super::mv::MV;
3use super::super::indeo3data::*;
4use super::{Indeo3Cell, Plane};
5
6pub const MAX_CELL_SIZE: usize = 2400;
7const DEFAULT_PIXEL: u8 = 0x40;
8const INTRA_FLAT_THRESHOLD: u32 = 8;
9const INTER_FLAT_THRESHOLD: u32 = 8;
10
11struct IndexWriter<'a> {
12 dst: &'a mut [u8],
13 pos: usize,
14 do_rle: bool,
15}
16
17const SKIP_CELL: u8 = 0xFD;
18const ZERO_CELL: u8 = 0xFD;
19
20impl<'a> IndexWriter<'a> {
21 fn new(dst: &'a mut [u8], do_rle: bool) -> Self {
22 Self {
23 dst,
24 pos: 0,
25 do_rle,
26 }
27 }
28 fn write_pair(&mut self, idx0: u8, idx1: u8, quad_radix: u8, esc: u8) {
29 //xxx: in theory one in theory the other index just has to make output fit byte range
30 if idx0 < quad_radix && idx1 < quad_radix {
31 let quad = idx1 * quad_radix + idx0 + esc;
32 self.dst[self.pos] = quad;
33 self.pos += 1;
34 } else {
35 self.dst[self.pos] = idx0;
36 self.pos += 1;
37 self.dst[self.pos] = idx1;
38 self.pos += 1;
39 }
40 }
41 fn write_byte(&mut self, val: u8) {
42 self.dst[self.pos] = val;
43 self.pos += 1;
44 }
45 fn compact_cell(&mut self, esc_vals: [u8; 4]) {
46 if !self.do_rle {
47 return;
48 }
49 let tail = &self.dst[self.pos - 4..][..4];
50 let mut count = 0;
51 for (&a, &b) in tail.iter().zip(esc_vals.iter()).rev() {
52 if a != b {
53 break;
54 }
55 count += 1;
56 }
57 if count > 1 {
58 self.pos -= count;
59 self.dst[self.pos] = ZERO_CELL;
60 self.pos += 1;
61 }
62 }
63 fn compact_all_cells(&mut self) {
64 if !self.do_rle {
65 return;
66 }
67 if self.pos > 2 {
68 let mut i = 0;
69 while i + 2 < self.pos {
70 if self.dst[i] == ZERO_CELL && self.dst[i + 1] == ZERO_CELL {
71 let mut last_idx = i;
72 for j in (i + 1)..self.pos {
73 if self.dst[j] != ZERO_CELL {
74 break;
75 }
76 last_idx = j;
77 }
78 let len = (last_idx - i + 1).min(31);
79 if len == 2 {
80 self.dst[i] = 0xFC;
81 move_tail(&mut self.dst[i + 1..self.pos], 1);
82 self.pos -= 1;
83 } else {
84 self.dst[i] = 0xFB;
85 self.dst[i + 1] = len as u8;
86 move_tail(&mut self.dst[i + 2..self.pos], len - 2);
87 self.pos -= len - 2;
88 }
89 }
90 i += 1;
91 }
92 }
93 }
94 fn end(self) -> usize {
95 self.pos
96 }
97}
98
99fn move_tail(buf: &mut [u8], off: usize) {
100 let len = buf.len();
101 for i in off..len {
102 buf[i - off] = buf[i];
103 }
104}
105
106#[derive(Default)]
107struct CodebookSuggester {
108 count: [u16; 16],
109}
110
111const BINNING_FACTORS: [u8; 16] = [3, 7, 9, 12, 14, 16, 18, 40, 2, 3, 4, 5, 6, 7, 8, 9];
112
113impl CodebookSuggester {
114 fn new() -> Self { Self::default() }
115 fn merge(cs1: &Self, cs2: &Self) -> Self {
116 let mut count = [0; 16];
117 for (dst, (&src1, &src2)) in count.iter_mut().zip(cs1.count.iter().zip(cs2.count.iter())) {
118 *dst = src1 + src2;
119 }
120 Self { count }
121 }
122 fn add_delta(&mut self, delta: u8) {
123 for (i, &fac) in BINNING_FACTORS.iter().enumerate() {
124 let val = if i < 8 { delta + fac - 1 } else { delta };
125 if (val % fac) == 0 {
126 self.count[i] += 1;
127 }
128 }
129 }
130 fn add_line(&mut self, src: &[i8]) {
131 for &delta in src.iter() {
132 if delta == 0 {
133 continue;
134 }
e6aaad5c 135 let delta = delta.unsigned_abs();
77c25c7b
KS
136 self.add_delta(delta);
137 }
138 }
139 fn add_line_half(&mut self, src: &[i8]) {
140 for &delta in src.iter().step_by(2) {
141 if delta == 0 {
142 continue;
143 }
e6aaad5c 144 let delta = delta.unsigned_abs();
77c25c7b
KS
145 self.add_delta(delta);
146 }
147 }
148 fn get_best(&self) -> u8 {
149 let mut idx = 0;
150 for (i, &cnt) in self.count.iter().enumerate().skip(1) {
151 if cnt > self.count[idx] {
152 idx = i;
153 }
154 }
155 idx as u8
156 }
157}
158
159pub struct CellEncoder {
160 buf: [u8; MAX_CELL_SIZE + 160],
161 rbuf: [u8; MAX_CELL_SIZE + 160],
162 deltas: [i8; MAX_CELL_SIZE],
163 cell: Indeo3Cell,
164 pub out: [u8; MAX_CELL_SIZE / 2 + 1],
165 pub osize: usize,
166
167 pub flat_thr_i: u32,
168 pub flat_thr_p: u32,
169 pub do_rle: bool,
170 pub quant: Option<u8>,
171}
172
173impl CellEncoder {
174 pub fn new() -> Self {
175 Self {
176 buf: [0; MAX_CELL_SIZE + 160],
177 rbuf: [0; MAX_CELL_SIZE + 160],
178 deltas: [0; MAX_CELL_SIZE],
3ff976b2 179 cell: Indeo3Cell::new(0, 0),
77c25c7b
KS
180 out: [0; MAX_CELL_SIZE / 2 + 1],
181 osize: 0,
182
183 flat_thr_i: INTRA_FLAT_THRESHOLD,
184 flat_thr_p: INTER_FLAT_THRESHOLD,
185 do_rle: true,
186 quant: None,
187 }
188 }
189 pub fn read_buffer(&mut self, plane: &Plane, cell: Indeo3Cell) {
190 self.cell = cell;
191
192 let src = &plane.data[cell.get_x() + cell.get_y() * plane.width..];
193 let dst_w = cell.get_width();
194 for (dline, sline) in self.buf.chunks_mut(dst_w).skip(1).zip(src.chunks(plane.width)).take(cell.get_height()) {
195 dline.copy_from_slice(&sline[..dst_w]);
196 }
197 if cell.get_y() > 0 {
198 self.buf[..dst_w].copy_from_slice(&plane.data[cell.get_x() + (cell.get_y() - 1) * plane.width..][..dst_w]);
199 } else {
200 for el in self.buf[..dst_w].iter_mut() {
201 *el = DEFAULT_PIXEL;
202 }
203 }
204 }
205 pub fn read_mv_buffer(&mut self, plane: &Plane, cell: Indeo3Cell, mv: MV) {
206 self.cell = cell;
207
208 let xoff = (cell.get_x() as isize + isize::from(mv.x)) as usize;
209 let yoff = (cell.get_y() as isize + isize::from(mv.y)) as usize;
210 let src = &plane.data[xoff + yoff * plane.width..];
211 let dst_w = cell.get_width();
212 for (dline, sline) in self.rbuf.chunks_mut(dst_w).skip(1).zip(src.chunks(plane.width)).take(cell.get_height()) {
213 dline.copy_from_slice(&sline[..dst_w]);
214 }
215 }
216 pub fn null_mv(&mut self) {
217 let stride = self.cell.get_width();
218 self.buf[stride..].copy_from_slice(&self.rbuf[stride..]);
219 }
220 pub fn gen_diffs_intra(&mut self) {
221 let stride = self.cell.get_width();
222 let mut start = stride;
223 for dline in self.deltas.chunks_mut(stride).take(self.cell.get_height()) {
224 let (pprev, cur) = self.buf.split_at(start);
225 let prev = &pprev[pprev.len() - stride..];
226
227 for (dst, (&cur, &top)) in dline.iter_mut().zip(cur.iter().zip(prev.iter())) {
228 *dst = (cur as i8) - (top as i8);
229 }
230
231 start += stride;
232 }
233 }
234 pub fn gen_diffs_inter(&mut self) {
235 let stride = self.cell.get_width();
236 let prev_iter = self.rbuf.chunks(stride).skip(1);
237 let cur_iter = self.buf.chunks(stride).skip(1);
238 for (dline, (cur, prev)) in self.deltas.chunks_mut(stride).take(self.cell.get_height()).zip(cur_iter.zip(prev_iter)) {
239 for (dst, (&cur, &prev)) in dline.iter_mut().zip(cur.iter().zip(prev.iter())) {
240 *dst = (cur as i8) - (prev as i8);
241 }
242 }
243 }
244 pub fn put_buffer(&self, plane: &mut Plane) {
245 let to_skip = if !self.cell.is_intra() || self.cell.get_y() == 0 { 1 } else { 0 };
246
247 let dst = &mut plane.data[self.cell.get_x() + (self.cell.get_y() + to_skip - 1) * plane.width..];
248 let src_w = self.cell.get_width();
249 for (sline, dline) in self.buf.chunks(src_w).skip(to_skip).zip(dst.chunks_mut(plane.width)).take(self.cell.get_height() + 1 - to_skip) {
250 dline[..src_w].copy_from_slice(sline);
251 }
252 }
253 fn determine_mode(&self, intra: bool, mut mode_hint: u8) -> (u8, [u8; 2]) {
254 if let Some(qmode) = self.quant {
255 if intra {
e6aaad5c 256 return (mode_hint, [qmode, qmode]);
77c25c7b 257 } else {
e6aaad5c 258 let qmode = qmode & 7;
77c25c7b
KS
259 return (mode_hint, [qmode, qmode]);
260 }
261 }
262
263 let stride = self.cell.get_width();
264
265 let mut cb_p = CodebookSuggester::new();
266 let mut cb_s = CodebookSuggester::new();
267 if !intra && (self.cell.get_height() & 7 == 0) {
268 let mut vdiff = 0;
269 let mut hdiff = 0;
270 for line_pair in self.deltas.chunks(stride * 2).take(self.cell.get_height() / 2) {
271 let (line1, line2) = line_pair.split_at(stride);
272 for (&el1, &el2) in line1.iter().zip(line2.iter()) {
273 let diff = i32::from(el1) - i32::from(el2);
274 vdiff += (diff * diff) as u32;
275 }
276 }
277 for line in self.deltas.chunks(stride).take(self.cell.get_height()) {
278 for pair in line.chunks(2) {
279 let diff = i32::from(pair[1]) - i32::from(pair[0]);
280 hdiff += (diff * diff) as u32;
281 }
282 }
283 vdiff /= (self.cell.get_width() * self.cell.get_height() / 2) as u32;
284 hdiff /= (self.cell.get_width() * self.cell.get_height() / 2) as u32;
285
286 mode_hint = match ((vdiff > self.flat_thr_p), (hdiff > self.flat_thr_p)) {
287 (false, false) if (self.cell.get_width() & 7) == 0 => 10,
288 (false, _) => 11,
289 _ => 0,
290 };
291 }
292 match mode_hint {
293 0 => {
294 for line_pair in self.deltas.chunks(stride * 2).take(self.cell.get_height() / 2) {
295 let (line1, line2) = line_pair.split_at(stride);
296 cb_p.add_line(line1);
297 cb_s.add_line(line2);
298 }
299 },
300 3 => {
301 for line_quad in self.deltas.chunks(stride * 4).take(self.cell.get_height() / 4) {
302 let (line01, line23) = line_quad.split_at(stride * 2);
303 let (_line0, line1) = line01.split_at(stride);
304 let (_line2, line3) = line23.split_at(stride);
305 cb_p.add_line(line1);
306 cb_s.add_line(line3);
307 }
308 },
309 10 => {
310 for line_quad in self.deltas.chunks(stride * 4).take(self.cell.get_height() / 4) {
311 let (line01, line23) = line_quad.split_at(stride * 2);
312 let (_line0, line1) = line01.split_at(stride);
313 let (_line2, line3) = line23.split_at(stride);
314 cb_p.add_line_half(line1);
315 cb_s.add_line_half(line3);
316 }
317 },
318 11 => {
319 for line_quad in self.deltas.chunks(stride * 4).take(self.cell.get_height() / 4) {
320 let (line01, line23) = line_quad.split_at(stride * 2);
321 let (_line0, line1) = line01.split_at(stride);
322 let (_line2, line3) = line23.split_at(stride);
323 cb_p.add_line(line1);
324 cb_s.add_line(line3);
325 }
326 },
327 _ => unreachable!(),
328 };
329 let cb_f = CodebookSuggester::merge(&cb_p, &cb_s).get_best();
330 let cb_p = cb_p.get_best();
331 let mut cb_s = cb_s.get_best();
332
333 let mut use_single = !intra || mode_hint == 10 || cb_p == cb_s;
334 if !use_single {
335 if cb_s == 0 { // we can adjust to the CB_SELECTORS here
336 cb_s = (((cb_p & 7) + 1) * 2).min(15);
337 }
338 let ncb = (cb_p << 4) + cb_s;
339 use_single = !CB_SELECTORS.contains(&ncb);
340 }
341
342 if use_single {
343 if intra || cb_f < 8 { // we don't want requant happening in inter mode
344 (mode_hint, [cb_f, cb_f])
345 } else {
346 (mode_hint, [0, 0])
347 }
348 } else {
349 (mode_hint + 1, [cb_p, cb_s])
350 }
351 }
352 pub fn compress_intra(&mut self, mode_hint: u8) {
353 let (mode, vq_idx) = self.determine_mode(true, mode_hint);
354
355 let cb_no1 = usize::from(vq_idx[1]);
356 let cb_no2 = usize::from(vq_idx[0]);
357 let cb1 = IVI3_DELTA_CBS[cb_no1];
358 let cb2 = IVI3_DELTA_CBS[cb_no2];
359
360 let mut requant_idx = None;
361 if (mode == 1) || (mode == 4) {
362 let aq_idx = (vq_idx[0] << 4) | vq_idx[1];
363 let mut idx = 42;
364 for (i, &el) in CB_SELECTORS.iter().enumerate() {
365 if el == aq_idx {
366 idx = i;
367 break;
368 }
369 }
370 self.out[0] = (mode << 4) | (idx as u8);
77c25c7b
KS
371 } else {
372 self.out[0] = (mode << 4) | (cb_no1 as u8);
373
374 if (8..=15).contains(&cb_no1) {
375 requant_idx = Some(cb_no1 - 8);
376 }
377 }
a6627cc2 378 if self.cell.get_y() == 0 || !matches!(mode, 0 | 3 | 10) {
77c25c7b
KS
379 requant_idx = None;
380 }
381
382 let start = 1;
383 let mut iwriter = IndexWriter::new(&mut self.out[start..], self.do_rle);
384
385 let esc_val1 = (cb1.data.len() / 2) as u8;
386 let esc_val2 = (cb2.data.len() / 2) as u8;
387
388 let cbs = [cb1, cb2, cb1, cb2];
389 let esc_vals = [esc_val1, esc_val2, esc_val1, esc_val2];
390
391 let mut first_line = self.cell.get_y() == 0;
392 let stride = self.cell.get_width();
393
394 if let Some(ridx) = requant_idx {// && !first_line {
395 requant(&mut self.buf[..stride], ridx);
396 }
397
398 let mut cell4 = [0; 20];
399 match mode {
400 0 | 1 | 2 => {
401 for y in (0..self.cell.get_height()).step_by(4) {
402 for x in (0..self.cell.get_width()).step_by(4) {
403 Self::get_cell4(&self.buf, x, y, stride, &mut cell4);
404 // first check if the cell can be coded with zero predictor
405 let mut diff = 0;
406 let mut pivot = 4;
407 for _y in 0..4 {
408 let (top, cur) = cell4.split_at(pivot);
409 let top = &top[top.len() - 4..];
410 for (&tval, &cval) in top.iter().zip(cur.iter()) {
411 let cdiff = i32::from(tval) - i32::from(cval);
412 diff += cdiff * cdiff;
413 }
414 pivot += 4;
415 }
416 if (diff as u32) < self.flat_thr_i {
417 iwriter.write_byte(ZERO_CELL);
418 let (top, tail) = cell4.split_at_mut(4);
419 for dline in tail.chunks_mut(4) {
420 dline.copy_from_slice(top);
421 }
422 Self::put_cell4(&mut self.buf, x, y, stride, &cell4);
423 continue;
424 }
425
426 compress_intra_cell(&mut iwriter, &mut cell4, &cbs, esc_vals);
427 Self::put_cell4(&mut self.buf, x, y, stride, &cell4);
428 }
429 }
430 },
431 3 | 4 => {
432 for y in (0..self.cell.get_height()).step_by(8) {
433 for x in (0..self.cell.get_width()).step_by(4) {
434 Self::get_cell_mode3(&self.buf, x, y, stride, &mut cell4);
435 compress_intra_cell(&mut iwriter, &mut cell4, &cbs, esc_vals);
436 Self::put_cell_mode3(&mut self.buf, x, y, stride, &cell4, first_line);
437 }
438 first_line = false;
439 }
440 },
441 10 => {
442 for y in (0..self.cell.get_height()).step_by(8) {
443 for x in (0..self.cell.get_width()).step_by(8) {
444 Self::get_cell_mode10i(&self.buf, x, y, stride, &mut cell4);
445 compress_intra_cell(&mut iwriter, &mut cell4, &cbs, esc_vals);
446 Self::put_cell_mode10i(&mut self.buf, x, y, stride, &cell4, first_line);
447 }
448 first_line = false;
449 }
450 },
451 _ => unreachable!(),
452 };
453 iwriter.compact_all_cells();
454
455 self.osize = iwriter.end() + start;
456 }
457 pub fn compress_inter(&mut self) {
458 let (mode, vq_idx) = self.determine_mode(false, 0);
459
460 let cb_no1 = usize::from(vq_idx[1]);
461 let cb_no2 = usize::from(vq_idx[0]);
462 let cb1 = IVI3_DELTA_CBS[cb_no1];
463 let cb2 = IVI3_DELTA_CBS[cb_no2];
464
465 if (mode == 1) || (mode == 4) {
466 let aq_idx = (vq_idx[0] << 4) | vq_idx[1];
467 let mut idx = 42;
468 for (i, &el) in CB_SELECTORS.iter().enumerate() {
469 if el == aq_idx {
470 idx = i;
471 break;
472 }
473 }
474 self.out[0] = (mode << 4) | (idx as u8);
475 } else {
476 self.out[0] = (mode << 4) | (cb_no1 as u8);
477 }
478 let start = 1;
479 let mut iwriter = IndexWriter::new(&mut self.out[start..], self.do_rle);
480
481 let esc_val1 = (cb1.data.len() / 2) as u8;
482 let esc_val2 = (cb2.data.len() / 2) as u8;
483
484 let cbs = [cb1, cb2, cb1, cb2];
485 let esc_vals = [esc_val1, esc_val2, esc_val1, esc_val2];
486
487
488 let stride = self.cell.get_width();
489 let mut ccell4 = [0; 20];
490 let mut pcell4 = [0; 20];
491 match mode {
492 0 | 1 | 2 => {
493 for y in (0..self.cell.get_height()).step_by(4) {
494 for x in (0..self.cell.get_width()).step_by(4) {
495 Self::get_cell4(&self.buf, x, y, stride, &mut ccell4);
496 Self::get_cell4(&self.rbuf, x, y, stride, &mut pcell4);
497 // first check if the cell can be coded with zero predictor
498 let mut diff = 0;
499 for (&pval, &cval) in pcell4[4..].iter().zip(ccell4[4..].iter()) {
500 let cdiff = i32::from(pval) - i32::from(cval);
501 diff += cdiff * cdiff;
502 }
503 if diff < 8 {
504 iwriter.write_byte(SKIP_CELL);
505 Self::put_cell4(&mut self.buf, x, y, stride, &pcell4);
506 continue;
507 }
508
509 compress_inter_cell(&mut iwriter, &mut ccell4, &pcell4, &cbs, esc_vals);
510 Self::put_cell4(&mut self.buf, x, y, stride, &ccell4);
511 }
512 }
513 },
514 10 => {
515 let mut offset = 0;
516 let mut ref_cell = [0; 64];
517 let mut avg_diff: [i16; 16];
518 for _y in (0..self.cell.get_height()).step_by(8) {
519 for x in (0..self.cell.get_width()).step_by(8) {
520 for (dline, sline) in ref_cell.chunks_mut(8).zip(self.rbuf[offset + stride + x..].chunks(stride)) {
521 dline.copy_from_slice(&sline[..8]);
522 }
523 avg_diff = [0; 16];
524 for j in 0..8 {
525 for i in 0..8 {
526 avg_diff[i / 2 + (j / 2) * 4] += i16::from(self.deltas[offset + x + i + j * stride]);
527 }
528 }
529 for el in avg_diff.iter_mut() {
530 *el = (*el + 2) >> 2;
531 }
532 compress_inter_cell_mode10(&mut iwriter, &mut ref_cell, &avg_diff, &cbs, esc_vals);
533 for (sline, dline) in ref_cell.chunks(8).zip(self.buf[offset + stride + x..].chunks_mut(stride)) {
534 dline[..8].copy_from_slice(sline);
535 }
536 }
537 offset += stride * 8;
538 }
539 },
540 11 => {
541 let mut offset = 0;
542 let mut ref_cell = [0; 32];
543 let mut avg_diff: [i16; 16];
544 for _y in (0..self.cell.get_height()).step_by(8) {
545 for x in (0..self.cell.get_width()).step_by(4) {
546 for (dline, sline) in ref_cell.chunks_mut(4).zip(self.rbuf[offset + stride + x..].chunks(stride)) {
547 dline.copy_from_slice(&sline[..4]);
548 }
549 avg_diff = [0; 16];
550 for j in 0..8 {
551 for i in 0..4 {
552 avg_diff[i + (j / 2) * 4] += i16::from(self.deltas[offset + x + i + j * stride]);
553 }
554 }
555 for el in avg_diff.iter_mut() {
556 *el = (*el + 1) >> 1;
557 }
558
559 compress_inter_cell_mode11(&mut iwriter, &mut ref_cell, &avg_diff, &cbs, esc_vals);
560 for (sline, dline) in ref_cell.chunks(4).zip(self.buf[offset + stride + x..].chunks_mut(stride)) {
561 dline[..4].copy_from_slice(sline);
562 }
563 }
564 offset += stride * 8;
565 }
566 },
567 _ => unreachable!(),
568 };
569 iwriter.compact_all_cells();
570
571 self.osize = iwriter.end() + start;
572 }
573
574 fn get_cell4(data: &[u8], x: usize, y: usize, stride: usize, cell: &mut [u8; 20]) {
575 for (dst, src) in cell.chunks_mut(4).zip(data[x + y * stride..].chunks(stride)) {
576 dst.copy_from_slice(&src[..4]);
577 }
578 }
579 fn put_cell4(data: &mut [u8], x: usize, y: usize, stride: usize, cell: &[u8; 20]) {
580 for (src, dst) in cell.chunks(4).zip(data[x + y * stride..].chunks_mut(stride)).skip(1) {
581 dst[..4].copy_from_slice(src);
582 }
583 }
584 fn get_cell_mode3(data: &[u8], x: usize, y: usize, stride: usize, cell: &mut [u8; 20]) {
585 let src = &data[x + y * stride..];
586 for (dline, slines) in cell.chunks_mut(4).zip(src.chunks(stride * 2)) {
587 dline.copy_from_slice(&slines[..4]);
588 }
589 }
590 fn put_cell_mode3(data: &mut [u8], x: usize, y: usize, stride: usize, cell: &[u8; 20], first_line: bool) {
591 let dst = &mut data[x + y * stride..];
592 let mut dst_idx = stride;
593 for line in 0..4 {
594 for x in 0..4 {
595 let top = cell[line * 4 + x];
596 let cur = cell[(line + 1) * 4 + x];
597 dst[dst_idx + x] = (top + cur) >> 1;
598 dst[dst_idx + stride + x] = cur;
599 }
600 dst_idx += stride * 2;
601 }
602 if first_line {
603 dst[stride..][..4].copy_from_slice(&cell[4..8]);
604 }
605 }
606 fn get_cell_mode10i(data: &[u8], x: usize, y: usize, stride: usize, cell: &mut [u8; 20]) {
607 let src = &data[x + y * stride..];
608 for (dline, src_pair) in cell.chunks_mut(4).zip(src.chunks(stride * 2)) {
609 for (dst, src) in dline.iter_mut().zip(src_pair.chunks(2)) {
610 *dst = src[0];
611 }
612 }
613 }
614 fn put_cell_mode10i(data: &mut [u8], x: usize, y: usize, stride: usize, cell: &[u8; 20], first_line: bool) {
615 let dst = &mut data[x + y * stride..];
616 let mut dst_idx = stride;
617 for line in 0..4 {
f5c61879
KS
618 for x in 0..8 {
619 let top = dst[dst_idx - stride + x];
620 let cur = cell[(line + 1) * 4 + x / 2];
621 dst[dst_idx + x] = (top + cur) >> 1;
622 dst[dst_idx + stride + x] = cur;
77c25c7b
KS
623 }
624 dst_idx += stride * 2;
625 }
626 if first_line {
627 let (top, tail) = dst[stride..].split_at_mut(stride);
628 top[..8].copy_from_slice(&tail[..8]);
629 }
630 }
631}
632
633fn requant(line: &mut [u8], rq_index: usize) {
634 let tab = &REQUANT_TAB[rq_index];
635 for el in line.iter_mut() {
636 *el = tab[usize::from(*el)];
637 }
638}
639
640fn compress_intra_cell(iwriter: &mut IndexWriter, cell4: &mut [u8; 20], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
641 let mut pivot = 4;
642 for y in 0..4 {
643 let cb = cbs[y];
644 let esc_val = esc_vals[y];
645
646 let (prev, cur) = cell4.split_at_mut(pivot);
647 let prev = &prev[prev.len() - 4..];
648 let cur = &mut cur[..4];
e6aaad5c 649 let (idx0, idx1) = find_quad(cb.data, prev, cur);
77c25c7b
KS
650
651 cur[0] = ((prev[0] as i8) + cb.data[usize::from(idx1) * 2]) as u8;
652 cur[1] = ((prev[1] as i8) + cb.data[usize::from(idx1) * 2 + 1]) as u8;
653 cur[2] = ((prev[2] as i8) + cb.data[usize::from(idx0) * 2]) as u8;
654 cur[3] = ((prev[3] as i8) + cb.data[usize::from(idx0) * 2 + 1]) as u8;
655
656 iwriter.write_pair(idx0, idx1, cb.quad_radix, esc_val);
657
658 pivot += 4;
659 }
660 iwriter.compact_cell(esc_vals);
661}
662
663fn compress_inter_cell(iwriter: &mut IndexWriter, ccell4: &mut [u8; 20], pcell: &[u8; 20], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
664 for (y, (prev, cur)) in pcell[4..].chunks(4).zip(ccell4[4..].chunks_mut(4)).enumerate() {
665 let cb = cbs[y];
666 let esc_val = esc_vals[y];
667
e6aaad5c 668 let (idx0, idx1) = find_quad(cb.data, prev, cur);
77c25c7b
KS
669
670 cur[0] = ((prev[0] as i8) + cb.data[usize::from(idx1) * 2]) as u8;
671 cur[1] = ((prev[1] as i8) + cb.data[usize::from(idx1) * 2 + 1]) as u8;
672 cur[2] = ((prev[2] as i8) + cb.data[usize::from(idx0) * 2]) as u8;
673 cur[3] = ((prev[3] as i8) + cb.data[usize::from(idx0) * 2 + 1]) as u8;
674
675 iwriter.write_pair(idx0, idx1, cb.quad_radix, esc_val);
676 }
677 iwriter.compact_cell(esc_vals);
678}
679
680fn compress_inter_cell_mode10(iwriter: &mut IndexWriter, cell: &mut [u8; 64], diffs: &[i16; 16], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
681 for y in 0..4 {
682 let cb = cbs[y];
683 let esc_val = esc_vals[y];
684 let mut indices = [0, 0];
685 for pair_no in (0..4).step_by(2) {
686 let src_idx = y * 8 * 2 + pair_no * 2;
687 let src0 = [cell[src_idx], cell[src_idx + 1], cell[src_idx + 8], cell[src_idx + 9]];
688 let src1 = [cell[src_idx + 2], cell[src_idx + 3], cell[src_idx + 10], cell[src_idx + 11]];
689
690 let cur_diff = [diffs[y * 4 + pair_no] as i8, diffs[y * 4 + pair_no + 1] as i8];
691
692 let mut best_idx = 0;
693 let mut best_dist = pair_dist(&cur_diff, &[0, 0]);
694 for (idx, cbpair) in cb.data.chunks(2).enumerate().skip(1) {
695 let dist = pair_dist(&cur_diff, cbpair);
696 if dist < best_dist {
697 let mut fits = true;
698 for &el in src0.iter() {
699 if !in_range(el as i8, cbpair[0]) {
700 fits = false;
701 break;
702 }
703 }
704 for &el in src1.iter() {
705 if !in_range(el as i8, cbpair[1]) {
706 fits = false;
707 break;
708 }
709 }
710 if fits {
711 best_dist = dist;
712 best_idx = idx;
713 }
714 }
715 }
716
717 indices[pair_no / 2] = best_idx as u8;
718
719 let cb_pair = &cb.data[best_idx * 2..];
720 for row in cell[src_idx..].chunks_mut(8).take(2) {
721 row[0] = ((row[0] as i8) + cb_pair[0]) as u8;
722 row[1] = ((row[1] as i8) + cb_pair[0]) as u8;
723 row[2] = ((row[2] as i8) + cb_pair[1]) as u8;
724 row[3] = ((row[3] as i8) + cb_pair[1]) as u8;
725 }
726 }
727 iwriter.write_pair(indices[1], indices[0], cb.quad_radix, esc_val);
728 }
729 iwriter.compact_cell(esc_vals);
730}
731
732fn compress_inter_cell_mode11(iwriter: &mut IndexWriter, cell: &mut [u8; 32], diffs: &[i16; 16], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
733 for y in 0..4 {
734 let cb = cbs[y];
735 let esc_val = esc_vals[y];
736 let mut indices = [0, 0];
737 for pair_no in (0..4).step_by(2) {
738 let src_idx = y * 4 * 2 + pair_no;
739 let src0 = [cell[src_idx], cell[src_idx + 4]];
740 let src1 = [cell[src_idx + 1], cell[src_idx + 5]];
741
742 let cur_diff = [diffs[y * 4 + pair_no] as i8, diffs[y * 4 + pair_no + 1] as i8];
743
744 let mut best_idx = 0;
745 let mut best_dist = pair_dist(&cur_diff, &[0, 0]);
746 for (idx, cbpair) in cb.data.chunks(2).enumerate().skip(1) {
747 let dist = pair_dist(&cur_diff, cbpair);
748 if dist < best_dist {
749 let mut fits = true;
750 for &el in src0.iter() {
751 if !in_range(el as i8, cbpair[0]) {
752 fits = false;
753 break;
754 }
755 }
756 for &el in src1.iter() {
757 if !in_range(el as i8, cbpair[1]) {
758 fits = false;
759 break;
760 }
761 }
762 if fits {
763 best_dist = dist;
764 best_idx = idx;
765 }
766 }
767 }
768
769 indices[pair_no / 2] = best_idx as u8;
770
771 let cb_pair = &cb.data[best_idx * 2..];
772 cell[src_idx] = ((cell[src_idx] as i8) + cb_pair[0]) as u8;
773 cell[src_idx + 4] = ((cell[src_idx + 4] as i8) + cb_pair[0]) as u8;
774 cell[src_idx + 1] = ((cell[src_idx + 1] as i8) + cb_pair[1]) as u8;
775 cell[src_idx + 5] = ((cell[src_idx + 5] as i8) + cb_pair[1]) as u8;
776 }
777 iwriter.write_pair(indices[1], indices[0], cb.quad_radix, esc_val);
778 }
779 iwriter.compact_cell(esc_vals);
780}
781
782fn pair_dist(src: &[i8], pair: &[i8]) -> u32 {
e6aaad5c
KS
783 let d0 = (i32::from(src[0]) - i32::from(pair[0])).unsigned_abs();
784 let d1 = (i32::from(src[1]) - i32::from(pair[1])).unsigned_abs();
77c25c7b
KS
785 d0 * d0 + d1 * d1
786}
787
788fn in_range(base: i8, delta: i8) -> bool {
789 if let Some(val) = base.checked_add(delta) {
790 val >= 0
791 } else {
792 false
793 }
794}
795
796fn find_pair(cb_data: &[i8], ppair: &[u8], cpair: &[u8]) -> u8 {
797 let ppair = [ppair[0] as i8, ppair[1] as i8];
798 let diff = [(cpair[0] as i8) - ppair[0], (cpair[1] as i8) - ppair[1]];
799 // pair 0 is always zero;
800 if diff == [0, 0] {
801 return 0;
802 }
803 let mut best_idx = 0;
804 let mut best_dist = pair_dist(&diff, &[0, 0]);
805 for (idx, cbpair) in cb_data.chunks(2).enumerate().skip(1) {
806 let dist = pair_dist(&diff, cbpair);
807 if dist < best_dist && in_range(ppair[0], cbpair[0]) && in_range(ppair[1], cbpair[1]) {
808 best_dist = dist;
809 best_idx = idx;
810 }
811 }
812 best_idx as u8
813}
814
815fn find_quad(cb_data: &[i8], prev: &[u8], cur: &[u8]) -> (u8, u8) {
816 let (ppair1, ppair0) = prev.split_at(2);
817 let (cpair1, cpair0) = cur.split_at(2);
818 let idx1 = find_pair(cb_data, ppair1, cpair1);
819 let idx0 = find_pair(cb_data, ppair0, cpair0);
820 (idx0, idx1)
821}
822
823const REQUANT_TAB: [[u8; 128]; 8] = [
824 [
825 0x00, 0x02, 0x02, 0x04, 0x04, 0x06, 0x06, 0x08,
826 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0e, 0x0e, 0x10,
827 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, 0x18,
828 0x18, 0x1a, 0x1a, 0x1c, 0x1c, 0x1e, 0x1e, 0x20,
829 0x20, 0x22, 0x22, 0x24, 0x24, 0x26, 0x26, 0x28,
830 0x28, 0x2a, 0x2a, 0x2c, 0x2c, 0x2e, 0x2e, 0x30,
831 0x30, 0x32, 0x32, 0x34, 0x34, 0x36, 0x36, 0x38,
832 0x38, 0x3a, 0x3a, 0x3c, 0x3c, 0x3e, 0x3e, 0x40,
833 0x40, 0x42, 0x42, 0x44, 0x44, 0x46, 0x46, 0x48,
834 0x48, 0x4a, 0x4a, 0x4c, 0x4c, 0x4e, 0x4e, 0x50,
835 0x50, 0x52, 0x52, 0x54, 0x54, 0x56, 0x56, 0x58,
836 0x58, 0x5a, 0x5a, 0x5c, 0x5c, 0x5e, 0x5e, 0x60,
837 0x60, 0x62, 0x62, 0x64, 0x64, 0x66, 0x66, 0x68,
838 0x68, 0x6a, 0x6a, 0x6c, 0x6c, 0x6e, 0x6e, 0x70,
839 0x70, 0x72, 0x72, 0x74, 0x74, 0x76, 0x76, 0x78,
840 0x78, 0x7a, 0x7a, 0x7c, 0x7c, 0x7e, 0x7e, 0x7e
841 ], [
842 0x01, 0x01, 0x04, 0x04, 0x04, 0x07, 0x07, 0x0a,
843 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, 0x10, 0x10,
844 0x10, 0x13, 0x13, 0x13, 0x16, 0x16, 0x16, 0x19,
845 0x19, 0x19, 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f,
846 0x22, 0x22, 0x22, 0x25, 0x25, 0x25, 0x28, 0x28,
847 0x28, 0x2b, 0x2b, 0x2b, 0x2e, 0x2e, 0x2e, 0x31,
848 0x31, 0x31, 0x34, 0x34, 0x34, 0x37, 0x37, 0x37,
849 0x3a, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x40, 0x40,
850 0x40, 0x43, 0x43, 0x43, 0x46, 0x46, 0x46, 0x49,
851 0x49, 0x49, 0x4c, 0x4c, 0x4c, 0x4f, 0x4f, 0x4f,
852 0x52, 0x52, 0x52, 0x55, 0x55, 0x55, 0x58, 0x58,
853 0x58, 0x5b, 0x5b, 0x5b, 0x5e, 0x5e, 0x5e, 0x61,
854 0x61, 0x61, 0x64, 0x64, 0x64, 0x67, 0x67, 0x67,
855 0x6a, 0x6a, 0x6a, 0x6d, 0x6d, 0x6d, 0x70, 0x70,
856 0x70, 0x73, 0x73, 0x73, 0x76, 0x76, 0x76, 0x76,
857 0x76, 0x79, 0x7c, 0x7c, 0x7c, 0x7f, 0x7f, 0x7f
858 ], [
859 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
860 0x08, 0x08, 0x0c, 0x0c, 0x0c, 0x0c, 0x10, 0x10,
861 0x10, 0x10, 0x14, 0x14, 0x14, 0x14, 0x18, 0x18,
862 0x18, 0x18, 0x1c, 0x1c, 0x1c, 0x1c, 0x20, 0x20,
863 0x20, 0x20, 0x24, 0x24, 0x24, 0x24, 0x28, 0x28,
864 0x28, 0x28, 0x2c, 0x2c, 0x2c, 0x2c, 0x30, 0x30,
865 0x30, 0x30, 0x34, 0x34, 0x34, 0x34, 0x38, 0x38,
866 0x38, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x40, 0x40,
867 0x40, 0x40, 0x44, 0x44, 0x44, 0x44, 0x48, 0x48,
868 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x50, 0x50,
869 0x50, 0x50, 0x54, 0x54, 0x54, 0x54, 0x58, 0x58,
870 0x58, 0x58, 0x5c, 0x5c, 0x5c, 0x5c, 0x60, 0x60,
871 0x60, 0x60, 0x64, 0x64, 0x64, 0x64, 0x68, 0x68,
872 0x68, 0x68, 0x6c, 0x6c, 0x6c, 0x6c, 0x70, 0x70,
873 0x70, 0x70, 0x74, 0x74, 0x74, 0x74, 0x78, 0x78,
874 0x78, 0x78, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
875 ], [
876 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
877 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e,
878 0x0e, 0x0e, 0x13, 0x13, 0x13, 0x13, 0x13, 0x18,
879 0x18, 0x18, 0x18, 0x18, 0x1d, 0x1d, 0x1d, 0x1d,
880 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x27,
881 0x27, 0x27, 0x27, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
882 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36,
883 0x36, 0x36, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x40,
884 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x45, 0x45,
885 0x45, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4f,
886 0x4f, 0x4f, 0x4f, 0x54, 0x54, 0x54, 0x54, 0x54,
887 0x59, 0x59, 0x59, 0x59, 0x59, 0x5e, 0x5e, 0x5e,
888 0x5e, 0x5e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x68,
889 0x68, 0x68, 0x68, 0x68, 0x6d, 0x6d, 0x6d, 0x6d,
890 0x6d, 0x72, 0x72, 0x72, 0x72, 0x72, 0x77, 0x77,
891 0x77, 0x77, 0x77, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
892 ], [
893 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
894 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x10,
895 0x10, 0x10, 0x10, 0x10, 0x10, 0x16, 0x16, 0x16,
896 0x16, 0x16, 0x16, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
897 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x28,
898 0x28, 0x28, 0x28, 0x28, 0x28, 0x2e, 0x2e, 0x2e,
899 0x2e, 0x2e, 0x2e, 0x34, 0x34, 0x34, 0x34, 0x34,
900 0x34, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x40,
901 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x46,
902 0x46, 0x46, 0x46, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
903 0x4c, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x58,
904 0x58, 0x58, 0x58, 0x58, 0x58, 0x5e, 0x5e, 0x5e,
905 0x5e, 0x5e, 0x5e, 0x64, 0x64, 0x64, 0x64, 0x64,
906 0x64, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x70,
907 0x70, 0x70, 0x70, 0x70, 0x70, 0x76, 0x76, 0x76,
908 0x76, 0x76, 0x76, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
909 ], [
910 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08,
911 0x08, 0x08, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
912 0x0f, 0x0f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
913 0x16, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
914 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x2b,
915 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x32, 0x32,
916 0x32, 0x32, 0x32, 0x32, 0x32, 0x39, 0x39, 0x39,
917 0x39, 0x39, 0x39, 0x39, 0x40, 0x40, 0x40, 0x40,
918 0x40, 0x40, 0x40, 0x47, 0x47, 0x47, 0x47, 0x47,
919 0x47, 0x47, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
920 0x4e, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
921 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x63,
922 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6a, 0x6a,
923 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x71, 0x71, 0x71,
924 0x71, 0x71, 0x71, 0x71, 0x78, 0x78, 0x78, 0x78,
925 0x78, 0x78, 0x78, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
926 ], [
927 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
928 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10,
929 0x10, 0x10, 0x10, 0x10, 0x18, 0x18, 0x18, 0x18,
930 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x20, 0x20,
931 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28,
932 0x28, 0x28, 0x28, 0x28, 0x30, 0x30, 0x30, 0x30,
933 0x30, 0x30, 0x30, 0x30, 0x38, 0x38, 0x38, 0x38,
934 0x38, 0x38, 0x38, 0x38, 0x40, 0x40, 0x40, 0x40,
935 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x48, 0x48,
936 0x48, 0x48, 0x48, 0x48, 0x50, 0x50, 0x50, 0x50,
937 0x50, 0x50, 0x50, 0x50, 0x58, 0x58, 0x58, 0x58,
938 0x58, 0x58, 0x58, 0x58, 0x60, 0x60, 0x60, 0x60,
939 0x60, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x68,
940 0x68, 0x68, 0x68, 0x68, 0x70, 0x70, 0x70, 0x70,
941 0x70, 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78,
942 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78
943 ], [
944 0x01, 0x01, 0x01, 0x01, 0x01, 0x0a, 0x0a, 0x0a,
945 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x13, 0x13,
946 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1c,
947 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
948 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
949 0x25, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
950 0x2e, 0x2e, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
951 0x37, 0x37, 0x37, 0x40, 0x40, 0x40, 0x40, 0x40,
952 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x49, 0x49,
953 0x49, 0x49, 0x49, 0x49, 0x49, 0x52, 0x52, 0x52,
954 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x5b, 0x5b,
955 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x64,
956 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
957 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
958 0x6d, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
959 0x76, 0x76, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
960 ]
961];