]> git.nihav.org Git - nihav.git/blame - nihav-indeo/src/codecs/indeo3.rs
smacker: fix version 4 support
[nihav.git] / nihav-indeo / src / codecs / indeo3.rs
CommitLineData
5641dccf
KS
1use nihav_core::formats;
2use nihav_core::codecs::*;
5641dccf 3use nihav_core::io::byteio::*;
afe29743 4use std::io::SeekFrom;
4d965fde 5use super::indeo3data::*;
afe29743 6
f614c96f
KS
7const DEFAULT_PIXEL: u8 = 0x40;
8const STRIP_WIDTH: u8 = 160;
9const FRMH_TAG: u32 = ((b'F' as u32) << 24) | ((b'R' as u32) << 16)
10 | ((b'M' as u32) << 8) | (b'H' as u32);
11
12const FLAG_8BIT: u16 = 1 << 1;
13const FLAG_KEYFRAME: u16 = 1 << 2;
14const FLAG_BUFSEL: u16 = 1 << 9;
15
16const MAX_DEPTH: u8 = 20;
17
18const H_SPLIT: u8 = 0;
19const V_SPLIT: u8 = 1;
20const ABS_FILL: u8 = 2;
21const REL_FILL: u8 = 3;
22const VQ_NULL: u8 = 2;
23const VQ_DATA: u8 = 3;
24
25type RequantTab = [[u8; 128]; 8];
26
27trait AddDelta {
28 fn add_delta(&mut self, delta: i8) -> DecoderResult<()>;
29}
30
31impl AddDelta for u8 {
32 fn add_delta(&mut self, delta: i8) -> DecoderResult<()> {
33 *self = self.wrapping_add(delta as u8);
34 validate!((*self & 0x80) == 0);
35 Ok(())
36 }
37}
38
afe29743
KS
39#[derive(Clone, Copy)]
40struct MV {
41 x: i8,
42 y: i8
43}
44
f614c96f
KS
45struct Header {
46 vq_offset: u8,
47 alt_quant: [u8; 16],
48 mvs: [MV; 256],
49 num_mvs: usize,
50 data_start: [u64; 3],
51 data_end: [u64; 3],
52 is_intra: bool,
afe29743
KS
53}
54
f614c96f
KS
55impl Header {
56 fn new() -> Self {
57 Self {
58 vq_offset: 0,
59 alt_quant: [0; 16],
60 mvs: [MV { x: 0, y: 0 }; 256],
61 num_mvs: 0,
62 data_start: [0; 3],
63 data_end: [0; 3],
64 is_intra: false,
afe29743
KS
65 }
66 }
67}
68
f614c96f
KS
69struct DataReader<'a, 'b> {
70 br: &'a mut ByteReader<'b>,
71 bpos: u8,
72 bitbuf: u8,
afe29743
KS
73}
74
f614c96f
KS
75impl<'a, 'b> DataReader<'a, 'b> {
76 fn new(br: &'a mut ByteReader<'b>) -> Self {
77 Self {
78 br,
79 bpos: 0,
80 bitbuf: 0,
81 }
afe29743 82 }
f614c96f
KS
83 fn read_2bits(&mut self) -> DecoderResult<u8> {
84 if self.bpos == 0 {
85 self.bitbuf = self.br.read_byte()?;
86 self.bpos = 8;
87 }
88 self.bpos -= 2;
89 let bits = (self.bitbuf >> self.bpos) & 3;
90 Ok(bits)
afe29743 91 }
f614c96f
KS
92 fn read_byte(&mut self) -> DecoderResult<u8> {
93 Ok(self.br.read_byte()?)
afe29743
KS
94 }
95}
96
f614c96f
KS
97#[derive(Debug, PartialEq)]
98enum Corrector {
99 Zero,
100 Skip,
101 Quad([i8; 4]),
102 Fill(u8),
103 ZeroBlock,
104 SkipBlock,
afe29743
KS
105}
106
f614c96f
KS
107impl Corrector {
108 fn is_whole_block(&self) -> bool { matches!(*self, Corrector::Fill(_) | Corrector::ZeroBlock | Corrector::SkipBlock) }
afe29743
KS
109}
110
f614c96f
KS
111struct QuadDecoder<'a, 'b, 'c> {
112 br: &'a mut DataReader<'b, 'c>,
113 cb: [&'static IviDeltaCB; 4],
114 cb_idx: [usize; 4],
115 mode: u8,
afe29743 116
f614c96f
KS
117 lines_run: u8,
118 block_run: u8,
119 skip_flag: bool,
120 next_lit: bool,
121 fill: Option<u8>,
afe29743
KS
122}
123
f614c96f
KS
124impl<'a, 'b, 'c> QuadDecoder<'a, 'b, 'c> {
125 fn new(br: &'a mut DataReader<'b, 'c>, mode: u8, cb_index: [usize; 2]) -> Self {
126 Self {
127 br, mode,
128 lines_run: 0,
129 block_run: 0,
130 skip_flag: false,
131 next_lit: false,
132 fill: None,
133 cb: [IVI3_DELTA_CBS[cb_index[0]], IVI3_DELTA_CBS[cb_index[1]],
134 IVI3_DELTA_CBS[cb_index[0]], IVI3_DELTA_CBS[cb_index[1]]],
135 cb_idx: [cb_index[0], cb_index[1], cb_index[0], cb_index[1]],
136 }
afe29743 137 }
f614c96f
KS
138 fn get_skip_corr(&self) -> Corrector {
139 if !self.skip_flag {
140 Corrector::Zero
141 } else {
142 Corrector::Skip
143 }
afe29743 144 }
f614c96f
KS
145 fn read(&mut self, line: u8) -> DecoderResult<Corrector> {
146 if let Some(fill) = self.fill {
147 self.fill = None;
148 return Ok(Corrector::Fill(fill));
149 }
150 if self.lines_run > 0 {
151 self.lines_run -= 1;
152 return Ok(self.get_skip_corr());
153 }
154 if self.block_run > 0 {
155 self.block_run -= 1;
156 let corr = if !self.skip_flag {
157 Corrector::ZeroBlock
158 } else {
159 Corrector::SkipBlock
160 };
161 return Ok(corr);
162 }
163 let mut b = self.br.read_byte()?;
164 if self.next_lit {
165 self.next_lit = false;
166 if b >= 0xF8 {
167 b = (self.cb[usize::from(line)].data.len() / 2) as u8;
168 }
169 }
afe29743 170
f614c96f
KS
171 match b {
172 0..=0xF7 => {
173 let cb = self.cb[usize::from(line)];
afe29743 174
f614c96f
KS
175 let esc_val = (cb.data.len() / 2) as u8;
176 let (idx0, idx1) = if b < esc_val {
177 let idx2 = self.br.read_byte()?;
178 validate!(idx2 < esc_val);
179 (b, idx2)
180 } else if self.cb_idx[usize::from(line)] < 16 {
181 ((b - esc_val) % cb.quad_radix, (b - esc_val) / cb.quad_radix)
182 } else {
183 ((b - esc_val) / cb.quad_radix, (b - esc_val) % cb.quad_radix)
184 };
185 let idx0 = usize::from(idx0);
186 let idx1 = usize::from(idx1);
187 Ok(Corrector::Quad([cb.data[idx1 * 2], cb.data[idx1 * 2 + 1],
188 cb.data[idx0 * 2], cb.data[idx0 * 2 + 1]]))
189 },
190 0xF8 => {
191 validate!(line == 0);
192 let fillval = self.br.read_byte()?;
193 if (fillval & 0x80) != 0 {
194 self.fill = Some(fillval & 0x7F);
195 }
196 Ok(Corrector::Fill(fillval & 0x7F))
197 },
198 0xF9 => {
199 validate!(line == 0);
200 self.skip_flag = true;
201 self.block_run = 1;
202 Ok(Corrector::SkipBlock)
203 },
204 0xFA => {
205 validate!(self.mode != 3 && self.mode != 10);
206 Ok(Corrector::SkipBlock)
207 },
208 0xFB => {
209 let b = self.br.read_byte()?;
210 validate!((b & 0x1F) > 0);
211 validate!(b < 0x40);
212 self.skip_flag = (b & 0x20) != 0;
213 self.block_run = (b & 0x1F) - 1;
214 if line > 0 {
215 self.lines_run = 3 - line;
216 Ok(self.get_skip_corr())
217 } else {
218 let corr = if !self.skip_flag {
219 Corrector::ZeroBlock
220 } else {
221 Corrector::SkipBlock
222 };
223 Ok(corr)
224 }
225 },
226 0xFC => {
227 self.block_run = 1;
228 self.skip_flag = false;
229 if line > 0 {
230 self.lines_run = 3 - line;
231 Ok(Corrector::Zero)
232 } else {
233 Ok(Corrector::ZeroBlock)
234 }
235 },
236 0xFD => {
237 self.lines_run = 3 - line;
238 self.skip_flag = false;
239 Ok(Corrector::Zero)
240 },
241 0xFE => {
242 validate!(line < 2);
243 self.lines_run = 2 - line;
244 self.skip_flag = false;
245 Ok(Corrector::Zero)
246 },
247 0xFF => {
248 validate!(line == 0);
249 self.lines_run = 1;
250 self.skip_flag = false;
251 self.next_lit = true;
252 Ok(Corrector::Zero)
253 },
254 }
255 }
afe29743
KS
256}
257
f614c96f
KS
258#[derive(Clone, Copy)]
259struct Indeo3Cell {
260 x: u8,
261 y: u8,
262 width: u8,
263 height: u8,
afe29743 264 mv: Option<MV>,
f614c96f 265 depth: u8,
afe29743
KS
266}
267
f614c96f
KS
268impl Indeo3Cell {
269 fn new(width: usize, height: usize) -> Self {
270 Self {
271 x: 0,
272 y: 0,
273 width: (width / 4) as u8,
274 height: (height / 4) as u8,
275 mv: None,
276 depth: 0,
277 }
afe29743 278 }
f614c96f
KS
279
280 fn get_x(&self) -> usize { usize::from(self.x) * 4 }
281 fn get_y(&self) -> usize { usize::from(self.y) * 4 }
282 fn get_width(&self) -> usize { usize::from(self.width) * 4 }
283 fn get_height(&self) -> usize { usize::from(self.height) * 4 }
284 fn is_intra(&self) -> bool { self.mv.is_none() }
285
afe29743 286 fn split_h(&self) -> (Self, Self) {
f614c96f
KS
287 let h1 = if self.height > 2 { ((self.height + 2) >> 2) << 1 } else { 1 };
288 let h2 = self.height - h1;
afe29743 289 let mut cell1 = *self;
f614c96f
KS
290 cell1.height = h1;
291 cell1.depth += 1;
afe29743 292 let mut cell2 = *self;
f614c96f
KS
293 cell2.y += h1;
294 cell2.height = h2;
295 cell2.depth += 1;
afe29743
KS
296 (cell1, cell2)
297 }
39cd2175 298 #[allow(clippy::collapsible_else_if)]
f614c96f
KS
299 fn split_v(&self, stripw: u8) -> (Self, Self) {
300 let w1 = if self.width > stripw {
301 if self.width > stripw * 2 { stripw * 2 } else { stripw }
afe29743 302 } else {
f614c96f 303 if self.width > 2 { ((self.width + 2) >> 2) << 1 } else { 1 }
afe29743 304 };
f614c96f 305 let w2 = self.width - w1;
afe29743 306 let mut cell1 = *self;
f614c96f
KS
307 cell1.width = w1;
308 cell1.depth += 1;
afe29743 309 let mut cell2 = *self;
f614c96f
KS
310 cell2.x += w1;
311 cell2.width = w2;
312 cell2.depth += 1;
afe29743
KS
313 (cell1, cell2)
314 }
afe29743
KS
315}
316
f614c96f
KS
317impl std::fmt::Display for Indeo3Cell {
318 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
319 let spec = if let Some(mv) = self.mv {
320 format!("mv {},{}", mv.x, mv.y)
321 } else {
322 "intra".to_owned()
323 };
324 write!(f, "[{}x{} @ {},{} {}]", self.get_width(), self.get_height(), self.get_x(), self.get_y(), spec)
325 }
afe29743
KS
326}
327
f614c96f
KS
328#[derive(Default)]
329struct Plane {
330 width: usize,
331 height: usize,
332 data: Vec<u8>,
333 stripw: u8,
334}
3bc2f5a4 335
f614c96f
KS
336impl Plane {
337 fn new(stripw: u8) -> Self {
338 Self {
339 stripw: stripw / 4,
340 ..Default::default()
341 }
342 }
343 fn alloc(&mut self, width: usize, height: usize) {
344 self.width = width;
345 self.height = height;
346 self.data.resize(width * (height + 1), 0);
347 for el in self.data[..width].iter_mut() {
348 *el = DEFAULT_PIXEL;
349 }
350 }
351 fn reset(&mut self) {
352 for el in self.data[self.width..].iter_mut() {
353 *el = 0;
354 }
355 }
356 fn output_plane(&self, dst: &mut [u8], stride: usize, is_8bit: bool) {
357 for (dline, sline) in dst.chunks_mut(stride).zip(self.data.chunks(self.width).skip(1)) {
358 if !is_8bit {
359 for (dst, &src) in dline.iter_mut().zip(sline.iter()) {
360 *dst = src << 1;
3bc2f5a4 361 }
f614c96f
KS
362 } else {
363 let size = dline.len();
364 dline.copy_from_slice(&sline[..size]);
3bc2f5a4
KS
365 }
366 }
afe29743 367 }
f614c96f
KS
368 fn checksum(&self) -> u16 {
369 let mut checksum = [0; 2];
370 for pair in self.data.chunks(2) {
371 checksum[0] ^= pair[0];
372 checksum[1] ^= pair[1];
373 }
374 read_u16le(&checksum).unwrap_or(0)
afe29743 375 }
f614c96f
KS
376 fn decode_data(&mut self, br: &mut DataReader, ref_plane: &mut Self, header: &Header, requant_tab: &RequantTab) -> DecoderResult<()> {
377 let cell = Indeo3Cell::new(self.width, self.height);
378 self.decode_mv_tree(br, ref_plane, cell, header, requant_tab)?;
379 Ok(())
380 }
381 fn decode_mv_tree(&mut self, br: &mut DataReader, ref_plane: &mut Self, cell: Indeo3Cell, header: &Header, requant_tab: &RequantTab) -> DecoderResult<()> {
382 validate!(cell.depth < MAX_DEPTH);
383 match br.read_2bits()? {
384 H_SPLIT => {
385 let (cell1, cell2) = cell.split_h();
386 self.decode_mv_tree(br, ref_plane, cell1, header, requant_tab)?;
387 self.decode_mv_tree(br, ref_plane, cell2, header, requant_tab)?;
388 },
389 V_SPLIT => {
390 let (cell1, cell2) = cell.split_v(self.stripw);
391 self.decode_mv_tree(br, ref_plane, cell1, header, requant_tab)?;
392 self.decode_mv_tree(br, ref_plane, cell2, header, requant_tab)?;
393 },
394 ABS_FILL => {
395 self.decode_vq_tree(br, ref_plane, cell, header, requant_tab)?;
396 },
397 REL_FILL => {
398 validate!(!header.is_intra);
399 let mv_idx = usize::from(br.read_byte()?);
400 validate!(mv_idx < header.num_mvs);
401 let mut sec_cell = cell;
402 sec_cell.mv = Some(header.mvs[mv_idx]);
403 self.decode_vq_tree(br, ref_plane, sec_cell, header, requant_tab)?;
404 },
405 _ => unreachable!(),
afe29743 406 }
f614c96f 407 Ok(())
afe29743 408 }
f614c96f
KS
409 fn decode_vq_tree(&mut self, br: &mut DataReader, ref_plane: &mut Self, cell: Indeo3Cell, header: &Header, requant_tab: &RequantTab) -> DecoderResult<()> {
410 validate!(cell.depth < MAX_DEPTH);
411 match br.read_2bits()? {
412 H_SPLIT => {
413 let (cell1, cell2) = cell.split_h();
414 self.decode_vq_tree(br, ref_plane, cell1, header, requant_tab)?;
415 self.decode_vq_tree(br, ref_plane, cell2, header, requant_tab)?;
416 },
417 V_SPLIT => {
418 let (cell1, cell2) = cell.split_v(self.stripw);
419 self.decode_vq_tree(br, ref_plane, cell1, header, requant_tab)?;
420 self.decode_vq_tree(br, ref_plane, cell2, header, requant_tab)?;
421 },
422 VQ_NULL => {
423 let code = br.read_2bits()?;
424 match code {
425 0 => {
426 self.copy_cell(ref_plane, cell)?;
427 },
428 1 => return Err(DecoderError::NotImplemented), // skip cell
429 _ => return Err(DecoderError::InvalidData),
430 };
431 },
432 VQ_DATA => {
433 let code = br.read_byte()?;
434 let mode = code >> 4;
435 let vq_index = code & 0xF;
436 let cb_index = if matches!(mode, 1 | 4 | 12) {
437 let aq = header.alt_quant[usize::from(vq_index)];
438 [aq & 0xF, aq >> 4]
439 } else {
440 [vq_index; 2]
441 };
442 let cb_index = [usize::from(cb_index[0] + header.vq_offset), usize::from(cb_index[1] + header.vq_offset)];
443 validate!(cb_index[0] < IVI3_DELTA_CBS.len());
444 validate!(cb_index[1] < IVI3_DELTA_CBS.len());
445 if cell.get_y() > 0 && matches!(mode, 0 | 3 | 10) && (8..=15).contains(&cb_index[0]) {
446 let src = if cell.is_intra() {
447 &mut self.data[cell.get_x() + cell.get_y() * self.width..]
448 } else {
449 &mut ref_plane.data[cell.get_x() + (cell.get_y() + 1) * ref_plane.width..]
450 };
451 let cur_requant_tab = &requant_tab[cb_index[0] - 8];
452 for el in src.iter_mut().take(cell.get_width()) {
453 *el = cur_requant_tab[usize::from(*el)];
3bc2f5a4
KS
454 }
455 }
f614c96f
KS
456
457 let qmode = if mode != 10 || cell.is_intra() { mode } else { 20 };
458 let mut quad_decoder = QuadDecoder::new(br, qmode, cb_index);
459 if !cell.is_intra() {
460 self.copy_cell(ref_plane, cell)?;
3bc2f5a4 461 }
f614c96f
KS
462 match qmode {
463 0 | 1 => {
464 self.process_cell_0_1(&mut quad_decoder, cell)?;
465 },
466 3 | 4 => {
467 validate!(cell.is_intra());
468 validate!((cell.get_height() & 7) == 0);
469 self.process_cell_3_4(&mut quad_decoder, cell)?;
470 },
471 10 => {
472 validate!((cell.get_width() & 7) == 0);
473 validate!((cell.get_height() & 7) == 0);
474 self.process_cell_10_intra(&mut quad_decoder, cell)?;
475 },
476 20 => {
477 validate!((cell.get_width() & 7) == 0);
478 validate!((cell.get_height() & 7) == 0);
479 self.process_cell_10_inter(&mut quad_decoder, cell)?;
480 },
481 11 => {
482 validate!(!cell.is_intra());
483 validate!((cell.get_height() & 7) == 0);
484 self.process_cell_11(&mut quad_decoder, cell)?;
485 },
486 2 | 12 => { return Err(DecoderError::NotImplemented)},
487 _ => return Err(DecoderError::InvalidData),
488 };
489 if matches!(qmode, 3 | 4 | 10) && cell.get_y() == 0 {
490 let line_pair = &mut self.data[cell.get_x() + (cell.get_y() + 1) * self.width..];
491 let (line0, line1) = line_pair.split_at_mut(self.width);
492 line0[..cell.get_width()].copy_from_slice(&line1[..cell.get_width()]);
493 }
494 },
495 _ => unreachable!(),
3bc2f5a4 496 }
f614c96f
KS
497 Ok(())
498 }
499 fn process_cell_0_1(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
500 let stride = self.width;
501 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
502 let cell_w = cell.get_width();
503 for _y in (0..cell.get_height()).step_by(4) {
504'block0:
505 for x in (0..cell_w).step_by(4) {
506 let top = &self.data[offset - stride + x..];
507 let mut top = [top[0], top[1], top[2], top[3]];
508 for line in 0..4 {
509 let corr = qd.read(line as u8)?;
510 if !cell.is_intra() && !corr.is_whole_block() {
511 let src = &self.data[offset + line * stride + x..];
512 top.copy_from_slice(&src[..4]);
afe29743 513 }
f614c96f
KS
514 match corr {
515 Corrector::SkipBlock => continue 'block0,
516 Corrector::Fill(fill) => {
517 for line in self.data[offset + x..].chunks_mut(stride).take(4) {
518 for el in line[..4].iter_mut() {
519 *el = fill;
afe29743
KS
520 }
521 }
f614c96f
KS
522 },
523 Corrector::ZeroBlock if cell.is_intra() => {
524 let (head, cur) = self.data.split_at_mut(offset + x);
525 let prev = &head[head.len() - stride..];
526 for dline in cur.chunks_mut(stride).take(4) {
527 dline[..4].copy_from_slice(&prev[..4]);
afe29743 528 }
f614c96f
KS
529 continue 'block0;
530 },
531 Corrector::ZeroBlock => continue 'block0,
532 Corrector::Quad(quad) => {
533 for (el, &corr) in top.iter_mut().zip(quad.iter()) {
534 el.add_delta(corr)?;
afe29743 535 }
f614c96f
KS
536 },
537 Corrector::Zero => {},
538 Corrector::Skip if cell.is_intra() => unimplemented!(),
539 Corrector::Skip => {},
540 };
541 let wback = match corr {
542 Corrector::Zero if cell.is_intra() => true,
543 Corrector::Quad(_) => true,
544 _ => false,
545 };
546 if wback {
547 self.data[offset + x + line * stride..][..4].copy_from_slice(&top);
548 }
549 }
550 }
551 offset += self.width * 4;
552 }
553 Ok(())
554 }
555 fn process_cell_3_4(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
556 let stride = self.width;
557 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
558 let cell_w = cell.get_width();
559 for _y in (0..cell.get_height()).step_by(8) {
560'block3:
561 for x in (0..cell_w).step_by(4) {
562 let top = &self.data[offset - stride + x..][..4];
563 let mut top = [top[0], top[1], top[2], top[3]];
564 for line in 0..4 {
565 let corr = qd.read(line as u8)?;
566 match corr {
567 Corrector::SkipBlock => continue 'block3,
568 Corrector::Fill(fill) => {
569 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
570 for el in line[..4].iter_mut() {
571 *el = fill;
afe29743
KS
572 }
573 }
f614c96f
KS
574 },
575 Corrector::ZeroBlock => {
576 for dline in self.data[offset + x..].chunks_mut(stride).take(8) {
577 dline[..4].copy_from_slice(&top);
afe29743 578 }
f614c96f
KS
579 continue 'block3;
580 },
581 Corrector::Quad(quad) => {
582 for (el, &corr) in top.iter_mut().zip(quad.iter()) {
583 el.add_delta(corr)?;
afe29743 584 }
f614c96f
KS
585 },
586 Corrector::Zero => {},
587 Corrector::Skip => unimplemented!(),
588 };
589
590 if corr != Corrector::Skip {
591 let dst = &mut self.data[offset + x + (line * 2 + 1) * stride..][..4];
592 dst.copy_from_slice(&top);
593 }
594 }
595
596 let mut top_off = offset + x - stride;
597 for _line in 0..4 {
598 for pos in 0..4 {
599 self.data[top_off + stride + pos] = (self.data[top_off + pos] + self.data[top_off + stride * 2 + pos]) >> 1;
600 }
601 top_off += stride * 2;
602 }
603 }
604 offset += self.width * 8;
605 }
606 Ok(())
607 }
608 fn process_cell_10_intra(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
609 let stride = self.width;
610 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
611 let cell_w = cell.get_width();
612 for _y in (0..cell.get_height()).step_by(8) {
613'block10i:
614 for x in (0..cell_w).step_by(8) {
615 let top = &self.data[offset - stride + x..][..8];
616 let mut top = [top[0], top[2], top[4], top[6]];
617 for line in 0..4 {
618 let corr = qd.read(line as u8)?;
619 match corr {
620 Corrector::SkipBlock => continue 'block10i,
621 Corrector::Fill(fill) => {
622 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
623 for el in line[..8].iter_mut() {
624 *el = fill;
afe29743
KS
625 }
626 }
f614c96f
KS
627 },
628 Corrector::ZeroBlock => {
629 let line_pair = &mut self.data[offset - stride + x..];
630 let (top_line, dst_line) = line_pair.split_at_mut(stride);
631 for (i, (dst, &top_s)) in dst_line.iter_mut()
632 .zip(top_line.iter()).take(8).enumerate() {
633 *dst = (top_s + top[i >> 1]) >> 1;
634 }
635 for dline in self.data[offset + x..].chunks_mut(stride).take(8).skip(1) {
636 for (dst, &src) in dline.chunks_mut(2).zip(top.iter()) {
637 dst[0] = src;
638 dst[1] = src;
639 }
640 }
641 continue 'block10i;
642 },
643 Corrector::Quad(quad) => {
644 for (el, &corr) in top.iter_mut().zip(quad.iter()) {
645 el.add_delta(corr)?;
646 }
647 },
648 Corrector::Zero => {},
649 Corrector::Skip => unimplemented!(),
650 };
651
652 if corr != Corrector::Skip {
653 for (dst, &prev) in self.data[offset + x + (line * 2 + 1) * stride..].chunks_mut(2).zip(top.iter()).take(4) {
654 dst[0] = prev;
655 dst[1] = prev;
afe29743
KS
656 }
657 }
658 }
f614c96f
KS
659
660 let mut top_off = offset + x - stride;
661 for _line in 0..4 {
662 for pos in 0..8 {
663 self.data[top_off + stride + pos] = (self.data[top_off + pos] + self.data[top_off + stride * 2 + pos]) >> 1;
664 }
665 top_off += stride * 2;
666 }
afe29743 667 }
f614c96f 668 offset += self.width * 8;
afe29743
KS
669 }
670 Ok(())
671 }
f614c96f
KS
672 fn process_cell_10_inter(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
673 let stride = self.width;
674 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
675 let cell_w = cell.get_width();
676 for _y in (0..cell.get_height()).step_by(8) {
677'block10p:
678 for x in (0..cell_w).step_by(8) {
679 for line in 0..4 {
680 let corr = qd.read(line as u8)?;
681 match corr {
682 Corrector::SkipBlock | Corrector::ZeroBlock => continue 'block10p,
683 Corrector::Fill(fill) => {
684 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
685 for el in line[..8].iter_mut() {
686 *el = fill;
687 }
688 }
689 },
690 Corrector::Quad(quad) => {
691 let strip = &mut self.data[offset + x + line * 2 * stride..];
692 for (xoff, &corr) in quad.iter().enumerate() {
693 strip[xoff * 2].add_delta(corr)?;
694 strip[xoff * 2 + 1].add_delta(corr)?;
695 strip[xoff * 2 + stride].add_delta(corr)?;
696 strip[xoff * 2 + stride + 1].add_delta(corr)?;
697 }
698 },
699 _ => {},
700 };
701 }
702 }
703 offset += self.width * 8;
704 }
afe29743
KS
705 Ok(())
706 }
f614c96f
KS
707 fn process_cell_11(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
708 let stride = self.width;
709 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
710 let cell_w = cell.get_width();
711 for _y in (0..cell.get_height()).step_by(8) {
712'block10p:
713 for x in (0..cell_w).step_by(4) {
714 for line in 0..4 {
715 let corr = qd.read(line as u8)?;
716 match corr {
717 Corrector::SkipBlock | Corrector::ZeroBlock => continue 'block10p,
718 Corrector::Fill(fill) => {
719 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
720 for el in line[..4].iter_mut() {
721 *el = fill;
722 }
723 }
724 },
725 Corrector::Quad(quad) => {
726 let strip = &mut self.data[offset + x + line * 2 * stride..];
727 for (xoff, &corr) in quad.iter().enumerate() {
728 strip[xoff].add_delta(corr)?;
729 strip[xoff + stride].add_delta(corr)?;
730 }
731 },
732 _ => {},
733 };
734 }
afe29743 735 }
f614c96f 736 offset += self.width * 8;
afe29743 737 }
f614c96f 738 Ok(())
afe29743 739 }
f614c96f
KS
740 fn copy_cell(&mut self, ref_plane: &Self, cell: Indeo3Cell) -> DecoderResult<()> {
741 if let Some(mv) = cell.mv {
742 let xpos = (cell.get_x() as isize) + isize::from(mv.x);
743 validate!(xpos >= 0);
744 let xpos = xpos as usize;
745 validate!(xpos + cell.get_width() <= self.width);
746 let ypos = (cell.get_y() as isize) + isize::from(mv.y);
747 validate!(ypos >= 0);
748 let ypos = ypos as usize;
749 validate!(ypos + cell.get_height() <= self.height);
750 let src = &ref_plane.data[xpos + (ypos + 1) * ref_plane.width..];
751 let dst = &mut self.data[cell.get_x() + (cell.get_y() + 1) * self.width..];
afe29743 752
f614c96f
KS
753 let width = cell.get_width();
754 let height = cell.get_height();
755 for (dline, sline) in dst.chunks_mut(ref_plane.width).zip(src.chunks(self.width)).take(height) {
756 dline[..width].copy_from_slice(&sline[..width]);
afe29743 757 }
f614c96f 758 Ok(())
afe29743 759 } else {
f614c96f 760 Err(DecoderError::InvalidData)
afe29743
KS
761 }
762 }
f614c96f 763}
afe29743 764
f614c96f
KS
765struct IV3Frame {
766 plane: [Plane; 3],
767}
afe29743 768
f614c96f
KS
769impl IV3Frame {
770 fn new() -> Self {
771 Self {
772 plane: [
773 Plane::new(STRIP_WIDTH),
774 Plane::new(STRIP_WIDTH >> 2),
775 Plane::new(STRIP_WIDTH >> 2),
776 ],
afe29743 777 }
f614c96f
KS
778 }
779 fn alloc(&mut self, width: usize, height: usize) {
780 self.plane[0].alloc( width, height);
781 let chroma_w = ((width + 15) & !15) >> 2;
782 let chroma_h = ((height + 15) & !15) >> 2;
783 self.plane[1].alloc(chroma_w, chroma_h);
784 self.plane[2].alloc(chroma_w, chroma_h);
785 }
786 fn reset(&mut self) {
787 for plane in self.plane.iter_mut() {
788 plane.reset()
789 }
790 }
791 fn decode_planes(&mut self, ref_frame: &mut IV3Frame, br: &mut ByteReader, header: &mut Header, requant_tab: &RequantTab) -> DecoderResult<()> {
792 let data_start = header.data_start;
793 let data_end = header.data_end;
794 for ((cur_plane, ref_plane), (&start, &end)) in self.plane.iter_mut()
795 .zip(ref_frame.plane.iter_mut())
796 .zip(data_start.iter().zip(data_end.iter())) {
797 br.seek(SeekFrom::Start(start))?;
798 let num_mvs = br.read_u32le()? as usize;
799 if header.is_intra {
800 validate!(num_mvs == 0);
0ddb146d 801 } else {
f614c96f
KS
802 validate!(num_mvs <= header.mvs.len());
803 }
804 header.num_mvs = num_mvs;
805 for mv in header.mvs.iter_mut().take(num_mvs) {
806 mv.y = br.read_byte()? as i8;
807 mv.x = br.read_byte()? as i8;
808 }
809 let mut reader = DataReader::new(br);
810 cur_plane.decode_data(&mut reader, ref_plane, header, requant_tab)?;
811 validate!(br.tell() <= end);
812 }
afe29743
KS
813 Ok(())
814 }
f614c96f
KS
815 fn output_frame(&self, dst: &mut NAVideoBuffer<u8>, is_8bit: bool) {
816 let dfrm = NASimpleVideoFrame::from_video_buf(dst).unwrap();
817 for (plane_no, plane) in self.plane.iter().enumerate() {
818 plane.output_plane(&mut dfrm.data[dfrm.offset[plane_no]..], dfrm.stride[plane_no], is_8bit);
819 }
820 }
821 fn checksum(&self, is_8bit: bool) -> u16 {
822 let mut checksum = 0;
823 for plane in self.plane.iter() {
824 checksum ^= plane.checksum();
825 }
826 if !is_8bit {
827 checksum <<= 1;
828 }
829 checksum
830 }
831}
832
833struct Indeo3Decoder {
834 info: NACodecInfoRef,
835 width: u16,
836 height: u16,
837 header: Header,
838 frame0: IV3Frame,
839 frame1: IV3Frame,
840 requant_tab: RequantTab,
841 do_crc: bool,
842 ign_size: bool,
843}
afe29743 844
f614c96f
KS
845impl Indeo3Decoder {
846 fn new() -> Self {
847 const REQUANT_OFF: [i32; 8] = [ 0, 1, 0, 4, 4, 1, 0, 1 ];
afe29743 848
f614c96f
KS
849 let dummy_info = NACodecInfo::new_dummy();
850
851 let mut requant_tab = [[0u8; 128]; 8];
852 for i in 0..8 {
853 let step = (i as i32) + 2;
854 let start = if (i == 3) || (i == 4) { -3 } else { step / 2 };
855 let mut last = 0;
856 for j in 0..128 {
857 requant_tab[i][j] = (((j as i32) + start) / step * step + REQUANT_OFF[i]) as u8;
858 if requant_tab[i][j] < 128 {
859 last = requant_tab[i][j];
860 } else {
861 requant_tab[i][j] = last;
862 }
863 }
afe29743 864 }
f614c96f
KS
865 requant_tab[1][7] = 10;
866 requant_tab[1][119] = 118;
867 requant_tab[1][120] = 118;
868 requant_tab[4][8] = 10;
afe29743 869
f614c96f
KS
870 Indeo3Decoder {
871 info: dummy_info,
872 width: 0,
873 height: 0,
874 header: Header::new(),
875 frame0: IV3Frame::new(),
876 frame1: IV3Frame::new(),
877 do_crc: false,
878 ign_size: false,
879 requant_tab
880 }
afe29743
KS
881 }
882}
883
afe29743 884impl NADecoder for Indeo3Decoder {
01613464 885 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
afe29743
KS
886 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
887 let w = vinfo.get_width();
888 let h = vinfo.get_height();
889 let fmt = formats::YUV410_FORMAT;
890 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt));
2422d969 891 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
f614c96f
KS
892 self.frame0.reset();
893 self.frame1.reset();
894 self.width = w as u16;
895 self.height = h as u16;
896 self.frame0.alloc(w, h);
897 self.frame1.alloc(w, h);
afe29743
KS
898 Ok(())
899 } else {
900 Err(DecoderError::InvalidData)
901 }
902 }
39cd2175 903 #[allow(clippy::manual_range_contains)]
01613464 904 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
afe29743
KS
905 let src = pkt.get_buffer();
906 let mut mr = MemoryReader::new_read(&src);
907 let mut br = ByteReader::new(&mut mr);
f614c96f
KS
908
909 // read OS header
910 let frameno = br.read_u32le()?;
911 let hdr_2 = br.read_u32le()?;
912 let check = br.read_u32le()?;
913 let size = br.read_u32le()?;
afe29743
KS
914
915 let data_start = br.tell();
916
917 if (frameno ^ hdr_2 ^ size ^ FRMH_TAG) != check {
918 return Err(DecoderError::InvalidData);
919 }
f614c96f
KS
920 if i64::from(size) > br.left() {
921 return Err(DecoderError::InvalidData);
922 }
923
924 let ver = br.read_u16le()?;
afe29743 925 if ver != 32 { return Err(DecoderError::NotImplemented); }
f614c96f
KS
926 let flags = br.read_u16le()?;
927 let size2 = br.read_u32le()?;
c5e335bf
KS
928 if size2 == 0x80 {
929 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
930 frm.set_keyframe(false);
931 frm.set_frame_type(FrameType::Skip);
932 return Ok(frm.into_ref());
933 }
afe29743 934 validate!(((size2 + 7) >> 3) <= size);
f614c96f
KS
935 self.header.vq_offset = br.read_byte()?;
936 br.read_skip(1)?;
937 let checksum = br.read_u16le()?;
938 let height = br.read_u16le()?;
939 let width = br.read_u16le()?;
afe29743 940 validate!((width >= 16) && (width <= 640));
f614c96f 941 validate!((height >= 16) && (height <= 480));
afe29743 942 validate!(((width & 3) == 0) && ((height & 3) == 0));
f614c96f
KS
943 if !self.ign_size && (width != self.width || height != self.height) {
944 self.width = width;
945 self.height = height;
946 self.frame0.alloc(width as usize, height as usize);
947 self.frame1.alloc(width as usize, height as usize);
948 let newinfo = NAVideoInfo::new(width as usize, height as usize, false, formats::YUV410_FORMAT);
949 self.info = NACodecInfo::new_ref(self.info.get_name(), NACodecTypeInfo::Video(newinfo), self.info.get_extradata()).into_ref();
afe29743 950 }
afe29743 951
f614c96f
KS
952 let yoff = br.read_u32le()?;
953 let voff = br.read_u32le()?;
954 let uoff = br.read_u32le()?;
955 validate!(yoff <= size && uoff <= size && voff <= size);
afe29743 956
f614c96f
KS
957 br.read_skip(4)?;
958 br.read_buf(&mut self.header.alt_quant)?;
afe29743
KS
959
960 let mut yend = src.len() as u32;//size;
961 if (uoff < yend) && (uoff > yoff) { yend = uoff; }
962 if (voff < yend) && (voff > yoff) { yend = voff; }
963 let mut uend = size;
964 if (yoff < uend) && (yoff > uoff) { uend = yoff; }
965 if (voff < uend) && (voff > uoff) { uend = voff; }
966 let mut vend = size;
967 if (yoff < vend) && (yoff > voff) { vend = yoff; }
968 if (uoff < vend) && (uoff > voff) { vend = uoff; }
969
f614c96f
KS
970 let intra_frame = (flags & FLAG_KEYFRAME) != 0;
971
972 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
afe29743 973 let mut buf = bufinfo.get_vbuf().unwrap();
f614c96f 974
f2af8eca
KS
975 let ystart = data_start + u64::from(yoff);
976 let ustart = data_start + u64::from(uoff);
977 let vstart = data_start + u64::from(voff);
978 let yendpos = data_start + u64::from(yend);
979 let uendpos = data_start + u64::from(uend);
980 let vendpos = data_start + u64::from(vend);
f614c96f
KS
981
982 self.header.data_start = [ystart, ustart, vstart];
983 self.header.data_end = [yendpos, uendpos, vendpos];
984 self.header.is_intra = intra_frame;
985
986 let (cur_frame, ref_frame) = if (flags & FLAG_BUFSEL) != 0 {
987 (&mut self.frame0, &mut self.frame1)
988 } else {
989 (&mut self.frame1, &mut self.frame0)
990 };
991 cur_frame.decode_planes(ref_frame, &mut br, &mut self.header, &self.requant_tab)?;
992 cur_frame.output_frame(&mut buf, (flags & FLAG_8BIT) != 0);
993 if self.do_crc && checksum != 0 {
994 let out_checksum = cur_frame.checksum((flags & FLAG_8BIT) != 0);
995 if checksum != out_checksum && checksum.rotate_left(8) != out_checksum {
996 println!("checksum {:04X} / {:04X}", checksum, out_checksum);
997 return Err(DecoderError::ChecksumError);
998 }
afe29743 999 }
f614c96f 1000
afe29743 1001 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
f614c96f
KS
1002 frm.set_keyframe(intra_frame);
1003 frm.set_frame_type(if intra_frame { FrameType::I } else { FrameType::P });
171860fc 1004 Ok(frm.into_ref())
afe29743 1005 }
f614c96f 1006
f9be4e75 1007 fn flush(&mut self) {
f614c96f
KS
1008 self.frame0.reset();
1009 self.frame1.reset();
f9be4e75 1010 }
afe29743
KS
1011}
1012
f614c96f
KS
1013const DO_CRC_OPTION: &str = "checksum";
1014const IGNORE_SIZE_OPTION: &str = "ignore_size_change";
1015
1016const DECODER_OPTS: &[NAOptionDefinition] = &[
1017 NAOptionDefinition {
1018 name: DO_CRC_OPTION, description: "Verify frame checksum",
1019 opt_type: NAOptionDefinitionType::Bool },
1020 NAOptionDefinition {
1021 name: IGNORE_SIZE_OPTION, description: "Ignore dimensions provided in the frame header",
1022 opt_type: NAOptionDefinitionType::Bool },
1023];
1024
7d57ae2f 1025impl NAOptionHandler for Indeo3Decoder {
f614c96f
KS
1026 fn get_supported_options(&self) -> &[NAOptionDefinition] { DECODER_OPTS }
1027 fn set_options(&mut self, options: &[NAOption]) {
1028 for option in options.iter() {
1029 for opt_def in DECODER_OPTS.iter() {
1030 if opt_def.check(option).is_ok() {
1031 match option.name {
1032 DO_CRC_OPTION => {
1033 if let NAValue::Bool(val) = option.value {
1034 self.do_crc = val;
1035 }
1036 },
1037 IGNORE_SIZE_OPTION => {
1038 if let NAValue::Bool(val) = option.value {
1039 self.ign_size = val;
1040 }
1041 },
1042 _ => {},
1043 };
1044 }
1045 }
1046 }
1047 }
1048 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1049 match name {
1050 DO_CRC_OPTION => Some(NAValue::Bool(self.do_crc)),
1051 IGNORE_SIZE_OPTION => Some(NAValue::Bool(self.ign_size)),
1052 _ => None,
1053 }
1054 }
7d57ae2f
KS
1055}
1056
08a1fab7 1057pub fn get_decoder() -> Box<dyn NADecoder + Send> {
379fd781
KS
1058 Box::new(Indeo3Decoder::new())
1059}
1060
afe29743
KS
1061#[cfg(test)]
1062mod test {
3167c45c
KS
1063 use nihav_core::codecs::RegisteredDecoders;
1064 use nihav_core::demuxers::RegisteredDemuxers;
ce742854 1065 use nihav_codec_support::test::dec_video::*;
78fb6560 1066 use crate::indeo_register_all_decoders;
e64739f8 1067 use nihav_commonfmt::generic_register_all_demuxers;
afe29743 1068 #[test]
f614c96f 1069 fn test_indeo3_decoder() {
3167c45c
KS
1070 let mut dmx_reg = RegisteredDemuxers::new();
1071 generic_register_all_demuxers(&mut dmx_reg);
1072 let mut dec_reg = RegisteredDecoders::new();
78fb6560 1073 indeo_register_all_decoders(&mut dec_reg);
3167c45c 1074
886cde48 1075 // sample: https://samples.mplayerhq.hu/V-codecs/IV32/iv32_example.avi
2890938d
KS
1076 test_decoding("avi", "indeo3", "assets/Indeo/iv32_example.avi", Some(10),
1077 &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
f614c96f
KS
1078 [0xd710b489, 0xbeee8f99, 0xfbe34549, 0xaf5805af],
1079 [0x2b56ad73, 0x1faea777, 0xed480d09, 0x801e5185],
1080 [0x06baa992, 0x74eef5fa, 0xf9d39fb2, 0xfac872ae],
1081 [0xadceb016, 0x1fbd67f9, 0xba3e6621, 0xd822a026],
1082 [0x052244b7, 0x1e3bd7bb, 0xd5ad10cf, 0x9177dc3e],
1083 [0x84cca4bc, 0x19ac192f, 0xb9281be7, 0x7ad6193e],
1084 [0xcab74cf9, 0xd7c77c2a, 0x848cbfc9, 0x604a2718],
1085 [0xe6d65b3b, 0x3f3ea0e1, 0x383cad01, 0x0788f3ac],
1086 [0xb25d9b0c, 0xc784bf67, 0x6e86991d, 0x7c2d9a14],
1087 [0x8c70aeae, 0xf95369a1, 0x31d60201, 0xe7e4acdb],
1088 [0x5c63f1bb, 0x32ce48a4, 0x226d112e, 0x440a5bba]]));
afe29743
KS
1089 }
1090}