1 use nihav_core::formats;
2 use nihav_core::codecs::*;
3 use nihav_core::io::byteio::*;
5 use super::indeo3data::*;
7 const DEFAULT_PIXEL: u8 = 0x40;
8 const STRIP_WIDTH: u8 = 160;
9 const FRMH_TAG: u32 = ((b'F' as u32) << 24) | ((b'R' as u32) << 16)
10 | ((b'M' as u32) << 8) | (b'H' as u32);
12 const FLAG_8BIT: u16 = 1 << 1;
13 const FLAG_KEYFRAME: u16 = 1 << 2;
14 const FLAG_BUFSEL: u16 = 1 << 9;
16 const MAX_DEPTH: u8 = 20;
18 const H_SPLIT: u8 = 0;
19 const V_SPLIT: u8 = 1;
20 const ABS_FILL: u8 = 2;
21 const REL_FILL: u8 = 3;
22 const VQ_NULL: u8 = 2;
23 const VQ_DATA: u8 = 3;
25 type RequantTab = [[u8; 128]; 8];
28 fn add_delta(&mut self, delta: i8) -> DecoderResult<()>;
31 impl 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);
39 #[derive(Clone, Copy)]
60 mvs: [MV { x: 0, y: 0 }; 256],
69 struct DataReader<'a, 'b> {
70 br: &'a mut ByteReader<'b>,
75 impl<'a, 'b> DataReader<'a, 'b> {
76 fn new(br: &'a mut ByteReader<'b>) -> Self {
83 fn read_2bits(&mut self) -> DecoderResult<u8> {
85 self.bitbuf = self.br.read_byte()?;
89 let bits = (self.bitbuf >> self.bpos) & 3;
92 fn read_byte(&mut self) -> DecoderResult<u8> {
93 Ok(self.br.read_byte()?)
97 #[derive(Debug, PartialEq)]
108 fn is_whole_block(&self) -> bool { matches!(*self, Corrector::Fill(_) | Corrector::ZeroBlock | Corrector::SkipBlock) }
111 struct QuadDecoder<'a, 'b, 'c> {
112 br: &'a mut DataReader<'b, 'c>,
113 cb: [&'static IviDeltaCB; 4],
124 impl<'a, 'b, 'c> QuadDecoder<'a, 'b, 'c> {
125 fn new(br: &'a mut DataReader<'b, 'c>, mode: u8, cb_index: [usize; 2]) -> Self {
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]],
138 fn get_skip_corr(&self) -> Corrector {
145 fn read(&mut self, line: u8) -> DecoderResult<Corrector> {
146 if let Some(fill) = self.fill {
148 return Ok(Corrector::Fill(fill));
150 if self.lines_run > 0 {
152 return Ok(self.get_skip_corr());
154 if self.block_run > 0 {
156 let corr = if !self.skip_flag {
163 let mut b = self.br.read_byte()?;
165 self.next_lit = false;
167 b = (self.cb[usize::from(line)].data.len() / 2) as u8;
173 let cb = self.cb[usize::from(line)];
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);
180 } else if self.cb_idx[usize::from(line)] < 16 {
181 ((b - esc_val) % cb.quad_radix, (b - esc_val) / cb.quad_radix)
183 ((b - esc_val) / cb.quad_radix, (b - esc_val) % cb.quad_radix)
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]]))
191 validate!(line == 0);
192 let fillval = self.br.read_byte()?;
193 if (fillval & 0x80) != 0 {
194 self.fill = Some(fillval & 0x7F);
196 Ok(Corrector::Fill(fillval & 0x7F))
199 validate!(line == 0);
200 self.skip_flag = true;
202 Ok(Corrector::SkipBlock)
205 validate!(self.mode != 3 && self.mode != 10);
206 Ok(Corrector::SkipBlock)
209 let b = self.br.read_byte()?;
210 validate!((b & 0x1F) > 0);
212 self.skip_flag = (b & 0x20) != 0;
213 self.block_run = (b & 0x1F) - 1;
215 self.lines_run = 3 - line;
216 Ok(self.get_skip_corr())
218 let corr = if !self.skip_flag {
228 self.skip_flag = false;
230 self.lines_run = 3 - line;
233 Ok(Corrector::ZeroBlock)
237 self.lines_run = 3 - line;
238 self.skip_flag = false;
243 self.lines_run = 2 - line;
244 self.skip_flag = false;
248 validate!(line == 0);
250 self.skip_flag = false;
251 self.next_lit = true;
258 #[derive(Clone, Copy)]
269 fn new(width: usize, height: usize) -> Self {
273 width: (width / 4) as u8,
274 height: (height / 4) as u8,
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() }
286 fn split_h(&self) -> (Self, Self) {
287 let h1 = if self.height > 2 { ((self.height + 2) >> 2) << 1 } else { 1 };
288 let h2 = self.height - h1;
289 let mut cell1 = *self;
292 let mut cell2 = *self;
298 fn split_v(&self, stripw: u8) -> (Self, Self) {
299 let w1 = if self.width > stripw {
300 if self.width > stripw * 2 { stripw * 2 } else { stripw }
302 if self.width > 2 { ((self.width + 2) >> 2) << 1 } else { 1 }
304 let w2 = self.width - w1;
305 let mut cell1 = *self;
308 let mut cell2 = *self;
316 impl std::fmt::Display for Indeo3Cell {
317 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
318 let spec = if let Some(mv) = self.mv {
319 format!("mv {},{}", mv.x, mv.y)
323 write!(f, "[{}x{} @ {},{} {}]", self.get_width(), self.get_height(), self.get_x(), self.get_y(), spec)
336 fn new(stripw: u8) -> Self {
342 fn alloc(&mut self, width: usize, height: usize) {
344 self.height = height;
345 self.data.resize(width * (height + 1), 0);
346 for el in self.data[..width].iter_mut() {
350 fn reset(&mut self) {
351 for el in self.data[self.width..].iter_mut() {
355 fn output_plane(&self, dst: &mut [u8], stride: usize, is_8bit: bool) {
356 for (dline, sline) in dst.chunks_mut(stride).zip(self.data.chunks(self.width).skip(1)) {
358 for (dst, &src) in dline.iter_mut().zip(sline.iter()) {
362 let size = dline.len();
363 dline.copy_from_slice(&sline[..size]);
367 fn checksum(&self) -> u16 {
368 let mut checksum = [0; 2];
369 for pair in self.data.chunks(2) {
370 checksum[0] ^= pair[0];
371 checksum[1] ^= pair[1];
373 read_u16le(&checksum).unwrap_or(0)
375 fn decode_data(&mut self, br: &mut DataReader, ref_plane: &mut Self, header: &Header, requant_tab: &RequantTab) -> DecoderResult<()> {
376 let cell = Indeo3Cell::new(self.width, self.height);
377 self.decode_mv_tree(br, ref_plane, cell, header, requant_tab)?;
380 fn decode_mv_tree(&mut self, br: &mut DataReader, ref_plane: &mut Self, cell: Indeo3Cell, header: &Header, requant_tab: &RequantTab) -> DecoderResult<()> {
381 validate!(cell.depth < MAX_DEPTH);
382 match br.read_2bits()? {
384 let (cell1, cell2) = cell.split_h();
385 self.decode_mv_tree(br, ref_plane, cell1, header, requant_tab)?;
386 self.decode_mv_tree(br, ref_plane, cell2, header, requant_tab)?;
389 let (cell1, cell2) = cell.split_v(self.stripw);
390 self.decode_mv_tree(br, ref_plane, cell1, header, requant_tab)?;
391 self.decode_mv_tree(br, ref_plane, cell2, header, requant_tab)?;
394 self.decode_vq_tree(br, ref_plane, cell, header, requant_tab)?;
397 validate!(!header.is_intra);
398 let mv_idx = usize::from(br.read_byte()?);
399 validate!(mv_idx < header.num_mvs);
400 let mut sec_cell = cell;
401 sec_cell.mv = Some(header.mvs[mv_idx]);
402 self.decode_vq_tree(br, ref_plane, sec_cell, header, requant_tab)?;
408 fn decode_vq_tree(&mut self, br: &mut DataReader, ref_plane: &mut Self, cell: Indeo3Cell, header: &Header, requant_tab: &RequantTab) -> DecoderResult<()> {
409 validate!(cell.depth < MAX_DEPTH);
410 match br.read_2bits()? {
412 let (cell1, cell2) = cell.split_h();
413 self.decode_vq_tree(br, ref_plane, cell1, header, requant_tab)?;
414 self.decode_vq_tree(br, ref_plane, cell2, header, requant_tab)?;
417 let (cell1, cell2) = cell.split_v(self.stripw);
418 self.decode_vq_tree(br, ref_plane, cell1, header, requant_tab)?;
419 self.decode_vq_tree(br, ref_plane, cell2, header, requant_tab)?;
422 let code = br.read_2bits()?;
425 self.copy_cell(ref_plane, cell)?;
427 1 => return Err(DecoderError::NotImplemented), // skip cell
428 _ => return Err(DecoderError::InvalidData),
432 let code = br.read_byte()?;
433 let mode = code >> 4;
434 let vq_index = code & 0xF;
435 let cb_index = if matches!(mode, 1 | 4 | 12) {
436 let aq = header.alt_quant[usize::from(vq_index)];
441 let cb_index = [usize::from(cb_index[0] + header.vq_offset), usize::from(cb_index[1] + header.vq_offset)];
442 validate!(cb_index[0] < IVI3_DELTA_CBS.len());
443 validate!(cb_index[1] < IVI3_DELTA_CBS.len());
444 if cell.get_y() > 0 && matches!(mode, 0 | 3 | 10) && (8..=15).contains(&cb_index[0]) {
445 let src = if cell.is_intra() {
446 &mut self.data[cell.get_x() + cell.get_y() * self.width..]
448 &mut ref_plane.data[cell.get_x() + (cell.get_y() + 1) * ref_plane.width..]
450 let cur_requant_tab = &requant_tab[cb_index[0] - 8];
451 for el in src.iter_mut().take(cell.get_width()) {
452 *el = cur_requant_tab[usize::from(*el)];
456 let qmode = if mode != 10 || cell.is_intra() { mode } else { 20 };
457 let mut quad_decoder = QuadDecoder::new(br, qmode, cb_index);
458 if !cell.is_intra() {
459 self.copy_cell(ref_plane, cell)?;
463 self.process_cell_0_1(&mut quad_decoder, cell)?;
466 validate!(cell.is_intra());
467 validate!((cell.get_height() & 7) == 0);
468 self.process_cell_3_4(&mut quad_decoder, cell)?;
471 validate!((cell.get_width() & 7) == 0);
472 validate!((cell.get_height() & 7) == 0);
473 self.process_cell_10_intra(&mut quad_decoder, cell)?;
476 validate!((cell.get_width() & 7) == 0);
477 validate!((cell.get_height() & 7) == 0);
478 self.process_cell_10_inter(&mut quad_decoder, cell)?;
481 validate!(!cell.is_intra());
482 validate!((cell.get_height() & 7) == 0);
483 self.process_cell_11(&mut quad_decoder, cell)?;
485 2 | 12 => { return Err(DecoderError::NotImplemented)},
486 _ => return Err(DecoderError::InvalidData),
488 if matches!(qmode, 3 | 4 | 10) && cell.get_y() == 0 {
489 let line_pair = &mut self.data[cell.get_x() + (cell.get_y() + 1) * self.width..];
490 let (line0, line1) = line_pair.split_at_mut(self.width);
491 line0[..cell.get_width()].copy_from_slice(&line1[..cell.get_width()]);
498 fn process_cell_0_1(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
499 let stride = self.width;
500 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
501 let cell_w = cell.get_width();
502 for _y in (0..cell.get_height()).step_by(4) {
504 for x in (0..cell_w).step_by(4) {
505 let top = &self.data[offset - stride + x..];
506 let mut top = [top[0], top[1], top[2], top[3]];
508 let corr = qd.read(line as u8)?;
509 if !cell.is_intra() && !corr.is_whole_block() {
510 let src = &self.data[offset + line * stride + x..];
511 top.copy_from_slice(&src[..4]);
514 Corrector::SkipBlock => continue 'block0,
515 Corrector::Fill(fill) => {
516 for line in self.data[offset + x..].chunks_mut(stride).take(4) {
517 for el in line[..4].iter_mut() {
522 Corrector::ZeroBlock if cell.is_intra() => {
523 let (head, cur) = self.data.split_at_mut(offset + x);
524 let prev = &head[head.len() - stride..];
525 for dline in cur.chunks_mut(stride).take(4) {
526 dline[..4].copy_from_slice(&prev[..4]);
530 Corrector::ZeroBlock => continue 'block0,
531 Corrector::Quad(quad) => {
532 for (el, &corr) in top.iter_mut().zip(quad.iter()) {
536 Corrector::Zero => {},
537 Corrector::Skip if cell.is_intra() => unimplemented!(),
538 Corrector::Skip => {},
540 let wback = match corr {
541 Corrector::Zero if cell.is_intra() => true,
542 Corrector::Quad(_) => true,
546 self.data[offset + x + line * stride..][..4].copy_from_slice(&top);
550 offset += self.width * 4;
554 fn process_cell_3_4(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
555 let stride = self.width;
556 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
557 let cell_w = cell.get_width();
558 for _y in (0..cell.get_height()).step_by(8) {
560 for x in (0..cell_w).step_by(4) {
561 let top = &self.data[offset - stride + x..][..4];
562 let mut top = [top[0], top[1], top[2], top[3]];
564 let corr = qd.read(line as u8)?;
566 Corrector::SkipBlock => continue 'block3,
567 Corrector::Fill(fill) => {
568 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
569 for el in line[..4].iter_mut() {
574 Corrector::ZeroBlock => {
575 for dline in self.data[offset + x..].chunks_mut(stride).take(8) {
576 dline[..4].copy_from_slice(&top);
580 Corrector::Quad(quad) => {
581 for (el, &corr) in top.iter_mut().zip(quad.iter()) {
585 Corrector::Zero => {},
586 Corrector::Skip => unimplemented!(),
589 if corr != Corrector::Skip {
590 let dst = &mut self.data[offset + x + (line * 2 + 1) * stride..][..4];
591 dst.copy_from_slice(&top);
595 let mut top_off = offset + x - stride;
598 self.data[top_off + stride + pos] = (self.data[top_off + pos] + self.data[top_off + stride * 2 + pos]) >> 1;
600 top_off += stride * 2;
603 offset += self.width * 8;
607 fn process_cell_10_intra(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
608 let stride = self.width;
609 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
610 let cell_w = cell.get_width();
611 for _y in (0..cell.get_height()).step_by(8) {
613 for x in (0..cell_w).step_by(8) {
614 let top = &self.data[offset - stride + x..][..8];
615 let mut top = [top[0], top[2], top[4], top[6]];
617 let corr = qd.read(line as u8)?;
619 Corrector::SkipBlock => continue 'block10i,
620 Corrector::Fill(fill) => {
621 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
622 for el in line[..8].iter_mut() {
627 Corrector::ZeroBlock => {
628 let line_pair = &mut self.data[offset - stride + x..];
629 let (top_line, dst_line) = line_pair.split_at_mut(stride);
630 for (i, (dst, &top_s)) in dst_line.iter_mut()
631 .zip(top_line.iter()).take(8).enumerate() {
632 *dst = (top_s + top[i >> 1]) >> 1;
634 for dline in self.data[offset + x..].chunks_mut(stride).take(8).skip(1) {
635 for (dst, &src) in dline.chunks_mut(2).zip(top.iter()) {
642 Corrector::Quad(quad) => {
643 for (el, &corr) in top.iter_mut().zip(quad.iter()) {
647 Corrector::Zero => {},
648 Corrector::Skip => unimplemented!(),
651 if corr != Corrector::Skip {
652 for (dst, &prev) in self.data[offset + x + (line * 2 + 1) * stride..].chunks_mut(2).zip(top.iter()).take(4) {
659 let mut top_off = offset + x - stride;
662 self.data[top_off + stride + pos] = (self.data[top_off + pos] + self.data[top_off + stride * 2 + pos]) >> 1;
664 top_off += stride * 2;
667 offset += self.width * 8;
671 fn process_cell_10_inter(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
672 let stride = self.width;
673 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
674 let cell_w = cell.get_width();
675 for _y in (0..cell.get_height()).step_by(8) {
677 for x in (0..cell_w).step_by(8) {
679 let corr = qd.read(line as u8)?;
681 Corrector::SkipBlock | Corrector::ZeroBlock => continue 'block10p,
682 Corrector::Fill(fill) => {
683 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
684 for el in line[..8].iter_mut() {
689 Corrector::Quad(quad) => {
690 let strip = &mut self.data[offset + x + line * 2 * stride..];
691 for (xoff, &corr) in quad.iter().enumerate() {
692 strip[xoff * 2].add_delta(corr)?;
693 strip[xoff * 2 + 1].add_delta(corr)?;
694 strip[xoff * 2 + stride].add_delta(corr)?;
695 strip[xoff * 2 + stride + 1].add_delta(corr)?;
702 offset += self.width * 8;
706 fn process_cell_11(&mut self, qd: &mut QuadDecoder, cell: Indeo3Cell) -> DecoderResult<()> {
707 let stride = self.width;
708 let mut offset = cell.get_x() + (cell.get_y() + 1) * stride;
709 let cell_w = cell.get_width();
710 for _y in (0..cell.get_height()).step_by(8) {
712 for x in (0..cell_w).step_by(4) {
714 let corr = qd.read(line as u8)?;
716 Corrector::SkipBlock | Corrector::ZeroBlock => continue 'block10p,
717 Corrector::Fill(fill) => {
718 for line in self.data[offset + x..].chunks_mut(stride).take(8) {
719 for el in line[..4].iter_mut() {
724 Corrector::Quad(quad) => {
725 let strip = &mut self.data[offset + x + line * 2 * stride..];
726 for (xoff, &corr) in quad.iter().enumerate() {
727 strip[xoff].add_delta(corr)?;
728 strip[xoff + stride].add_delta(corr)?;
735 offset += self.width * 8;
739 fn copy_cell(&mut self, ref_plane: &Self, cell: Indeo3Cell) -> DecoderResult<()> {
740 if let Some(mv) = cell.mv {
741 let xpos = (cell.get_x() as isize) + isize::from(mv.x);
742 validate!(xpos >= 0);
743 let xpos = xpos as usize;
744 validate!(xpos + cell.get_width() <= self.width);
745 let ypos = (cell.get_y() as isize) + isize::from(mv.y);
746 validate!(ypos >= 0);
747 let ypos = ypos as usize;
748 validate!(ypos + cell.get_height() <= self.height);
749 let src = &ref_plane.data[xpos + (ypos + 1) * ref_plane.width..];
750 let dst = &mut self.data[cell.get_x() + (cell.get_y() + 1) * self.width..];
752 let width = cell.get_width();
753 let height = cell.get_height();
754 for (dline, sline) in dst.chunks_mut(ref_plane.width).zip(src.chunks(self.width)).take(height) {
755 dline[..width].copy_from_slice(&sline[..width]);
759 Err(DecoderError::InvalidData)
772 Plane::new(STRIP_WIDTH),
773 Plane::new(STRIP_WIDTH >> 2),
774 Plane::new(STRIP_WIDTH >> 2),
778 fn alloc(&mut self, width: usize, height: usize) {
779 self.plane[0].alloc( width, height);
780 let chroma_w = ((width + 15) & !15) >> 2;
781 let chroma_h = ((height + 15) & !15) >> 2;
782 self.plane[1].alloc(chroma_w, chroma_h);
783 self.plane[2].alloc(chroma_w, chroma_h);
785 fn reset(&mut self) {
786 for plane in self.plane.iter_mut() {
790 fn decode_planes(&mut self, ref_frame: &mut IV3Frame, br: &mut ByteReader, header: &mut Header, requant_tab: &RequantTab) -> DecoderResult<()> {
791 let data_start = header.data_start;
792 let data_end = header.data_end;
793 for ((cur_plane, ref_plane), (&start, &end)) in self.plane.iter_mut()
794 .zip(ref_frame.plane.iter_mut())
795 .zip(data_start.iter().zip(data_end.iter())) {
796 br.seek(SeekFrom::Start(start))?;
797 let num_mvs = br.read_u32le()? as usize;
799 validate!(num_mvs == 0);
801 validate!(num_mvs <= header.mvs.len());
803 header.num_mvs = num_mvs;
804 for mv in header.mvs.iter_mut().take(num_mvs) {
805 mv.y = br.read_byte()? as i8;
806 mv.x = br.read_byte()? as i8;
808 let mut reader = DataReader::new(br);
809 cur_plane.decode_data(&mut reader, ref_plane, header, requant_tab)?;
810 validate!(br.tell() <= end);
814 fn output_frame(&self, dst: &mut NAVideoBuffer<u8>, is_8bit: bool) {
815 let dfrm = NASimpleVideoFrame::from_video_buf(dst).unwrap();
816 for (plane_no, plane) in self.plane.iter().enumerate() {
817 plane.output_plane(&mut dfrm.data[dfrm.offset[plane_no]..], dfrm.stride[plane_no], is_8bit);
820 fn checksum(&self, is_8bit: bool) -> u16 {
821 let mut checksum = 0;
822 for plane in self.plane.iter() {
823 checksum ^= plane.checksum();
832 struct Indeo3Decoder {
833 info: NACodecInfoRef,
839 requant_tab: RequantTab,
846 const REQUANT_OFF: [i32; 8] = [ 0, 1, 0, 4, 4, 1, 0, 1 ];
848 let dummy_info = NACodecInfo::new_dummy();
850 let mut requant_tab = [[0u8; 128]; 8];
852 let step = (i as i32) + 2;
853 let start = if (i == 3) || (i == 4) { -3 } else { step / 2 };
856 requant_tab[i][j] = (((j as i32) + start) / step * step + REQUANT_OFF[i]) as u8;
857 if requant_tab[i][j] < 128 {
858 last = requant_tab[i][j];
860 requant_tab[i][j] = last;
864 requant_tab[1][7] = 10;
865 requant_tab[1][119] = 118;
866 requant_tab[1][120] = 118;
867 requant_tab[4][8] = 10;
873 header: Header::new(),
874 frame0: IV3Frame::new(),
875 frame1: IV3Frame::new(),
883 impl NADecoder for Indeo3Decoder {
884 fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
885 if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
886 let w = vinfo.get_width();
887 let h = vinfo.get_height();
888 let fmt = formats::YUV410_FORMAT;
889 let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt));
890 self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
893 self.width = w as u16;
894 self.height = h as u16;
895 self.frame0.alloc(w, h);
896 self.frame1.alloc(w, h);
899 Err(DecoderError::InvalidData)
902 fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
903 let src = pkt.get_buffer();
904 let mut mr = MemoryReader::new_read(&src);
905 let mut br = ByteReader::new(&mut mr);
908 let frameno = br.read_u32le()?;
909 let hdr_2 = br.read_u32le()?;
910 let check = br.read_u32le()?;
911 let size = br.read_u32le()?;
913 let data_start = br.tell();
915 if (frameno ^ hdr_2 ^ size ^ FRMH_TAG) != check {
916 return Err(DecoderError::InvalidData);
918 if i64::from(size) > br.left() {
919 return Err(DecoderError::InvalidData);
922 let ver = br.read_u16le()?;
923 if ver != 32 { return Err(DecoderError::NotImplemented); }
924 let flags = br.read_u16le()?;
925 let size2 = br.read_u32le()?;
927 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
928 frm.set_keyframe(false);
929 frm.set_frame_type(FrameType::Skip);
930 return Ok(frm.into_ref());
932 validate!(((size2 + 7) >> 3) <= size);
933 self.header.vq_offset = br.read_byte()?;
935 let checksum = br.read_u16le()?;
936 let height = br.read_u16le()?;
937 let width = br.read_u16le()?;
938 validate!((width >= 16) && (width <= 640));
939 validate!((height >= 16) && (height <= 480));
940 validate!(((width & 3) == 0) && ((height & 3) == 0));
941 if !self.ign_size && (width != self.width || height != self.height) {
943 self.height = height;
944 self.frame0.alloc(width as usize, height as usize);
945 self.frame1.alloc(width as usize, height as usize);
946 let newinfo = NAVideoInfo::new(width as usize, height as usize, false, formats::YUV410_FORMAT);
947 self.info = NACodecInfo::new_ref(self.info.get_name(), NACodecTypeInfo::Video(newinfo), self.info.get_extradata()).into_ref();
950 let yoff = br.read_u32le()?;
951 let voff = br.read_u32le()?;
952 let uoff = br.read_u32le()?;
953 validate!(yoff <= size && uoff <= size && voff <= size);
956 br.read_buf(&mut self.header.alt_quant)?;
958 let mut yend = src.len() as u32;//size;
959 if (uoff < yend) && (uoff > yoff) { yend = uoff; }
960 if (voff < yend) && (voff > yoff) { yend = voff; }
962 if (yoff < uend) && (yoff > uoff) { uend = yoff; }
963 if (voff < uend) && (voff > uoff) { uend = voff; }
965 if (yoff < vend) && (yoff > voff) { vend = yoff; }
966 if (uoff < vend) && (uoff > voff) { vend = uoff; }
968 let intra_frame = (flags & FLAG_KEYFRAME) != 0;
970 let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 4)?;
971 let mut buf = bufinfo.get_vbuf().unwrap();
973 let ystart = data_start + u64::from(yoff);
974 let ustart = data_start + u64::from(uoff);
975 let vstart = data_start + u64::from(voff);
976 let yendpos = data_start + u64::from(yend);
977 let uendpos = data_start + u64::from(uend);
978 let vendpos = data_start + u64::from(vend);
980 self.header.data_start = [ystart, ustart, vstart];
981 self.header.data_end = [yendpos, uendpos, vendpos];
982 self.header.is_intra = intra_frame;
984 let (cur_frame, ref_frame) = if (flags & FLAG_BUFSEL) != 0 {
985 (&mut self.frame0, &mut self.frame1)
987 (&mut self.frame1, &mut self.frame0)
989 cur_frame.decode_planes(ref_frame, &mut br, &mut self.header, &self.requant_tab)?;
990 cur_frame.output_frame(&mut buf, (flags & FLAG_8BIT) != 0);
991 if self.do_crc && checksum != 0 {
992 let out_checksum = cur_frame.checksum((flags & FLAG_8BIT) != 0);
993 if checksum != out_checksum && checksum.rotate_left(8) != out_checksum {
994 println!("checksum {:04X} / {:04X}", checksum, out_checksum);
995 return Err(DecoderError::ChecksumError);
999 let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
1000 frm.set_keyframe(intra_frame);
1001 frm.set_frame_type(if intra_frame { FrameType::I } else { FrameType::P });
1005 fn flush(&mut self) {
1006 self.frame0.reset();
1007 self.frame1.reset();
1011 const DO_CRC_OPTION: &str = "checksum";
1012 const IGNORE_SIZE_OPTION: &str = "ignore_size_change";
1014 const DECODER_OPTS: &[NAOptionDefinition] = &[
1015 NAOptionDefinition {
1016 name: DO_CRC_OPTION, description: "Verify frame checksum",
1017 opt_type: NAOptionDefinitionType::Bool },
1018 NAOptionDefinition {
1019 name: IGNORE_SIZE_OPTION, description: "Ignore dimensions provided in the frame header",
1020 opt_type: NAOptionDefinitionType::Bool },
1023 impl NAOptionHandler for Indeo3Decoder {
1024 fn get_supported_options(&self) -> &[NAOptionDefinition] { DECODER_OPTS }
1025 fn set_options(&mut self, options: &[NAOption]) {
1026 for option in options.iter() {
1027 for opt_def in DECODER_OPTS.iter() {
1028 if opt_def.check(option).is_ok() {
1031 if let NAValue::Bool(val) = option.value {
1035 IGNORE_SIZE_OPTION => {
1036 if let NAValue::Bool(val) = option.value {
1037 self.ign_size = val;
1046 fn query_option_value(&self, name: &str) -> Option<NAValue> {
1048 DO_CRC_OPTION => Some(NAValue::Bool(self.do_crc)),
1049 IGNORE_SIZE_OPTION => Some(NAValue::Bool(self.ign_size)),
1055 pub fn get_decoder() -> Box<dyn NADecoder + Send> {
1056 Box::new(Indeo3Decoder::new())
1061 use nihav_core::codecs::RegisteredDecoders;
1062 use nihav_core::demuxers::RegisteredDemuxers;
1063 use nihav_codec_support::test::dec_video::*;
1064 use crate::indeo_register_all_decoders;
1065 use nihav_commonfmt::generic_register_all_demuxers;
1067 fn test_indeo3_decoder() {
1068 let mut dmx_reg = RegisteredDemuxers::new();
1069 generic_register_all_demuxers(&mut dmx_reg);
1070 let mut dec_reg = RegisteredDecoders::new();
1071 indeo_register_all_decoders(&mut dec_reg);
1073 // sample: https://samples.mplayerhq.hu/V-codecs/IV32/iv32_example.avi
1074 test_decoding("avi", "indeo3", "assets/Indeo/iv32_example.avi", Some(10),
1075 &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![
1076 [0xd710b489, 0xbeee8f99, 0xfbe34549, 0xaf5805af],
1077 [0x2b56ad73, 0x1faea777, 0xed480d09, 0x801e5185],
1078 [0x06baa992, 0x74eef5fa, 0xf9d39fb2, 0xfac872ae],
1079 [0xadceb016, 0x1fbd67f9, 0xba3e6621, 0xd822a026],
1080 [0x052244b7, 0x1e3bd7bb, 0xd5ad10cf, 0x9177dc3e],
1081 [0x84cca4bc, 0x19ac192f, 0xb9281be7, 0x7ad6193e],
1082 [0xcab74cf9, 0xd7c77c2a, 0x848cbfc9, 0x604a2718],
1083 [0xe6d65b3b, 0x3f3ea0e1, 0x383cad01, 0x0788f3ac],
1084 [0xb25d9b0c, 0xc784bf67, 0x6e86991d, 0x7c2d9a14],
1085 [0x8c70aeae, 0xf95369a1, 0x31d60201, 0xe7e4acdb],
1086 [0x5c63f1bb, 0x32ce48a4, 0x226d112e, 0x440a5bba]]));