]> git.nihav.org Git - nihav.git/blob - nihav-indeo/src/codecs/indeo3enc/cell.rs
910418974159e156605e478f6ff01fd9ab76b13f
[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),
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..8 {
623 let top = dst[dst_idx - stride + x];
624 let cur = cell[(line + 1) * 4 + x / 2];
625 dst[dst_idx + x] = (top + cur) >> 1;
626 dst[dst_idx + stride + x] = cur;
627 }
628 dst_idx += stride * 2;
629 }
630 if first_line {
631 let (top, tail) = dst[stride..].split_at_mut(stride);
632 top[..8].copy_from_slice(&tail[..8]);
633 }
634 }
635 }
636
637 fn requant(line: &mut [u8], rq_index: usize) {
638 let tab = &REQUANT_TAB[rq_index];
639 for el in line.iter_mut() {
640 *el = tab[usize::from(*el)];
641 }
642 }
643
644 fn compress_intra_cell(iwriter: &mut IndexWriter, cell4: &mut [u8; 20], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
645 let mut pivot = 4;
646 for y in 0..4 {
647 let cb = cbs[y];
648 let esc_val = esc_vals[y];
649
650 let (prev, cur) = cell4.split_at_mut(pivot);
651 let prev = &prev[prev.len() - 4..];
652 let cur = &mut cur[..4];
653 let (idx0, idx1) = find_quad(&cb.data, prev, cur);
654
655 cur[0] = ((prev[0] as i8) + cb.data[usize::from(idx1) * 2]) as u8;
656 cur[1] = ((prev[1] as i8) + cb.data[usize::from(idx1) * 2 + 1]) as u8;
657 cur[2] = ((prev[2] as i8) + cb.data[usize::from(idx0) * 2]) as u8;
658 cur[3] = ((prev[3] as i8) + cb.data[usize::from(idx0) * 2 + 1]) as u8;
659
660 iwriter.write_pair(idx0, idx1, cb.quad_radix, esc_val);
661
662 pivot += 4;
663 }
664 iwriter.compact_cell(esc_vals);
665 }
666
667 fn compress_inter_cell(iwriter: &mut IndexWriter, ccell4: &mut [u8; 20], pcell: &[u8; 20], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
668 for (y, (prev, cur)) in pcell[4..].chunks(4).zip(ccell4[4..].chunks_mut(4)).enumerate() {
669 let cb = cbs[y];
670 let esc_val = esc_vals[y];
671
672 let (idx0, idx1) = find_quad(&cb.data, prev, cur);
673
674 cur[0] = ((prev[0] as i8) + cb.data[usize::from(idx1) * 2]) as u8;
675 cur[1] = ((prev[1] as i8) + cb.data[usize::from(idx1) * 2 + 1]) as u8;
676 cur[2] = ((prev[2] as i8) + cb.data[usize::from(idx0) * 2]) as u8;
677 cur[3] = ((prev[3] as i8) + cb.data[usize::from(idx0) * 2 + 1]) as u8;
678
679 iwriter.write_pair(idx0, idx1, cb.quad_radix, esc_val);
680 }
681 iwriter.compact_cell(esc_vals);
682 }
683
684 fn compress_inter_cell_mode10(iwriter: &mut IndexWriter, cell: &mut [u8; 64], diffs: &[i16; 16], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
685 for y in 0..4 {
686 let cb = cbs[y];
687 let esc_val = esc_vals[y];
688 let mut indices = [0, 0];
689 for pair_no in (0..4).step_by(2) {
690 let src_idx = y * 8 * 2 + pair_no * 2;
691 let src0 = [cell[src_idx], cell[src_idx + 1], cell[src_idx + 8], cell[src_idx + 9]];
692 let src1 = [cell[src_idx + 2], cell[src_idx + 3], cell[src_idx + 10], cell[src_idx + 11]];
693
694 let cur_diff = [diffs[y * 4 + pair_no] as i8, diffs[y * 4 + pair_no + 1] as i8];
695
696 let mut best_idx = 0;
697 let mut best_dist = pair_dist(&cur_diff, &[0, 0]);
698 for (idx, cbpair) in cb.data.chunks(2).enumerate().skip(1) {
699 let dist = pair_dist(&cur_diff, cbpair);
700 if dist < best_dist {
701 let mut fits = true;
702 for &el in src0.iter() {
703 if !in_range(el as i8, cbpair[0]) {
704 fits = false;
705 break;
706 }
707 }
708 for &el in src1.iter() {
709 if !in_range(el as i8, cbpair[1]) {
710 fits = false;
711 break;
712 }
713 }
714 if fits {
715 best_dist = dist;
716 best_idx = idx;
717 }
718 }
719 }
720
721 indices[pair_no / 2] = best_idx as u8;
722
723 let cb_pair = &cb.data[best_idx * 2..];
724 for row in cell[src_idx..].chunks_mut(8).take(2) {
725 row[0] = ((row[0] as i8) + cb_pair[0]) as u8;
726 row[1] = ((row[1] as i8) + cb_pair[0]) as u8;
727 row[2] = ((row[2] as i8) + cb_pair[1]) as u8;
728 row[3] = ((row[3] as i8) + cb_pair[1]) as u8;
729 }
730 }
731 iwriter.write_pair(indices[1], indices[0], cb.quad_radix, esc_val);
732 }
733 iwriter.compact_cell(esc_vals);
734 }
735
736 fn compress_inter_cell_mode11(iwriter: &mut IndexWriter, cell: &mut [u8; 32], diffs: &[i16; 16], cbs: &[&IviDeltaCB; 4], esc_vals: [u8; 4]) {
737 for y in 0..4 {
738 let cb = cbs[y];
739 let esc_val = esc_vals[y];
740 let mut indices = [0, 0];
741 for pair_no in (0..4).step_by(2) {
742 let src_idx = y * 4 * 2 + pair_no;
743 let src0 = [cell[src_idx], cell[src_idx + 4]];
744 let src1 = [cell[src_idx + 1], cell[src_idx + 5]];
745
746 let cur_diff = [diffs[y * 4 + pair_no] as i8, diffs[y * 4 + pair_no + 1] as i8];
747
748 let mut best_idx = 0;
749 let mut best_dist = pair_dist(&cur_diff, &[0, 0]);
750 for (idx, cbpair) in cb.data.chunks(2).enumerate().skip(1) {
751 let dist = pair_dist(&cur_diff, cbpair);
752 if dist < best_dist {
753 let mut fits = true;
754 for &el in src0.iter() {
755 if !in_range(el as i8, cbpair[0]) {
756 fits = false;
757 break;
758 }
759 }
760 for &el in src1.iter() {
761 if !in_range(el as i8, cbpair[1]) {
762 fits = false;
763 break;
764 }
765 }
766 if fits {
767 best_dist = dist;
768 best_idx = idx;
769 }
770 }
771 }
772
773 indices[pair_no / 2] = best_idx as u8;
774
775 let cb_pair = &cb.data[best_idx * 2..];
776 cell[src_idx] = ((cell[src_idx] as i8) + cb_pair[0]) as u8;
777 cell[src_idx + 4] = ((cell[src_idx + 4] as i8) + cb_pair[0]) as u8;
778 cell[src_idx + 1] = ((cell[src_idx + 1] as i8) + cb_pair[1]) as u8;
779 cell[src_idx + 5] = ((cell[src_idx + 5] as i8) + cb_pair[1]) as u8;
780 }
781 iwriter.write_pair(indices[1], indices[0], cb.quad_radix, esc_val);
782 }
783 iwriter.compact_cell(esc_vals);
784 }
785
786 fn pair_dist(src: &[i8], pair: &[i8]) -> u32 {
787 let d0 = (i32::from(src[0]) - i32::from(pair[0])).abs() as u32;
788 let d1 = (i32::from(src[1]) - i32::from(pair[1])).abs() as u32;
789 d0 * d0 + d1 * d1
790 }
791
792 fn in_range(base: i8, delta: i8) -> bool {
793 if let Some(val) = base.checked_add(delta) {
794 val >= 0
795 } else {
796 false
797 }
798 }
799
800 fn find_pair(cb_data: &[i8], ppair: &[u8], cpair: &[u8]) -> u8 {
801 let ppair = [ppair[0] as i8, ppair[1] as i8];
802 let diff = [(cpair[0] as i8) - ppair[0], (cpair[1] as i8) - ppair[1]];
803 // pair 0 is always zero;
804 if diff == [0, 0] {
805 return 0;
806 }
807 let mut best_idx = 0;
808 let mut best_dist = pair_dist(&diff, &[0, 0]);
809 for (idx, cbpair) in cb_data.chunks(2).enumerate().skip(1) {
810 let dist = pair_dist(&diff, cbpair);
811 if dist < best_dist && in_range(ppair[0], cbpair[0]) && in_range(ppair[1], cbpair[1]) {
812 best_dist = dist;
813 best_idx = idx;
814 }
815 }
816 best_idx as u8
817 }
818
819 fn find_quad(cb_data: &[i8], prev: &[u8], cur: &[u8]) -> (u8, u8) {
820 let (ppair1, ppair0) = prev.split_at(2);
821 let (cpair1, cpair0) = cur.split_at(2);
822 let idx1 = find_pair(cb_data, ppair1, cpair1);
823 let idx0 = find_pair(cb_data, ppair0, cpair0);
824 (idx0, idx1)
825 }
826
827 const REQUANT_TAB: [[u8; 128]; 8] = [
828 [
829 0x00, 0x02, 0x02, 0x04, 0x04, 0x06, 0x06, 0x08,
830 0x08, 0x0a, 0x0a, 0x0c, 0x0c, 0x0e, 0x0e, 0x10,
831 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, 0x18,
832 0x18, 0x1a, 0x1a, 0x1c, 0x1c, 0x1e, 0x1e, 0x20,
833 0x20, 0x22, 0x22, 0x24, 0x24, 0x26, 0x26, 0x28,
834 0x28, 0x2a, 0x2a, 0x2c, 0x2c, 0x2e, 0x2e, 0x30,
835 0x30, 0x32, 0x32, 0x34, 0x34, 0x36, 0x36, 0x38,
836 0x38, 0x3a, 0x3a, 0x3c, 0x3c, 0x3e, 0x3e, 0x40,
837 0x40, 0x42, 0x42, 0x44, 0x44, 0x46, 0x46, 0x48,
838 0x48, 0x4a, 0x4a, 0x4c, 0x4c, 0x4e, 0x4e, 0x50,
839 0x50, 0x52, 0x52, 0x54, 0x54, 0x56, 0x56, 0x58,
840 0x58, 0x5a, 0x5a, 0x5c, 0x5c, 0x5e, 0x5e, 0x60,
841 0x60, 0x62, 0x62, 0x64, 0x64, 0x66, 0x66, 0x68,
842 0x68, 0x6a, 0x6a, 0x6c, 0x6c, 0x6e, 0x6e, 0x70,
843 0x70, 0x72, 0x72, 0x74, 0x74, 0x76, 0x76, 0x78,
844 0x78, 0x7a, 0x7a, 0x7c, 0x7c, 0x7e, 0x7e, 0x7e
845 ], [
846 0x01, 0x01, 0x04, 0x04, 0x04, 0x07, 0x07, 0x0a,
847 0x0a, 0x0a, 0x0a, 0x0d, 0x0d, 0x0d, 0x10, 0x10,
848 0x10, 0x13, 0x13, 0x13, 0x16, 0x16, 0x16, 0x19,
849 0x19, 0x19, 0x1c, 0x1c, 0x1c, 0x1f, 0x1f, 0x1f,
850 0x22, 0x22, 0x22, 0x25, 0x25, 0x25, 0x28, 0x28,
851 0x28, 0x2b, 0x2b, 0x2b, 0x2e, 0x2e, 0x2e, 0x31,
852 0x31, 0x31, 0x34, 0x34, 0x34, 0x37, 0x37, 0x37,
853 0x3a, 0x3a, 0x3a, 0x3d, 0x3d, 0x3d, 0x40, 0x40,
854 0x40, 0x43, 0x43, 0x43, 0x46, 0x46, 0x46, 0x49,
855 0x49, 0x49, 0x4c, 0x4c, 0x4c, 0x4f, 0x4f, 0x4f,
856 0x52, 0x52, 0x52, 0x55, 0x55, 0x55, 0x58, 0x58,
857 0x58, 0x5b, 0x5b, 0x5b, 0x5e, 0x5e, 0x5e, 0x61,
858 0x61, 0x61, 0x64, 0x64, 0x64, 0x67, 0x67, 0x67,
859 0x6a, 0x6a, 0x6a, 0x6d, 0x6d, 0x6d, 0x70, 0x70,
860 0x70, 0x73, 0x73, 0x73, 0x76, 0x76, 0x76, 0x76,
861 0x76, 0x79, 0x7c, 0x7c, 0x7c, 0x7f, 0x7f, 0x7f
862 ], [
863 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
864 0x08, 0x08, 0x0c, 0x0c, 0x0c, 0x0c, 0x10, 0x10,
865 0x10, 0x10, 0x14, 0x14, 0x14, 0x14, 0x18, 0x18,
866 0x18, 0x18, 0x1c, 0x1c, 0x1c, 0x1c, 0x20, 0x20,
867 0x20, 0x20, 0x24, 0x24, 0x24, 0x24, 0x28, 0x28,
868 0x28, 0x28, 0x2c, 0x2c, 0x2c, 0x2c, 0x30, 0x30,
869 0x30, 0x30, 0x34, 0x34, 0x34, 0x34, 0x38, 0x38,
870 0x38, 0x38, 0x3c, 0x3c, 0x3c, 0x3c, 0x40, 0x40,
871 0x40, 0x40, 0x44, 0x44, 0x44, 0x44, 0x48, 0x48,
872 0x48, 0x48, 0x4c, 0x4c, 0x4c, 0x4c, 0x50, 0x50,
873 0x50, 0x50, 0x54, 0x54, 0x54, 0x54, 0x58, 0x58,
874 0x58, 0x58, 0x5c, 0x5c, 0x5c, 0x5c, 0x60, 0x60,
875 0x60, 0x60, 0x64, 0x64, 0x64, 0x64, 0x68, 0x68,
876 0x68, 0x68, 0x6c, 0x6c, 0x6c, 0x6c, 0x70, 0x70,
877 0x70, 0x70, 0x74, 0x74, 0x74, 0x74, 0x78, 0x78,
878 0x78, 0x78, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
879 ], [
880 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
881 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e,
882 0x0e, 0x0e, 0x13, 0x13, 0x13, 0x13, 0x13, 0x18,
883 0x18, 0x18, 0x18, 0x18, 0x1d, 0x1d, 0x1d, 0x1d,
884 0x1d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x27, 0x27,
885 0x27, 0x27, 0x27, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c,
886 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36,
887 0x36, 0x36, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x40,
888 0x40, 0x40, 0x40, 0x40, 0x45, 0x45, 0x45, 0x45,
889 0x45, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4f, 0x4f,
890 0x4f, 0x4f, 0x4f, 0x54, 0x54, 0x54, 0x54, 0x54,
891 0x59, 0x59, 0x59, 0x59, 0x59, 0x5e, 0x5e, 0x5e,
892 0x5e, 0x5e, 0x63, 0x63, 0x63, 0x63, 0x63, 0x68,
893 0x68, 0x68, 0x68, 0x68, 0x6d, 0x6d, 0x6d, 0x6d,
894 0x6d, 0x72, 0x72, 0x72, 0x72, 0x72, 0x77, 0x77,
895 0x77, 0x77, 0x77, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
896 ], [
897 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
898 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x10,
899 0x10, 0x10, 0x10, 0x10, 0x10, 0x16, 0x16, 0x16,
900 0x16, 0x16, 0x16, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
901 0x1c, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x28,
902 0x28, 0x28, 0x28, 0x28, 0x28, 0x2e, 0x2e, 0x2e,
903 0x2e, 0x2e, 0x2e, 0x34, 0x34, 0x34, 0x34, 0x34,
904 0x34, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x40,
905 0x40, 0x40, 0x40, 0x40, 0x40, 0x46, 0x46, 0x46,
906 0x46, 0x46, 0x46, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c,
907 0x4c, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x58,
908 0x58, 0x58, 0x58, 0x58, 0x58, 0x5e, 0x5e, 0x5e,
909 0x5e, 0x5e, 0x5e, 0x64, 0x64, 0x64, 0x64, 0x64,
910 0x64, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x70,
911 0x70, 0x70, 0x70, 0x70, 0x70, 0x76, 0x76, 0x76,
912 0x76, 0x76, 0x76, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c
913 ], [
914 0x01, 0x01, 0x01, 0x01, 0x08, 0x08, 0x08, 0x08,
915 0x08, 0x08, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
916 0x0f, 0x0f, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16,
917 0x16, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
918 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x2b,
919 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x32, 0x32,
920 0x32, 0x32, 0x32, 0x32, 0x32, 0x39, 0x39, 0x39,
921 0x39, 0x39, 0x39, 0x39, 0x40, 0x40, 0x40, 0x40,
922 0x40, 0x40, 0x40, 0x47, 0x47, 0x47, 0x47, 0x47,
923 0x47, 0x47, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
924 0x4e, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
925 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x63,
926 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x6a, 0x6a,
927 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x71, 0x71, 0x71,
928 0x71, 0x71, 0x71, 0x71, 0x78, 0x78, 0x78, 0x78,
929 0x78, 0x78, 0x78, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
930 ], [
931 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
932 0x08, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10, 0x10,
933 0x10, 0x10, 0x10, 0x10, 0x18, 0x18, 0x18, 0x18,
934 0x18, 0x18, 0x18, 0x18, 0x20, 0x20, 0x20, 0x20,
935 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28,
936 0x28, 0x28, 0x28, 0x28, 0x30, 0x30, 0x30, 0x30,
937 0x30, 0x30, 0x30, 0x30, 0x38, 0x38, 0x38, 0x38,
938 0x38, 0x38, 0x38, 0x38, 0x40, 0x40, 0x40, 0x40,
939 0x40, 0x40, 0x40, 0x40, 0x48, 0x48, 0x48, 0x48,
940 0x48, 0x48, 0x48, 0x48, 0x50, 0x50, 0x50, 0x50,
941 0x50, 0x50, 0x50, 0x50, 0x58, 0x58, 0x58, 0x58,
942 0x58, 0x58, 0x58, 0x58, 0x60, 0x60, 0x60, 0x60,
943 0x60, 0x60, 0x60, 0x60, 0x68, 0x68, 0x68, 0x68,
944 0x68, 0x68, 0x68, 0x68, 0x70, 0x70, 0x70, 0x70,
945 0x70, 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78,
946 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78
947 ], [
948 0x01, 0x01, 0x01, 0x01, 0x01, 0x0a, 0x0a, 0x0a,
949 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x13, 0x13,
950 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x1c,
951 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
952 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
953 0x25, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e,
954 0x2e, 0x2e, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
955 0x37, 0x37, 0x37, 0x40, 0x40, 0x40, 0x40, 0x40,
956 0x40, 0x40, 0x40, 0x40, 0x49, 0x49, 0x49, 0x49,
957 0x49, 0x49, 0x49, 0x49, 0x49, 0x52, 0x52, 0x52,
958 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x5b, 0x5b,
959 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x64,
960 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
961 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d, 0x6d,
962 0x6d, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
963 0x76, 0x76, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
964 ]
965 ];