]> git.nihav.org Git - nihav.git/blob - nihav-indeo/src/codecs/indeo3enc/cell.rs
6f641eb3c87355a8f6db9f98552b5e79365463c9
[nihav.git] / nihav-indeo / src / codecs / indeo3enc / cell.rs
1 use super::CB_SELECTORS;
2 use super::mv::MV;
3 use super::super::indeo3data::*;
4 use super::{Indeo3Cell, Plane};
5
6 pub const MAX_CELL_SIZE: usize = 2400;
7 const DEFAULT_PIXEL: u8 = 0x40;
8 const INTRA_FLAT_THRESHOLD: u32 = 8;
9 const INTER_FLAT_THRESHOLD: u32 = 8;
10
11 struct IndexWriter<'a> {
12 dst: &'a mut [u8],
13 pos: usize,
14 do_rle: bool,
15 }
16
17 const SKIP_CELL: u8 = 0xFD;
18 const ZERO_CELL: u8 = 0xFD;
19
20 impl<'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
99 fn 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)]
107 struct CodebookSuggester {
108 count: [u16; 16],
109 }
110
111 const BINNING_FACTORS: [u8; 16] = [3, 7, 9, 12, 14, 16, 18, 40, 2, 3, 4, 5, 6, 7, 8, 9];
112
113 impl 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 }
135 let delta = delta.abs() as u8;
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 }
144 let delta = delta.abs() as u8;
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
159 pub 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
173 impl 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],
179 cell: Indeo3Cell::new(0, 0, false),
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 {
256 return (mode_hint, [qmode as u8, qmode as u8]);
257 } else {
258 let qmode = (qmode & 7) as u8;
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);
371
372 if idx >= 8 {
373 requant_idx = Some(idx - 8);
374 }
375 } else {
376 self.out[0] = (mode << 4) | (cb_no1 as u8);
377
378 if (8..=15).contains(&cb_no1) {
379 requant_idx = Some(cb_no1 - 8);
380 }
381 }
382 if self.cell.get_y() == 0 {
383 requant_idx = None;
384 }
385
386 let start = 1;
387 let mut iwriter = IndexWriter::new(&mut self.out[start..], self.do_rle);
388
389 let esc_val1 = (cb1.data.len() / 2) as u8;
390 let esc_val2 = (cb2.data.len() / 2) as u8;
391
392 let cbs = [cb1, cb2, cb1, cb2];
393 let esc_vals = [esc_val1, esc_val2, esc_val1, esc_val2];
394
395 let mut first_line = self.cell.get_y() == 0;
396 let stride = self.cell.get_width();
397
398 if let Some(ridx) = requant_idx {// && !first_line {
399 requant(&mut self.buf[..stride], ridx);
400 }
401
402 let mut cell4 = [0; 20];
403 match mode {
404 0 | 1 | 2 => {
405 for y in (0..self.cell.get_height()).step_by(4) {
406 for x in (0..self.cell.get_width()).step_by(4) {
407 Self::get_cell4(&self.buf, x, y, stride, &mut cell4);
408 // first check if the cell can be coded with zero predictor
409 let mut diff = 0;
410 let mut pivot = 4;
411 for _y in 0..4 {
412 let (top, cur) = cell4.split_at(pivot);
413 let top = &top[top.len() - 4..];
414 for (&tval, &cval) in top.iter().zip(cur.iter()) {
415 let cdiff = i32::from(tval) - i32::from(cval);
416 diff += cdiff * cdiff;
417 }
418 pivot += 4;
419 }
420 if (diff as u32) < self.flat_thr_i {
421 iwriter.write_byte(ZERO_CELL);
422 let (top, tail) = cell4.split_at_mut(4);
423 for dline in tail.chunks_mut(4) {
424 dline.copy_from_slice(top);
425 }
426 Self::put_cell4(&mut self.buf, x, y, stride, &cell4);
427 continue;
428 }
429
430 compress_intra_cell(&mut iwriter, &mut cell4, &cbs, esc_vals);
431 Self::put_cell4(&mut self.buf, x, y, stride, &cell4);
432 }
433 }
434 },
435 3 | 4 => {
436 for y in (0..self.cell.get_height()).step_by(8) {
437 for x in (0..self.cell.get_width()).step_by(4) {
438 Self::get_cell_mode3(&self.buf, x, y, stride, &mut cell4);
439 compress_intra_cell(&mut iwriter, &mut cell4, &cbs, esc_vals);
440 Self::put_cell_mode3(&mut self.buf, x, y, stride, &cell4, first_line);
441 }
442 first_line = false;
443 }
444 },
445 10 => {
446 for y in (0..self.cell.get_height()).step_by(8) {
447 for x in (0..self.cell.get_width()).step_by(8) {
448 Self::get_cell_mode10i(&self.buf, x, y, stride, &mut cell4);
449 compress_intra_cell(&mut iwriter, &mut cell4, &cbs, esc_vals);
450 Self::put_cell_mode10i(&mut self.buf, x, y, stride, &cell4, first_line);
451 }
452 first_line = false;
453 }
454 },
455 _ => unreachable!(),
456 };
457 iwriter.compact_all_cells();
458
459 self.osize = iwriter.end() + start;
460 }
461 pub fn compress_inter(&mut self) {
462 let (mode, vq_idx) = self.determine_mode(false, 0);
463
464 let cb_no1 = usize::from(vq_idx[1]);
465 let cb_no2 = usize::from(vq_idx[0]);
466 let cb1 = IVI3_DELTA_CBS[cb_no1];
467 let cb2 = IVI3_DELTA_CBS[cb_no2];
468
469 if (mode == 1) || (mode == 4) {
470 let aq_idx = (vq_idx[0] << 4) | vq_idx[1];
471 let mut idx = 42;
472 for (i, &el) in CB_SELECTORS.iter().enumerate() {
473 if el == aq_idx {
474 idx = i;
475 break;
476 }
477 }
478 self.out[0] = (mode << 4) | (idx as u8);
479 } else {
480 self.out[0] = (mode << 4) | (cb_no1 as u8);
481 }
482 let start = 1;
483 let mut iwriter = IndexWriter::new(&mut self.out[start..], self.do_rle);
484
485 let esc_val1 = (cb1.data.len() / 2) as u8;
486 let esc_val2 = (cb2.data.len() / 2) as u8;
487
488 let cbs = [cb1, cb2, cb1, cb2];
489 let esc_vals = [esc_val1, esc_val2, esc_val1, esc_val2];
490
491
492 let stride = self.cell.get_width();
493 let mut ccell4 = [0; 20];
494 let mut pcell4 = [0; 20];
495 match mode {
496 0 | 1 | 2 => {
497 for y in (0..self.cell.get_height()).step_by(4) {
498 for x in (0..self.cell.get_width()).step_by(4) {
499 Self::get_cell4(&self.buf, x, y, stride, &mut ccell4);
500 Self::get_cell4(&self.rbuf, x, y, stride, &mut pcell4);
501 // first check if the cell can be coded with zero predictor
502 let mut diff = 0;
503 for (&pval, &cval) in pcell4[4..].iter().zip(ccell4[4..].iter()) {
504 let cdiff = i32::from(pval) - i32::from(cval);
505 diff += cdiff * cdiff;
506 }
507 if diff < 8 {
508 iwriter.write_byte(SKIP_CELL);
509 Self::put_cell4(&mut self.buf, x, y, stride, &pcell4);
510 continue;
511 }
512
513 compress_inter_cell(&mut iwriter, &mut ccell4, &pcell4, &cbs, esc_vals);
514 Self::put_cell4(&mut self.buf, x, y, stride, &ccell4);
515 }
516 }
517 },
518 10 => {
519 let mut offset = 0;
520 let mut ref_cell = [0; 64];
521 let mut avg_diff: [i16; 16];
522 for _y in (0..self.cell.get_height()).step_by(8) {
523 for x in (0..self.cell.get_width()).step_by(8) {
524 for (dline, sline) in ref_cell.chunks_mut(8).zip(self.rbuf[offset + stride + x..].chunks(stride)) {
525 dline.copy_from_slice(&sline[..8]);
526 }
527 avg_diff = [0; 16];
528 for j in 0..8 {
529 for i in 0..8 {
530 avg_diff[i / 2 + (j / 2) * 4] += i16::from(self.deltas[offset + x + i + j * stride]);
531 }
532 }
533 for el in avg_diff.iter_mut() {
534 *el = (*el + 2) >> 2;
535 }
536 compress_inter_cell_mode10(&mut iwriter, &mut ref_cell, &avg_diff, &cbs, esc_vals);
537 for (sline, dline) in ref_cell.chunks(8).zip(self.buf[offset + stride + x..].chunks_mut(stride)) {
538 dline[..8].copy_from_slice(sline);
539 }
540 }
541 offset += stride * 8;
542 }
543 },
544 11 => {
545 let mut offset = 0;
546 let mut ref_cell = [0; 32];
547 let mut avg_diff: [i16; 16];
548 for _y in (0..self.cell.get_height()).step_by(8) {
549 for x in (0..self.cell.get_width()).step_by(4) {
550 for (dline, sline) in ref_cell.chunks_mut(4).zip(self.rbuf[offset + stride + x..].chunks(stride)) {
551 dline.copy_from_slice(&sline[..4]);
552 }
553 avg_diff = [0; 16];
554 for j in 0..8 {
555 for i in 0..4 {
556 avg_diff[i + (j / 2) * 4] += i16::from(self.deltas[offset + x + i + j * stride]);
557 }
558 }
559 for el in avg_diff.iter_mut() {
560 *el = (*el + 1) >> 1;
561 }
562
563 compress_inter_cell_mode11(&mut iwriter, &mut ref_cell, &avg_diff, &cbs, esc_vals);
564 for (sline, dline) in ref_cell.chunks(4).zip(self.buf[offset + stride + x..].chunks_mut(stride)) {
565 dline[..4].copy_from_slice(sline);
566 }
567 }
568 offset += stride * 8;
569 }
570 },
571 _ => unreachable!(),
572 };
573 iwriter.compact_all_cells();
574
575 self.osize = iwriter.end() + start;
576 }
577
578 fn get_cell4(data: &[u8], x: usize, y: usize, stride: usize, cell: &mut [u8; 20]) {
579 for (dst, src) in cell.chunks_mut(4).zip(data[x + y * stride..].chunks(stride)) {
580 dst.copy_from_slice(&src[..4]);
581 }
582 }
583 fn put_cell4(data: &mut [u8], x: usize, y: usize, stride: usize, cell: &[u8; 20]) {
584 for (src, dst) in cell.chunks(4).zip(data[x + y * stride..].chunks_mut(stride)).skip(1) {
585 dst[..4].copy_from_slice(src);
586 }
587 }
588 fn get_cell_mode3(data: &[u8], x: usize, y: usize, stride: usize, cell: &mut [u8; 20]) {
589 let src = &data[x + y * stride..];
590 for (dline, slines) in cell.chunks_mut(4).zip(src.chunks(stride * 2)) {
591 dline.copy_from_slice(&slines[..4]);
592 }
593 }
594 fn put_cell_mode3(data: &mut [u8], x: usize, y: usize, stride: usize, cell: &[u8; 20], first_line: bool) {
595 let dst = &mut data[x + y * stride..];
596 let mut dst_idx = stride;
597 for line in 0..4 {
598 for x in 0..4 {
599 let top = cell[line * 4 + x];
600 let cur = cell[(line + 1) * 4 + x];
601 dst[dst_idx + x] = (top + cur) >> 1;
602 dst[dst_idx + stride + x] = cur;
603 }
604 dst_idx += stride * 2;
605 }
606 if first_line {
607 dst[stride..][..4].copy_from_slice(&cell[4..8]);
608 }
609 }
610 fn get_cell_mode10i(data: &[u8], x: usize, y: usize, stride: usize, cell: &mut [u8; 20]) {
611 let src = &data[x + y * stride..];
612 for (dline, src_pair) in cell.chunks_mut(4).zip(src.chunks(stride * 2)) {
613 for (dst, src) in dline.iter_mut().zip(src_pair.chunks(2)) {
614 *dst = src[0];
615 }
616 }
617 }
618 fn put_cell_mode10i(data: &mut [u8], x: usize, y: usize, stride: usize, cell: &[u8; 20], first_line: bool) {
619 let dst = &mut data[x + y * stride..];
620 let mut dst_idx = stride;
621 for line in 0..4 {
622 for x in 0..4 {
623 let top = dst[dst_idx - stride + x * 2];
624 let cur = cell[(line + 1) * 4 + x];
625 dst[dst_idx + x * 2] = (top + cur) >> 1;
626 dst[dst_idx + x * 2 + 1] = (top + cur) >> 1;
627 dst[dst_idx + stride + x * 2] = cur;
628 dst[dst_idx + stride + x * 2 + 1] = cur;
629 }
630 dst_idx += stride * 2;
631 }
632 if first_line {
633 let (top, tail) = dst[stride..].split_at_mut(stride);
634 top[..8].copy_from_slice(&tail[..8]);
635 }
636 }
637 }
638
639 fn requant(line: &mut [u8], rq_index: usize) {
640 let tab = &REQUANT_TAB[rq_index];
641 for el in line.iter_mut() {
642 *el = tab[usize::from(*el)];
643 }
644 }
645
646 fn compress_intra_cell(iwriter: &mut IndexWriter, cell4: &mut [u8; 20], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
647 let mut pivot = 4;
648 for y in 0..4 {
649 let cb = cbs[y];
650 let esc_val = esc_vals[y];
651
652 let (prev, cur) = cell4.split_at_mut(pivot);
653 let prev = &prev[prev.len() - 4..];
654 let cur = &mut cur[..4];
655 let (idx0, idx1) = find_quad(&cb.data, prev, cur);
656
657 cur[0] = ((prev[0] as i8) + cb.data[usize::from(idx1) * 2]) as u8;
658 cur[1] = ((prev[1] as i8) + cb.data[usize::from(idx1) * 2 + 1]) as u8;
659 cur[2] = ((prev[2] as i8) + cb.data[usize::from(idx0) * 2]) as u8;
660 cur[3] = ((prev[3] as i8) + cb.data[usize::from(idx0) * 2 + 1]) as u8;
661
662 iwriter.write_pair(idx0, idx1, cb.quad_radix, esc_val);
663
664 pivot += 4;
665 }
666 iwriter.compact_cell(esc_vals);
667 }
668
669 fn compress_inter_cell(iwriter: &mut IndexWriter, ccell4: &mut [u8; 20], pcell: &[u8; 20], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
670 for (y, (prev, cur)) in pcell[4..].chunks(4).zip(ccell4[4..].chunks_mut(4)).enumerate() {
671 let cb = cbs[y];
672 let esc_val = esc_vals[y];
673
674 let (idx0, idx1) = find_quad(&cb.data, prev, cur);
675
676 cur[0] = ((prev[0] as i8) + cb.data[usize::from(idx1) * 2]) as u8;
677 cur[1] = ((prev[1] as i8) + cb.data[usize::from(idx1) * 2 + 1]) as u8;
678 cur[2] = ((prev[2] as i8) + cb.data[usize::from(idx0) * 2]) as u8;
679 cur[3] = ((prev[3] as i8) + cb.data[usize::from(idx0) * 2 + 1]) as u8;
680
681 iwriter.write_pair(idx0, idx1, cb.quad_radix, esc_val);
682 }
683 iwriter.compact_cell(esc_vals);
684 }
685
686 fn compress_inter_cell_mode10(iwriter: &mut IndexWriter, cell: &mut [u8; 64], diffs: &[i16; 16], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
687 for y in 0..4 {
688 let cb = cbs[y];
689 let esc_val = esc_vals[y];
690 let mut indices = [0, 0];
691 for pair_no in (0..4).step_by(2) {
692 let src_idx = y * 8 * 2 + pair_no * 2;
693 let src0 = [cell[src_idx], cell[src_idx + 1], cell[src_idx + 8], cell[src_idx + 9]];
694 let src1 = [cell[src_idx + 2], cell[src_idx + 3], cell[src_idx + 10], cell[src_idx + 11]];
695
696 let cur_diff = [diffs[y * 4 + pair_no] as i8, diffs[y * 4 + pair_no + 1] as i8];
697
698 let mut best_idx = 0;
699 let mut best_dist = pair_dist(&cur_diff, &[0, 0]);
700 for (idx, cbpair) in cb.data.chunks(2).enumerate().skip(1) {
701 let dist = pair_dist(&cur_diff, cbpair);
702 if dist < best_dist {
703 let mut fits = true;
704 for &el in src0.iter() {
705 if !in_range(el as i8, cbpair[0]) {
706 fits = false;
707 break;
708 }
709 }
710 for &el in src1.iter() {
711 if !in_range(el as i8, cbpair[1]) {
712 fits = false;
713 break;
714 }
715 }
716 if fits {
717 best_dist = dist;
718 best_idx = idx;
719 }
720 }
721 }
722
723 indices[pair_no / 2] = best_idx as u8;
724
725 let cb_pair = &cb.data[best_idx * 2..];
726 for row in cell[src_idx..].chunks_mut(8).take(2) {
727 row[0] = ((row[0] as i8) + cb_pair[0]) as u8;
728 row[1] = ((row[1] as i8) + cb_pair[0]) as u8;
729 row[2] = ((row[2] as i8) + cb_pair[1]) as u8;
730 row[3] = ((row[3] as i8) + cb_pair[1]) as u8;
731 }
732 }
733 iwriter.write_pair(indices[1], indices[0], cb.quad_radix, esc_val);
734 }
735 iwriter.compact_cell(esc_vals);
736 }
737
738 fn compress_inter_cell_mode11(iwriter: &mut IndexWriter, cell: &mut [u8; 32], diffs: &[i16; 16], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
739 for y in 0..4 {
740 let cb = cbs[y];
741 let esc_val = esc_vals[y];
742 let mut indices = [0, 0];
743 for pair_no in (0..4).step_by(2) {
744 let src_idx = y * 4 * 2 + pair_no;
745 let src0 = [cell[src_idx], cell[src_idx + 4]];
746 let src1 = [cell[src_idx + 1], cell[src_idx + 5]];
747
748 let cur_diff = [diffs[y * 4 + pair_no] as i8, diffs[y * 4 + pair_no + 1] as i8];
749
750 let mut best_idx = 0;
751 let mut best_dist = pair_dist(&cur_diff, &[0, 0]);
752 for (idx, cbpair) in cb.data.chunks(2).enumerate().skip(1) {
753 let dist = pair_dist(&cur_diff, cbpair);
754 if dist < best_dist {
755 let mut fits = true;
756 for &el in src0.iter() {
757 if !in_range(el as i8, cbpair[0]) {
758 fits = false;
759 break;
760 }
761 }
762 for &el in src1.iter() {
763 if !in_range(el as i8, cbpair[1]) {
764 fits = false;
765 break;
766 }
767 }
768 if fits {
769 best_dist = dist;
770 best_idx = idx;
771 }
772 }
773 }
774
775 indices[pair_no / 2] = best_idx as u8;
776
777 let cb_pair = &cb.data[best_idx * 2..];
778 cell[src_idx] = ((cell[src_idx] as i8) + cb_pair[0]) as u8;
779 cell[src_idx + 4] = ((cell[src_idx + 4] as i8) + cb_pair[0]) as u8;
780 cell[src_idx + 1] = ((cell[src_idx + 1] as i8) + cb_pair[1]) as u8;
781 cell[src_idx + 5] = ((cell[src_idx + 5] as i8) + cb_pair[1]) as u8;
782 }
783 iwriter.write_pair(indices[1], indices[0], cb.quad_radix, esc_val);
784 }
785 iwriter.compact_cell(esc_vals);
786 }
787
788 fn pair_dist(src: &[i8], pair: &[i8]) -> u32 {
789 let d0 = (i32::from(src[0]) - i32::from(pair[0])).abs() as u32;
790 let d1 = (i32::from(src[1]) - i32::from(pair[1])).abs() as u32;
791 d0 * d0 + d1 * d1
792 }
793
794 fn in_range(base: i8, delta: i8) -> bool {
795 if let Some(val) = base.checked_add(delta) {
796 val >= 0
797 } else {
798 false
799 }
800 }
801
802 fn find_pair(cb_data: &[i8], ppair: &[u8], cpair: &[u8]) -> u8 {
803 let ppair = [ppair[0] as i8, ppair[1] as i8];
804 let diff = [(cpair[0] as i8) - ppair[0], (cpair[1] as i8) - ppair[1]];
805 // pair 0 is always zero;
806 if diff == [0, 0] {
807 return 0;
808 }
809 let mut best_idx = 0;
810 let mut best_dist = pair_dist(&diff, &[0, 0]);
811 for (idx, cbpair) in cb_data.chunks(2).enumerate().skip(1) {
812 let dist = pair_dist(&diff, cbpair);
813 if dist < best_dist && in_range(ppair[0], cbpair[0]) && in_range(ppair[1], cbpair[1]) {
814 best_dist = dist;
815 best_idx = idx;
816 }
817 }
818 best_idx as u8
819 }
820
821 fn find_quad(cb_data: &[i8], prev: &[u8], cur: &[u8]) -> (u8, u8) {
822 let (ppair1, ppair0) = prev.split_at(2);
823 let (cpair1, cpair0) = cur.split_at(2);
824 let idx1 = find_pair(cb_data, ppair1, cpair1);
825 let idx0 = find_pair(cb_data, ppair0, cpair0);
826 (idx0, idx1)
827 }
828
829 const REQUANT_TAB: [[u8; 128]; 8] = [
830 [
831 0x00, 0x02, 0x02, 0x04, 0x04, 0x06, 0x06, 0x08,
832 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0e, 0x0e, 0x10,
833 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, 0x18,
834 0x18, 0x1a, 0x1a, 0x1c, 0x1c, 0x1e, 0x1e, 0x20,
835 0x20, 0x22, 0x22, 0x24, 0x24, 0x26, 0x26, 0x28,
836 0x28, 0x2a, 0x2a, 0x2c, 0x2c, 0x2e, 0x2e, 0x30,
837 0x30, 0x32, 0x32, 0x34, 0x34, 0x36, 0x36, 0x38,
838 0x38, 0x3a, 0x3a, 0x3c, 0x3c, 0x3e, 0x3e, 0x40,
839 0x40, 0x42, 0x42, 0x44, 0x44, 0x46, 0x46, 0x48,
840 0x48, 0x4a, 0x4a, 0x4c, 0x4c, 0x4e, 0x4e, 0x50,
841 0x50, 0x52, 0x52, 0x54, 0x54, 0x56, 0x56, 0x58,
842 0x58, 0x5a, 0x5a, 0x5c, 0x5c, 0x5e, 0x5e, 0x60,
843 0x60, 0x62, 0x62, 0x64, 0x64, 0x66, 0x66, 0x68,
844 0x68, 0x6a, 0x6a, 0x6c, 0x6c, 0x6e, 0x6e, 0x70,
845 0x70, 0x72, 0x72, 0x74, 0x74, 0x76, 0x76, 0x78,
846 0x78, 0x7a, 0x7a, 0x7c, 0x7c, 0x7e, 0x7e, 0x7e
847 ], [
848 0x01, 0x01, 0x04, 0x04, 0x04, 0x07, 0x07, 0x0a,
849 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, 0x10, 0x10,
850 0x10, 0x13, 0x13, 0x13, 0x16, 0x16, 0x16, 0x19,
851 0x19, 0x19, 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f,
852 0x22, 0x22, 0x22, 0x25, 0x25, 0x25, 0x28, 0x28,
853 0x28, 0x2b, 0x2b, 0x2b, 0x2e, 0x2e, 0x2e, 0x31,
854 0x31, 0x31, 0x34, 0x34, 0x34, 0x37, 0x37, 0x37,
855 0x3a, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x40, 0x40,
856 0x40, 0x43, 0x43, 0x43, 0x46, 0x46, 0x46, 0x49,
857 0x49, 0x49, 0x4c, 0x4c, 0x4c, 0x4f, 0x4f, 0x4f,
858 0x52, 0x52, 0x52, 0x55, 0x55, 0x55, 0x58, 0x58,
859 0x58, 0x5b, 0x5b, 0x5b, 0x5e, 0x5e, 0x5e, 0x61,
860 0x61, 0x61, 0x64, 0x64, 0x64, 0x67, 0x67, 0x67,
861 0x6a, 0x6a, 0x6a, 0x6d, 0x6d, 0x6d, 0x70, 0x70,
862 0x70, 0x73, 0x73, 0x73, 0x76, 0x76, 0x76, 0x76,
863 0x76, 0x79, 0x7c, 0x7c, 0x7c, 0x7f, 0x7f, 0x7f
864 ], [
865 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
866 0x08, 0x08, 0x0c, 0x0c, 0x0c, 0x0c, 0x10, 0x10,
867 0x10, 0x10, 0x14, 0x14, 0x14, 0x14, 0x18, 0x18,
868 0x18, 0x18, 0x1c, 0x1c, 0x1c, 0x1c, 0x20, 0x20,
869 0x20, 0x20, 0x24, 0x24, 0x24, 0x24, 0x28, 0x28,
870 0x28, 0x28, 0x2c, 0x2c, 0x2c, 0x2c, 0x30, 0x30,
871 0x30, 0x30, 0x34, 0x34, 0x34, 0x34, 0x38, 0x38,
872 0x38, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x40, 0x40,
873 0x40, 0x40, 0x44, 0x44, 0x44, 0x44, 0x48, 0x48,
874 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x50, 0x50,
875 0x50, 0x50, 0x54, 0x54, 0x54, 0x54, 0x58, 0x58,
876 0x58, 0x58, 0x5c, 0x5c, 0x5c, 0x5c, 0x60, 0x60,
877 0x60, 0x60, 0x64, 0x64, 0x64, 0x64, 0x68, 0x68,
878 0x68, 0x68, 0x6c, 0x6c, 0x6c, 0x6c, 0x70, 0x70,
879 0x70, 0x70, 0x74, 0x74, 0x74, 0x74, 0x78, 0x78,
880 0x78, 0x78, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
881 ], [
882 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
883 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e,
884 0x0e, 0x0e, 0x13, 0x13, 0x13, 0x13, 0x13, 0x18,
885 0x18, 0x18, 0x18, 0x18, 0x1d, 0x1d, 0x1d, 0x1d,
886 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x27,
887 0x27, 0x27, 0x27, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
888 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36,
889 0x36, 0x36, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x40,
890 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x45, 0x45,
891 0x45, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4f,
892 0x4f, 0x4f, 0x4f, 0x54, 0x54, 0x54, 0x54, 0x54,
893 0x59, 0x59, 0x59, 0x59, 0x59, 0x5e, 0x5e, 0x5e,
894 0x5e, 0x5e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x68,
895 0x68, 0x68, 0x68, 0x68, 0x6d, 0x6d, 0x6d, 0x6d,
896 0x6d, 0x72, 0x72, 0x72, 0x72, 0x72, 0x77, 0x77,
897 0x77, 0x77, 0x77, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
898 ], [
899 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
900 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x10,
901 0x10, 0x10, 0x10, 0x10, 0x10, 0x16, 0x16, 0x16,
902 0x16, 0x16, 0x16, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
903 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x28,
904 0x28, 0x28, 0x28, 0x28, 0x28, 0x2e, 0x2e, 0x2e,
905 0x2e, 0x2e, 0x2e, 0x34, 0x34, 0x34, 0x34, 0x34,
906 0x34, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x40,
907 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x46,
908 0x46, 0x46, 0x46, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
909 0x4c, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x58,
910 0x58, 0x58, 0x58, 0x58, 0x58, 0x5e, 0x5e, 0x5e,
911 0x5e, 0x5e, 0x5e, 0x64, 0x64, 0x64, 0x64, 0x64,
912 0x64, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x70,
913 0x70, 0x70, 0x70, 0x70, 0x70, 0x76, 0x76, 0x76,
914 0x76, 0x76, 0x76, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
915 ], [
916 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08,
917 0x08, 0x08, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
918 0x0f, 0x0f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
919 0x16, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
920 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x2b,
921 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x32, 0x32,
922 0x32, 0x32, 0x32, 0x32, 0x32, 0x39, 0x39, 0x39,
923 0x39, 0x39, 0x39, 0x39, 0x40, 0x40, 0x40, 0x40,
924 0x40, 0x40, 0x40, 0x47, 0x47, 0x47, 0x47, 0x47,
925 0x47, 0x47, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
926 0x4e, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
927 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x63,
928 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6a, 0x6a,
929 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x71, 0x71, 0x71,
930 0x71, 0x71, 0x71, 0x71, 0x78, 0x78, 0x78, 0x78,
931 0x78, 0x78, 0x78, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
932 ], [
933 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
934 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10,
935 0x10, 0x10, 0x10, 0x10, 0x18, 0x18, 0x18, 0x18,
936 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x20, 0x20,
937 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28,
938 0x28, 0x28, 0x28, 0x28, 0x30, 0x30, 0x30, 0x30,
939 0x30, 0x30, 0x30, 0x30, 0x38, 0x38, 0x38, 0x38,
940 0x38, 0x38, 0x38, 0x38, 0x40, 0x40, 0x40, 0x40,
941 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x48, 0x48,
942 0x48, 0x48, 0x48, 0x48, 0x50, 0x50, 0x50, 0x50,
943 0x50, 0x50, 0x50, 0x50, 0x58, 0x58, 0x58, 0x58,
944 0x58, 0x58, 0x58, 0x58, 0x60, 0x60, 0x60, 0x60,
945 0x60, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x68,
946 0x68, 0x68, 0x68, 0x68, 0x70, 0x70, 0x70, 0x70,
947 0x70, 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78,
948 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78
949 ], [
950 0x01, 0x01, 0x01, 0x01, 0x01, 0x0a, 0x0a, 0x0a,
951 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x13, 0x13,
952 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1c,
953 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
954 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
955 0x25, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
956 0x2e, 0x2e, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
957 0x37, 0x37, 0x37, 0x40, 0x40, 0x40, 0x40, 0x40,
958 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x49, 0x49,
959 0x49, 0x49, 0x49, 0x49, 0x49, 0x52, 0x52, 0x52,
960 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x5b, 0x5b,
961 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x64,
962 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
963 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
964 0x6d, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
965 0x76, 0x76, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
966 ]
967 ];