Indeo4/5 decoder
authorKostya Shishkov <kostya.shishkov@gmail.com>
Fri, 14 Jul 2017 16:29:33 +0000 (18:29 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sun, 30 Jul 2017 11:01:54 +0000 (13:01 +0200)
Cargo.toml
src/codecs/indeo/indeo4.rs [new file with mode: 0644]
src/codecs/indeo/indeo5.rs [new file with mode: 0644]
src/codecs/indeo/ivi.rs [new file with mode: 0644]
src/codecs/indeo/ivibr.rs [new file with mode: 0644]
src/codecs/indeo/ividsp.rs [new file with mode: 0644]
src/codecs/indeo/mod.rs
src/codecs/mod.rs

index ce56480dea6fba40cd850f03f4c1bfdc0c766bfa..5995625583aec68050fe0e4647f139e2076c7ccc 100644 (file)
@@ -20,10 +20,12 @@ dsp_window = ["dsp"]
 
 all_decoders = ["all_video_decoders", "all_audio_decoders"]
 
-all_video_decoders = ["decoder_gdvvid", "decoder_indeo2", "decoder_indeo3", "decoder_intel263"]
+all_video_decoders = ["decoder_gdvvid", "decoder_indeo2", "decoder_indeo3", "decoder_indeo4", "decoder_indeo5", "decoder_intel263"]
 decoder_gdvvid = ["decoders"]
 decoder_indeo2 = ["decoders"]
 decoder_indeo3 = ["decoders"]
+decoder_indeo4 = ["decoders"]
+decoder_indeo5 = ["decoders"]
 decoder_intel263 = ["h263", "decoders"]
 
 all_audio_decoders = ["decoder_pcm", "decoder_imc"]
diff --git a/src/codecs/indeo/indeo4.rs b/src/codecs/indeo/indeo4.rs
new file mode 100644 (file)
index 0000000..60c45ab
--- /dev/null
@@ -0,0 +1,718 @@
+use std::cell::Ref;
+use io::bitreader::*;
+use formats;
+use super::super::*;
+use super::ivi::*;
+use super::ivibr::*;
+
+struct Indeo4Parser {
+    mb_cb:          IVICodebook,
+    blk_cb:         IVICodebook,
+}
+
+fn calc_quant(glob_q: u32, qd: i16) -> u8 {
+    let q = (glob_q as i16) + qd;
+    if q < 0 {
+        0
+    } else if q > 31 {
+        31
+    } else {
+        q as u8
+    }
+}
+
+impl Indeo4Parser {
+    fn new() -> Self {
+        Indeo4Parser {
+            mb_cb:      IVI_CB_ZERO,
+            blk_cb:     IVI_CB_ZERO,
+        }
+    }
+}
+
+impl IndeoXParser for Indeo4Parser {
+#[allow(unused_variables,unused_assignments)]
+    fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader> {
+        let sync                = br.read(18)?;
+        validate!(sync == 0x3FFF8);
+        let ftype_idx           = br.read(3)?;
+        validate!(ftype_idx < 7);
+        let ftype               = INDEO4_FRAME_TYPE[ftype_idx as usize];
+        let transparent         = br.read_bool()?;
+        br.skip(1)?;
+        let data_size;
+        if br.read_bool()? {
+            data_size = br.read(24)? as usize;
+        } else {
+            data_size = 0;
+        }
+        if ftype.is_null() {
+            return Ok(PictureHeader::new_null(ftype));
+        }
+        if br.read_bool()? {
+            br.skip(32)?; // key lock
+        }
+        let width;
+        let height;
+        let pic_size_idx        = br.read(3)?;
+        if pic_size_idx < 7 {
+            width  = INDEO4_PICTURE_SIZE_TAB[pic_size_idx as usize][0];
+            height = INDEO4_PICTURE_SIZE_TAB[pic_size_idx as usize][1];
+        } else {
+            height              = br.read(16)? as usize;
+            width               = br.read(16)? as usize;
+            validate!((width  > 0) && ((width  & 3) == 0));
+            validate!((height > 0) && ((height & 3) == 0));
+        }
+
+        let slice_w;
+        let slice_h;
+        if br.read_bool()? {
+            let idx = br.read(4)? as usize;
+            if idx < 15 {
+                slice_w = INDEO4_SLICE_SIZE_TAB[idx];
+                slice_h = INDEO4_SLICE_SIZE_TAB[idx];
+            } else {
+                slice_w = width;
+                slice_h = height;
+            }
+        } else {
+            slice_w = width;
+            slice_h = height;
+        }
+        let subsampling         = br.read(2)?;
+        validate!(subsampling == 0);
+        let sc_idx              = br.read(2)?;
+        match sc_idx {
+            3 => { },
+            2 => { validate!(br.read(2*4)? == 0xFF); }
+            _ => { return Err(DecoderError::InvalidData); }
+        };
+        let luma_bands = if sc_idx == 2 { 4 } else { 1 };
+        let sc_idx              = br.read(2)?;
+        match sc_idx {
+            3 => { },
+            2 => { validate!(br.read(2*4)? == 0xFF); }
+            _ => { return Err(DecoderError::InvalidData); }
+        };
+        let chroma_bands = if sc_idx == 2 { 4 } else { 1 };
+        let frame_no;
+        if br.read_bool()? {
+            frame_no = br.read(20)?;
+        } else {
+            frame_no = 0;
+        }
+        if br.read_bool()? {
+            br.skip(8)?; // decTimeEst
+        }
+        let desc_coded          = br.read_bool()?;
+        self.mb_cb              = br.read_ivi_codebook_desc(true,  desc_coded)?;
+        let desc_coded          = br.read_bool()?;
+        self.blk_cb             = br.read_ivi_codebook_desc(false, desc_coded)?;
+        let rvmap               = if br.read_bool()? { br.read(3)? as usize } else { 8 };
+        let in_imf              = br.read_bool()?;
+        let in_q                = br.read_bool()?;
+        let glob_q              = br.read(5)? as u8;
+        if br.read_bool()? {
+            br.skip(3)?;
+        }
+        let checksum            = if br.read_bool()? { br.read(16)? } else { 0 };
+        if br.read_bool()? {
+            br.skip(8)?; // pic hdr extension
+        }
+        if br.read_bool()? {
+            println!("bad blocks bits!");
+        }
+        br.align();
+
+        Ok(PictureHeader::new(ftype, width, height, slice_w, slice_h, transparent, luma_bands, chroma_bands, in_q))
+    }
+
+#[allow(unused_variables,unused_assignments)]
+    fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane: usize, band: usize) -> DecoderResult<BandHeader> {
+        let plane_no        = br.read(2)? as usize;
+        let band_no         = br.read(4)? as usize;
+        validate!(plane_no == plane);
+        validate!(band_no  == band);
+        if br.read_bool()? {
+            br.align();
+            return Ok(BandHeader::new_empty(plane_no, band_no));
+        }
+        let hdr_size;
+        if br.read_bool()? {
+            hdr_size        = br.read(16)? as usize;
+        } else {
+            hdr_size = 32;
+        }
+        let mv_mode         = br.read(2)?;
+        validate!(mv_mode < 2);
+        if br.read_bool()? {
+            br.skip(16)?; //checksum
+        }
+
+        let scale           = br.read(2)?;
+        validate!(scale != 3);
+        let mb_size  = 16 >> scale;
+        let blk_size =  8 >> (scale >> 1);
+        let inherit_mv      = br.read_bool()?;
+        let inherit_qd      = br.read_bool()?;
+        let quant           = br.read(5)?;
+
+        let tr: IVITransformType;
+        let txtype: TxType;
+        if !br.read_bool()? || pic_hdr.ftype == IVIFrameType::Intra {
+            let tr_id       = br.read(5)?;
+            validate!(tr_id < 18);
+            let scan_idx    = br.read(4)? as usize;
+            validate!(scan_idx != 15);
+            let qmat_idx    = br.read(5)? as usize;
+
+            tr = INDEO4_TRANSFORMS[tr_id as usize];
+            if (scan_idx < 5) || (scan_idx >= 10) {
+                validate!(tr.is_8x8());
+                validate!(qmat_idx < 15);
+                let scan = if scan_idx < 5 { INDEO4_SCANS_8X8[scan_idx] }
+                           else            { INDEO4_SCANS_8X8[4] };
+                let qidx = INDEO4_Q8X8_IDX[qmat_idx];
+                let qintra = INDEO4_Q8_INTRA[qidx];
+                let qinter = INDEO4_Q8_INTER[qidx];
+                txtype = TxType::Transform8(TxParams8x8::new(qintra, qinter, scan));
+            } else if scan_idx < 10 {
+                validate!(!tr.is_8x8());
+                validate!((qmat_idx >= 15) && (qmat_idx < 22));
+                let scan = INDEO4_SCANS_4X4[scan_idx - 5];
+                let qidx = INDEO4_Q4X4_IDX[qmat_idx - 15];
+                let qintra = INDEO4_Q4_INTRA[qidx];
+                let qinter = INDEO4_Q4_INTER[qidx];
+                txtype = TxType::Transform4(TxParams4x4::new(qintra, qinter, scan));
+            } else {
+                unreachable!();
+            }
+        } else {
+            tr = IVITransformType::None(TSize::T8x8);
+            txtype = TxType::None;
+        }
+
+        let blk_cb;
+        if br.read_bool()? {
+            
+            blk_cb = br.read_ivi_codebook_desc(false, true)?;
+        } else {
+            blk_cb = self.blk_cb;
+        }
+        let rvmap_idx;
+        if br.read_bool()? {
+            rvmap_idx = br.read(3)? as usize;
+        } else {
+            rvmap_idx = 8;
+        }
+        let num_corr;
+        let mut corr_map: [u8; CORR_MAP_SIZE] = [0; CORR_MAP_SIZE];
+        if br.read_bool()? {
+            num_corr = br.read(8)? as usize;
+            validate!(num_corr*2 <= CORR_MAP_SIZE);
+            for i in 0..num_corr*2 {
+                corr_map[i] = br.read(8)? as u8;
+            }
+        } else {
+            num_corr = 0;
+        }
+
+        br.align();
+        Ok(BandHeader::new(plane_no, band_no, mb_size, blk_size, mv_mode == 1, inherit_mv, false, inherit_qd, quant, rvmap_idx, num_corr, corr_map, blk_cb, tr, txtype))
+    }
+
+    fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band: &BandHeader, tile: &mut IVITile, ref_tile: Option<Ref<IVITile>>, mv_scale: u8) -> DecoderResult<()> {
+        let mut mv_x = 0;
+        let mut mv_y = 0;
+        let mut mb_idx = 0;
+
+        for mb_y in 0..tile.mb_h {
+            for mb_x in 0..tile.mb_w {
+                let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
+                if !br.read_bool()? {
+                    if pic_hdr.ftype.is_intra() {
+                        mb.mtype = MBType::Intra;
+                    } else if band.inherit_mv {
+                        if let Some(ref tileref) = ref_tile {
+                            mb.mtype = tileref.mb[mb_idx].mtype;
+                        } else {
+                            return Err(DecoderError::MissingReference);
+                        }
+                    } else {
+                        if !pic_hdr.ftype.is_bidir() {
+                            mb.mtype = if br.read_bool()? { MBType::Inter } else { MBType::Intra };
+                        } else {
+                            mb.mtype = match br.read(2)? {
+                                0 => { MBType::Intra },
+                                1 => { MBType::Inter },
+                                2 => { MBType::Backward },
+                                _ => { MBType::Bidir },
+                            };
+                        }
+                    }
+                    if band.mb_size == band.blk_size {
+                        mb.cbp = br.read(1)? as u8;
+                    } else {
+                        mb.cbp = br.read(4)? as u8;
+                    }
+                    if band.inherit_qd {
+                        if let Some(ref tileref) = ref_tile {
+                            mb.qd = tileref.mb[mb_idx].qd;
+                            mb.q  = calc_quant(band.quant, mb.qd);
+                        } else {
+                            mb.q = band.quant as u8;
+                        }
+                    } else if (mb.cbp != 0) || ((band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q) {
+                        mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+                        mb.q = calc_quant(band.quant, mb.qd);
+                    } else {
+                        mb.q = band.quant as u8;
+                    }
+
+                    if mb.mtype != MBType::Intra {
+                        if band.inherit_mv {
+                            if let Some(ref tileref) = ref_tile {
+                                let mx = tileref.mb[mb_idx].mv_x;
+                                let my = tileref.mb[mb_idx].mv_y;
+                                if mv_scale == 0 {
+                                    mb.mv_x = mx;
+                                    mb.mv_y = my;
+                                } else {
+                                    mb.mv_x = scale_mv(mx, mv_scale);
+                                    mb.mv_y = scale_mv(my, mv_scale);
+                                }
+                            }
+                        } else {
+                            mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
+                            mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
+                            mb.mv_x = mv_x;
+                            mb.mv_y = mv_y;
+                            if mb.mtype == MBType::Backward {
+                                mb.mv2_x = -mb.mv_x;
+                                mb.mv2_y = -mb.mv_y;
+                                mb.mv_x  = 0;
+                                mb.mv_y  = 0;
+                            } else if mb.mtype == MBType::Bidir {
+                                mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
+                                mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
+                                mb.mv2_x = -mv_x;
+                                mb.mv2_y = -mv_y;
+                            }
+                        }
+                    }
+                } else {
+                    validate!(!pic_hdr.ftype.is_intra());
+                    mb.mtype = MBType::Inter;
+                    mb.cbp   = 0;
+                    mb.qd    = 0;
+                    if (band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q {
+                        mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+                        mb.q  = calc_quant(band.quant, mb.qd);
+                    }
+                    if band.inherit_mv {
+                        if let Some(ref tileref) = ref_tile {
+                            let mx = tileref.mb[mb_idx].mv_x;
+                            let my = tileref.mb[mb_idx].mv_y;
+                            if mv_scale == 0 {
+                                mb.mv_x = mx;
+                                mb.mv_y = my;
+                            } else {
+                                mb.mv_x = scale_mv(mx, mv_scale);
+                                mb.mv_y = scale_mv(my, mv_scale);
+                            }
+                        }
+                    }
+                }
+                tile.mb[mb_idx] = mb;
+                mb_idx += 1;
+            }
+        }
+        br.align();
+        Ok(())
+    }
+
+    fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize) {
+        let mut idx0 = 0;
+        let mut idx1 = w / 2;
+        let mut idx2 = (h / 2) * sstride;
+        let mut idx3 = idx2 + idx1;
+        let mut oidx0 = 0;
+        let mut oidx1 = dstride;
+
+        for _ in 0..(h/2) {
+            for x in 0..(w/2) {
+                let p0 = src[idx0 + x];
+                let p1 = src[idx1 + x];
+                let p2 = src[idx2 + x];
+                let p3 = src[idx3 + x];
+                dst[oidx0 + x * 2 + 0] = clip8(((p0 + p1 + p2 + p3 + 2) >> 2) + 128);
+                dst[oidx0 + x * 2 + 1] = clip8(((p0 + p1 - p2 - p3 + 2) >> 2) + 128);
+                dst[oidx1 + x * 2 + 0] = clip8(((p0 - p1 + p2 - p3 + 2) >> 2) + 128);
+                dst[oidx1 + x * 2 + 1] = clip8(((p0 - p1 - p2 + p3 + 2) >> 2) + 128);
+            }
+            idx0 += sstride;
+            idx1 += sstride;
+            idx2 += sstride;
+            idx3 += sstride;
+            oidx0 += dstride * 2;
+            oidx1 += dstride * 2;
+        }
+    }
+}
+
+struct Indeo4Decoder {
+    info:   Rc<NACodecInfo>,
+    dec:    IVIDecoder,
+}
+
+impl Indeo4Decoder {
+    fn new() -> Self {
+        Indeo4Decoder {
+            info:   NACodecInfo::new_dummy(),
+            dec:    IVIDecoder::new(),
+        }
+    }
+}
+
+impl NADecoder for Indeo4Decoder {
+    fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            let w = vinfo.get_width();
+            let h = vinfo.get_height();
+            let f = vinfo.is_flipped();
+            let fmt = formats::YUV410_FORMAT;
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, fmt));
+            self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        let mut br = BitReader::new(src.as_slice(), src.len(), BitReaderMode::LE);
+
+        let mut ip = Indeo4Parser::new();
+        let bufinfo = self.dec.decode_frame(&mut ip, &mut br)?;
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+        frm.set_keyframe(self.dec.is_intra());
+        frm.set_frame_type(self.dec.get_frame_type());
+        Ok(Rc::new(RefCell::new(frm)))
+    }
+}
+
+const INDEO4_PICTURE_SIZE_TAB: [[usize; 2]; 7] = [
+    [640, 480], [320, 240], [160, 120], [704, 480], [352, 240], [252, 288], [176, 144]
+];
+
+const INDEO4_SLICE_SIZE_TAB: [usize; 15] = [
+    32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480
+];
+
+const INDEO4_FRAME_TYPE: [IVIFrameType; 7] = [
+    IVIFrameType::Intra, IVIFrameType::Intra1, IVIFrameType::Inter, IVIFrameType::Bidir,
+    IVIFrameType::InterDroppable, IVIFrameType::NULL, IVIFrameType::NULL2
+];
+
+const INDEO4_TRANSFORMS: [IVITransformType; 18] = [
+    IVITransformType::Haar(TSize::T8x8, TDir::TwoD),
+    IVITransformType::Haar(TSize::T8x8, TDir::Row),
+    IVITransformType::Haar(TSize::T8x8, TDir::Col),
+    IVITransformType::None(TSize::T8x8),
+    IVITransformType::Slant(TSize::T8x8, TDir::TwoD),
+    IVITransformType::Slant(TSize::T8x8, TDir::Row),
+    IVITransformType::Slant(TSize::T8x8, TDir::Col),
+    IVITransformType::DCT(TSize::T8x8, TDir::TwoD),
+    IVITransformType::DCT(TSize::T8x8, TDir::Row),
+    IVITransformType::DCT(TSize::T8x8, TDir::Col),
+    IVITransformType::Haar(TSize::T4x4, TDir::TwoD),
+    IVITransformType::Slant(TSize::T4x4, TDir::TwoD),
+    IVITransformType::None(TSize::T4x4),
+    IVITransformType::Haar(TSize::T4x4, TDir::Row),
+    IVITransformType::Haar(TSize::T4x4, TDir::Col),
+    IVITransformType::Slant(TSize::T4x4, TDir::Row),
+    IVITransformType::Slant(TSize::T4x4, TDir::Col),
+    IVITransformType::DCT(TSize::T4x4, TDir::TwoD),
+];
+
+const INDEO4_SCAN_8X8_ALT: [usize; 64] = [
+     0,  8,  1,  9, 16, 24,  2,  3,
+    17, 25, 10, 11, 32, 40, 48, 56,
+     4,  5,  6,  7, 33, 41, 49, 57,
+    18, 19, 26, 27, 12, 13, 14, 15,
+    34, 35, 43, 42, 50, 51, 59, 58,
+    20, 21, 22, 23, 31, 30, 29, 28,
+    36, 37, 38, 39, 47, 46, 45, 44,
+    52, 53, 54, 55, 63, 62, 61, 60
+];
+const INDEO4_SCAN_4X4_ALT: [usize; 16] = [ 0, 1, 4, 5, 8, 12, 2, 3, 9, 13, 6, 7, 10, 11, 14, 15 ];
+const INDEO4_SCAN_4X4_VER: [usize; 16] = [ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 ];
+const INDEO4_SCAN_4X4_HOR: [usize; 16] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ];
+
+const INDEO4_SCANS_8X8: [&[usize; 64]; 5] = [
+    &IVI_ZIGZAG, &INDEO4_SCAN_8X8_ALT, &IVI_SCAN_8X8_HOR, &IVI_SCAN_8X8_VER, &IVI_ZIGZAG
+];
+const INDEO4_SCANS_4X4: [&[usize; 16]; 5] = [
+    &IVI_SCAN_4X4, &INDEO4_SCAN_4X4_ALT, &INDEO4_SCAN_4X4_VER, &INDEO4_SCAN_4X4_HOR, &IVI_SCAN_4X4
+];
+
+const INDEO4_Q8X8_IDX: [usize; 15] = [ 0, 1, 0, 2, 1, 3, 0, 4, 1, 5, 0, 1, 6, 7, 8 ];
+const INDEO4_Q4X4_IDX: [usize; 7] = [ 0, 1, 2, 2, 3, 3, 4 ];
+
+const INDEO4_QUANT8X8_INTRA: [[u16; 64]; 9] = [
+  [
+      43,  342,  385,  470,  555,  555,  598,  726,
+     342,  342,  470,  513,  555,  598,  726,  769,
+     385,  470,  555,  555,  598,  726,  726,  811,
+     470,  470,  555,  555,  598,  726,  769,  854,
+     470,  555,  555,  598,  683,  726,  854, 1025,
+     555,  555,  598,  683,  726,  854, 1025, 1153,
+     555,  555,  598,  726,  811,  982, 1195, 1451,
+     555,  598,  726,  811,  982, 1195, 1451, 1793
+  ], [
+      86, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+    1195, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+    2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+    2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+    4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+    4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+    4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+    4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827
+  ], [
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+     235, 1067, 1195, 1323, 1451, 1579, 1707, 1835
+  ], [
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+    1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414
+  ], [
+     897,  897,  897,  897,  897,  897,  897,  897,
+    1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067,
+    1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+    1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409,
+    1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579,
+    1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
+    1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921,
+    2091, 2091, 2091, 2091, 2091, 2091, 2091, 2091
+  ], [
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414
+  ], [
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+    2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390
+  ], [
+      22,  171,  214,  257,  257,  299,  299,  342,
+     171,  171,  257,  257,  299,  299,  342,  385,
+     214,  257,  257,  299,  299,  342,  342,  385,
+     257,  257,  257,  299,  299,  342,  385,  427,
+     257,  257,  299,  299,  342,  385,  427,  513,
+     257,  299,  299,  342,  385,  427,  513,  598,
+     299,  299,  299,  385,  385,  470,  598,  726,
+     299,  299,  385,  385,  470,  598,  726,  897
+  ], [
+      86,  598, 1195, 1195, 2390, 2390, 2390, 2390,
+     598,  598, 1195, 1195, 2390, 2390, 2390, 2390,
+    1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+    1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+    2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+    2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+    2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+    2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414
+  ]
+];
+const INDEO4_QUANT8X8_INTER: [[u16; 64]; 9] = [
+  [
+     427,  427,  470,  427,  427,  427,  470,  470,
+     427,  427,  470,  427,  427,  427,  470,  470,
+     470,  470,  470,  470,  470,  470,  470,  470,
+     427,  427,  470,  470,  427,  427,  470,  470,
+     427,  427,  470,  427,  427,  427,  470,  470,
+     427,  427,  470,  427,  427,  427,  470,  470,
+     470,  470,  470,  470,  470,  470,  470,  470,
+     470,  470,  470,  470,  470,  470,  470,  470
+  ], [
+    1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+    1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+    2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+    2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+    3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+    3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+    3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+    3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414
+  ], [
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+    1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281
+  ], [
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+    2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433
+  ], [
+    1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+    1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+    1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+    1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+    1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+    1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+    1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+    1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281
+  ], [
+    2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+    2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+    2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+    2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+    2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+    2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433
+  ], [
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+    1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707
+  ], [
+      86,  171,  171,  214,  214,  214,  214,  257,
+     171,  171,  214,  214,  214,  214,  257,  257,
+     171,  214,  214,  214,  214,  257,  257,  257,
+     214,  214,  214,  214,  257,  257,  257,  299,
+     214,  214,  214,  257,  257,  257,  299,  299,
+     214,  214,  257,  257,  257,  299,  299,  299,
+     214,  257,  257,  257,  299,  299,  299,  342,
+     257,  257,  257,  299,  299,  299,  342,  342
+  ], [
+     854,  854, 1195, 1195, 1707, 1707, 1707, 1707,
+     854,  854, 1195, 1195, 1707, 1707, 1707, 1707,
+    1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+    1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+    1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+    1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+    1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+    1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707
+  ]
+];
+const INDEO4_QUANT4X4_INTRA: [[u16; 16]; 5] = [
+  [
+      22,  214,  257,  299,
+     214,  257,  299,  342,
+     257,  299,  342,  427,
+     299,  342,  427,  513
+  ], [
+     129, 1025, 1451, 1451,
+    1025, 1025, 1451, 1451,
+    1451, 1451, 2049, 2049,
+    1451, 1451, 2049, 2049
+  ], [
+      43,  171,  171,  171,
+      43,  171,  171,  171,
+      43,  171,  171,  171,
+      43,  171,  171,  171
+  ], [
+      43,   43,   43,   43,
+     171,  171,  171,  171,
+     171,  171,  171,  171,
+     171,  171,  171,  171
+  ], [
+      43,   43,   43,   43,
+      43,   43,   43,   43,
+      43,   43,   43,   43,
+      43,   43,   43,   43
+  ]
+];
+const INDEO4_QUANT4X4_INTER: [[u16; 16]; 5] = [
+  [
+     107,  214,  257,  299,
+     214,  257,  299,  299,
+     257,  299,  299,  342,
+     299,  299,  342,  342
+  ], [
+     513, 1025, 1238, 1238,
+    1025, 1025, 1238, 1238,
+    1238, 1238, 1451, 1451,
+    1238, 1238, 1451, 1451
+  ], [
+      43,  171,  171,  171,
+      43,  171,  171,  171,
+      43,  171,  171,  171,
+      43,  171,  171,  171
+  ], [
+      43,   43,   43,   43,
+     171,  171,  171,  171,
+     171,  171,  171,  171,
+     171,  171,  171,  171
+  ], [
+      43,   43,   43,   43,
+      43,   43,   43,   43,
+      43,   43,   43,   43,
+      43,   43,   43,   43
+  ]
+];
+const INDEO4_Q8_INTRA: [&[u16; 64]; 9] = [
+    &INDEO4_QUANT8X8_INTRA[0], &INDEO4_QUANT8X8_INTRA[1], &INDEO4_QUANT8X8_INTRA[2],
+    &INDEO4_QUANT8X8_INTRA[3], &INDEO4_QUANT8X8_INTRA[4], &INDEO4_QUANT8X8_INTRA[5],
+    &INDEO4_QUANT8X8_INTRA[6], &INDEO4_QUANT8X8_INTRA[7], &INDEO4_QUANT8X8_INTRA[8],
+];
+const INDEO4_Q8_INTER: [&[u16; 64]; 9] = [
+    &INDEO4_QUANT8X8_INTER[0], &INDEO4_QUANT8X8_INTER[1], &INDEO4_QUANT8X8_INTER[2],
+    &INDEO4_QUANT8X8_INTER[3], &INDEO4_QUANT8X8_INTER[4], &INDEO4_QUANT8X8_INTER[5],
+    &INDEO4_QUANT8X8_INTER[6], &INDEO4_QUANT8X8_INTER[7], &INDEO4_QUANT8X8_INTER[8],
+];
+const INDEO4_Q4_INTRA: [&[u16; 16]; 5] = [
+    &INDEO4_QUANT4X4_INTRA[0], &INDEO4_QUANT4X4_INTRA[1], &INDEO4_QUANT4X4_INTRA[2],
+    &INDEO4_QUANT4X4_INTRA[3], &INDEO4_QUANT4X4_INTRA[4]
+];
+const INDEO4_Q4_INTER: [&[u16; 16]; 5] = [
+    &INDEO4_QUANT4X4_INTER[0], &INDEO4_QUANT4X4_INTER[1], &INDEO4_QUANT4X4_INTER[2],
+    &INDEO4_QUANT4X4_INTER[3], &INDEO4_QUANT4X4_INTER[4]
+];
+
+pub fn get_decoder() -> Box<NADecoder> {
+    Box::new(Indeo4Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use test::dec_video::test_file_decoding;
+    #[test]
+    fn test_indeo4() {
+         test_file_decoding("avi", "assets/IV4/volcano.avi", /*None*/Some(16), true, false, Some("iv4"));
+panic!("the end");
+    }
+}
diff --git a/src/codecs/indeo/indeo5.rs b/src/codecs/indeo/indeo5.rs
new file mode 100644 (file)
index 0000000..ae9113a
--- /dev/null
@@ -0,0 +1,727 @@
+use std::cell::Ref;
+use io::bitreader::*;
+use formats;
+use super::super::*;
+use super::ivi::*;
+use super::ivibr::*;
+
+fn calc_quant(glob_q: u32, qd: i16) -> usize {
+    let qq = (glob_q as i16) + (qd as i16);
+    if qq < 0 {
+        0
+    } else if qq > 23 {
+        23
+    } else {
+        qq as usize
+    }
+}
+
+struct Indeo5Parser {
+    mb_cb:          IVICodebook,
+
+    width:          usize,
+    height:         usize,
+    tile_w:         usize,
+    tile_h:         usize,
+    luma_bands:     usize,
+    chroma_bands:   usize,
+
+    is_hpel:        [bool; 5],
+    mb_size:        [usize; 5],
+    blk_size:       [usize; 5],
+}
+
+impl Indeo5Parser {
+    fn new() -> Self {
+        Indeo5Parser {
+            mb_cb:      IVI_CB_ZERO,
+
+            width:          0,
+            height:         0,
+            tile_w:         0,
+            tile_h:         0,
+            luma_bands:     0,
+            chroma_bands:   0,
+
+            is_hpel:    [false; 5],
+            mb_size:    [0; 5],
+            blk_size:   [0; 5],
+        }
+    }
+}
+
+fn skip_extension(br: &mut BitReader) -> DecoderResult<()> {
+    loop {
+        let len             = br.read(8)?;
+        if len == 0 { break; }
+        br.skip(len * 8)?;
+    }
+    Ok(())
+}
+
+impl IndeoXParser for Indeo5Parser {
+#[allow(unused_variables)]
+#[allow(unused_assignments)]
+    fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader> {
+        let sync                = br.read(5)?;
+        validate!(sync == 0x1F);
+        let ftype_idx           = br.read(3)?;
+        validate!(ftype_idx < 5);
+        let ftype               = INDEO5_FRAME_TYPE[ftype_idx as usize];
+        let fnum                = br.read(8)?;
+        if ftype == IVIFrameType::Intra {
+            let gop_flags       = br.read(8)?;
+            let hdr_size;
+            if (gop_flags & 0x01) != 0 {
+                hdr_size        = br.read(16)?;
+            } else {
+                hdr_size = 0;
+            }
+            if (gop_flags & 0x20) != 0 {
+                br.skip(32)?; // lock word
+            }
+            self.tile_w = 0;
+            self.tile_h = 0;
+            if (gop_flags & 0x40) != 0 {
+                self.tile_w     = 64 << br.read(2)?;
+                self.tile_h = self.tile_w;
+            }
+            validate!(self.tile_w < 256);
+            self.luma_bands     = (br.read(2)? * 3 + 1) as usize;
+            self.chroma_bands   = (br.read(1)? * 3 + 1) as usize;
+            validate!((self.luma_bands == 4) || (self.luma_bands == 1));
+            validate!(self.chroma_bands == 1);
+            let pic_size_idx    = br.read(4)? as usize;
+            let w;
+            let h;
+            if pic_size_idx < 15 {
+                w = INDEO5_PICTURE_SIZE_TAB[pic_size_idx][0];
+                h = INDEO5_PICTURE_SIZE_TAB[pic_size_idx][1];
+            } else {
+                h               = br.read(13)? as usize;
+                w               = br.read(13)? as usize;
+            }
+            validate!((w != 0) && (h != 0));
+            self.width  = w;
+            self.height = h;
+
+            validate!((gop_flags & 0x02) == 0);
+            if self.tile_w == 0 {
+                self.tile_w = w;
+                self.tile_h = h;
+            }
+            for b in 0..self.luma_bands+self.chroma_bands {
+                self.is_hpel[b]     = br.read_bool()?;
+                let mb_scale        = br.read(1)?;
+                self.blk_size[b]    = 8 >> br.read(1)?;
+                self.mb_size[b]     = self.blk_size[b] << (1 - mb_scale);
+                let ext_tr          = br.read_bool()?;
+                validate!(!ext_tr);
+                let end_marker      = br.read(2)?;
+                validate!(end_marker == 0);
+            }
+            if (gop_flags & 0x08) != 0 {
+                let align       = br.read(3)?;
+                validate!(align == 0);
+                if br.read_bool()? {
+                    br.skip(24)?; // transparency color
+                }
+            }
+            br.align();
+            br.skip(23)?;
+            if br.read_bool()? { // gop extension
+                loop {
+                    let v       = br.read(16)?;
+                    if (v & 0x8000) == 0 { break; }
+                }
+            }
+            br.align();
+        }
+        if ftype.is_null() {
+            br.align();
+            return Ok(PictureHeader::new_null(ftype));
+        }
+        let flags               = br.read(8)?;
+        let size;
+        if (flags & 0x01) != 0 {
+            size                = br.read(24)?;
+        } else {
+            size = 0;
+        }
+        let checksum;
+        if (flags & 0x10) != 0 {
+            checksum            = br.read(16)?;
+        } else {
+            checksum = 0;
+        }
+        if (flags & 0x20) != 0 {
+            skip_extension(br)?;
+        }
+        let in_q = (flags & 0x08) != 0;
+        self.mb_cb              = br.read_ivi_codebook_desc(true, (flags & 0x40) != 0)?;
+        br.skip(3)?;
+        br.align();
+
+        Ok(PictureHeader::new(ftype, self.width, self.height, self.tile_w, self.tile_h, false, self.luma_bands, self.chroma_bands, in_q))
+    }
+
+#[allow(unused_variables)]
+    fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane_no: usize, band_no: usize) -> DecoderResult<BandHeader> {
+        let band_flags      = br.read(8)?;
+
+        if (band_flags & 0x01) != 0 {
+            br.align();
+            return Ok(BandHeader::new_empty(plane_no, band_no));
+        }
+        let inherit_mv = (band_flags & 0x02) != 0;
+        let has_qdelta = (band_flags & 0x04) != 0;
+        let inherit_qd = ((band_flags & 0x08) != 0) || !has_qdelta;
+        let data_size: usize;
+        if (band_flags & 0x80) != 0 {
+            data_size       = br.read(24)? as usize;
+        } else {
+            data_size = 0;
+        }
+        validate!(data_size <= ((br.left() / 8) as usize));
+
+        let num_corr: usize;
+        let mut corr_map: [u8; CORR_MAP_SIZE] = [0; CORR_MAP_SIZE];
+        if (band_flags & 0x10) != 0 {
+            num_corr = br.read(8)? as usize;
+            validate!(num_corr*2 <= CORR_MAP_SIZE);
+            for i in 0..num_corr*2 {
+                corr_map[i] = br.read(8)? as u8;
+            }
+        } else {
+            num_corr = 0;
+        }
+        let rvmap_idx;
+        if (band_flags & 0x40) != 0 {
+            rvmap_idx       = br.read(3)? as usize;
+        } else {
+            rvmap_idx = 8;
+        }
+        let blk_cb = br.read_ivi_codebook_desc(false, (band_flags & 0x80) != 0)?;
+        if br.read_bool()? {
+            br.skip(16)?; // checksum
+        }
+        let band_q          = br.read(5)?;
+        if (band_flags & 0x20) != 0 {
+            skip_extension(br)?;
+        }
+        br.align();
+
+        let tr;
+        let txtype;
+        let band_id = if plane_no == 0 { band_no } else { self.luma_bands };
+        match plane_no {
+            0 => {
+                    let scan = INDEO5_SCAN8X8[band_no];
+                    let qintra;
+                    let qinter;
+                    validate!(self.blk_size[band_id] == 8);
+                    match band_no {
+                        0 => {
+                                tr = IVITransformType::Slant(TSize::T8x8, TDir::TwoD);
+                                if self.luma_bands == 1 {
+                                    qintra = INDEO5_Q8_INTRA[0];
+                                    qinter = INDEO5_Q8_INTER[0];
+                                } else {
+                                    qintra = INDEO5_Q8_INTRA[1];
+                                    qinter = INDEO5_Q8_INTER[1];
+                                }
+                            },
+                        1 => {
+                                tr = IVITransformType::Slant(TSize::T8x8, TDir::Row);
+                                qintra = INDEO5_Q8_INTRA[2];
+                                qinter = INDEO5_Q8_INTER[2];
+                            },
+                        2 => {
+                                tr = IVITransformType::Slant(TSize::T8x8, TDir::Col);
+                                qintra = INDEO5_Q8_INTRA[3];
+                                qinter = INDEO5_Q8_INTER[3];
+                            },
+                        3 => {
+                                tr = IVITransformType::None(TSize::T8x8);
+                                qintra = INDEO5_Q8_INTRA[4];
+                                qinter = INDEO5_Q8_INTER[4];
+                            },
+                        _ => { unreachable!(); }
+                    };
+                    txtype = TxType::Transform8(TxParams8x8::new(qintra, qinter, scan));
+                },
+            1 | 2 => {
+                    validate!(self.blk_size[band_id] == 4);
+                    tr = IVITransformType::Slant(TSize::T4x4, TDir::TwoD);
+                    let scan = INDEO5_SCAN4X4;
+                    let qintra = INDEO5_Q4_INTRA;
+                    let qinter = INDEO5_Q4_INTER;
+                    txtype = TxType::Transform4(TxParams4x4::new(qintra, qinter, scan));
+                },
+            _ => { unreachable!(); }
+        };
+        
+        Ok(BandHeader::new(plane_no, band_no, self.mb_size[band_id], self.blk_size[band_id], self.is_hpel[band_id], inherit_mv, has_qdelta, inherit_qd, band_q, rvmap_idx, num_corr, corr_map, blk_cb, tr, txtype))
+    }
+
+    fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band: &BandHeader, tile: &mut IVITile, ref_tile: Option<Ref<IVITile>>, mv_scale: u8) -> DecoderResult<()> {
+        let mut mv_x = 0;
+        let mut mv_y = 0;
+        let band_id = if pic_hdr.luma_bands == 4 { band.band_no + 1 } else { 0 };
+        let mut mb_idx = 0;
+        for mb_y in 0..tile.mb_h {
+            for mb_x in 0..tile.mb_w {
+                let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
+                if !br.read_bool()? {
+                    if pic_hdr.ftype.is_intra() {
+                        mb.mtype = MBType::Intra;
+                    } else if band.inherit_mv {
+                        if let Some(ref tileref) = ref_tile {
+                            mb.mtype = tileref.mb[mb_idx].mtype;
+                        } else {
+                            return Err(DecoderError::MissingReference);
+                        }
+                    } else {
+                        mb.mtype = if br.read_bool()? { MBType::Inter } else { MBType::Intra };
+                    }
+                    if band.mb_size == band.blk_size {
+                        mb.cbp = br.read(1)? as u8;
+                    } else {
+                        mb.cbp = br.read(4)? as u8;
+                    }
+                    let q;
+                    if band.has_qdelta {
+                        if band.inherit_qd {
+                            if let Some(ref tileref) = ref_tile {
+                                mb.qd = tileref.mb[mb_idx].qd;
+                                q = calc_quant(band.quant, mb.qd);
+                            } else {
+                                return Err(DecoderError::MissingReference);
+                            }
+                        } else if (mb.cbp != 0) || ((band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q) {
+                            mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+                            q = calc_quant(band.quant, mb.qd);
+                        } else {
+                            q = band.quant as usize;
+                        }
+                    } else {
+                        q = band.quant as usize;
+                    }
+
+                    if mb.mtype == MBType::Intra {
+                        if band.blk_size == 8 {
+                            mb.q = INDEO5_QSCALE8_INTRA[band_id][q];
+                        } else {
+                            mb.q = INDEO5_QSCALE4_INTRA[q];
+                        }
+                    } else {
+                        if band.blk_size == 8 {
+                            mb.q = INDEO5_QSCALE8_INTER[band_id][q];
+                        } else {
+                            mb.q = INDEO5_QSCALE4_INTER[q];
+                        }
+                    }
+
+                    if mb.mtype != MBType::Intra {
+                        if band.inherit_mv {
+                            if let Some(ref tileref) = ref_tile {
+                                let mx = tileref.mb[mb_idx].mv_x;
+                                let my = tileref.mb[mb_idx].mv_y;
+                                if mv_scale == 0 {
+                                    mb.mv_x = mx;
+                                    mb.mv_y = my;
+                                } else {
+                                    mb.mv_x = scale_mv(mx, mv_scale);
+                                    mb.mv_y = scale_mv(my, mv_scale);
+                                }
+                            }
+                        } else {
+                            mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
+                            mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
+                            mb.mv_x = mv_x;
+                            mb.mv_y = mv_y;
+                        }
+                    }
+                } else {
+                    validate!(!pic_hdr.ftype.is_intra());
+                    mb.mtype = MBType::Inter;
+                    mb.cbp   = 0;
+                    mb.qd    = 0;
+                    if (band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q {
+                        mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+                        let q = calc_quant(band.quant, mb.qd);
+                        if mb.mtype == MBType::Intra {
+                            if band.blk_size == 8 {
+                                mb.q = INDEO5_QSCALE8_INTRA[band_id][q];
+                            } else {
+                                mb.q = INDEO5_QSCALE4_INTRA[q];
+                            }
+                        } else {
+                            if band.blk_size == 8 {
+                                mb.q = INDEO5_QSCALE8_INTER[band_id][q];
+                            } else {
+                                mb.q = INDEO5_QSCALE4_INTER[q];
+                            }
+                        }
+                    }
+                    if band.inherit_mv {
+                        if let Some(ref tileref) = ref_tile {
+                            let mx = tileref.mb[mb_idx].mv_x;
+                            let my = tileref.mb[mb_idx].mv_y;
+                            if mv_scale == 0 {
+                                mb.mv_x = mx;
+                                mb.mv_y = my;
+                            } else {
+                                mb.mv_x = scale_mv(mx, mv_scale);
+                                mb.mv_y = scale_mv(my, mv_scale);
+                            }
+                        }
+                    }
+                }
+                tile.mb[mb_idx] = mb;
+                mb_idx += 1;
+            }
+        }
+        br.align();
+        Ok(())
+    }
+
+    fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize) {
+        let mut idx0 = 0;
+        let mut idx1 = w / 2;
+        let mut idx2 = (h / 2) * sstride;
+        let mut idx3 = idx2 + idx1;
+        let mut bidx1 = idx1;
+        let mut bidx3 = idx3;
+        let mut oidx0 = 0;
+        let mut oidx1 = dstride;
+        let filt_lo = |a: i16, b: i16| a + b;
+        let filt_hi = |a: i16, b: i16, c: i16| a - b * 6 + c;
+
+        for _ in 0..(h/2) {
+            let mut b0_1 = src[idx0];
+            let mut b0_2 = src[idx0 + sstride];
+            let mut b1_1 = src[bidx1];
+            let mut b1_2 = src[idx1];
+            let mut b1_3 = filt_hi(b1_1, b1_2, src[idx1 + sstride]);
+            let mut b2_1;
+            let mut b2_2 = src[idx2];
+            let mut b2_3 = b2_2;
+            let mut b2_4;
+            let mut b2_5 = src[idx2 + sstride];
+            let mut b2_6 = b2_5;
+            let mut b3_1;
+            let mut b3_2 = src[bidx3];
+            let mut b3_3 = b3_2;
+            let mut b3_4;
+            let mut b3_5 = src[idx3];
+            let mut b3_6 = b3_5;
+            let mut b3_8 = filt_hi(b3_2, b3_5, src[idx3 + sstride]);
+            let mut b3_9 = b3_8;
+            let mut b3_7;
+
+            for x in 0..(w/2) {
+                b2_1 = b2_2;
+                b2_2 = b2_3;
+                b2_4 = b2_5;
+                b2_5 = b2_6;
+                b3_1 = b3_2;
+                b3_2 = b3_3;
+                b3_4 = b3_5;
+                b3_5 = b3_6;
+                b3_7 = b3_8;
+                b3_8 = b3_9;
+
+                let tmp0 = b0_1;
+                let tmp1 = b0_2;
+                b0_1 = src[idx0 + x + 1];
+                b0_2 = src[idx0 + x + 1 + sstride];
+                let mut p0 =  tmp0                       << 4;
+                let mut p1 = (tmp0 + b0_1)               << 3;
+                let mut p2 = (tmp0 + tmp1)               << 3;
+                let mut p3 = (tmp0 + tmp1 + b0_1 + b0_2) << 2;
+
+                let tmp0 = b1_1;
+                let tmp1 = b1_2;
+                let tmp2 = filt_lo(tmp0, tmp1);
+                let tmp3 = filt_hi(tmp0, tmp1, b1_3);
+                b1_2 = src[ idx1 + x + 1];
+                b1_1 = src[bidx1 + x + 1];
+                b1_3 = filt_hi(b1_1, b1_2, src[idx1 + x + 1 + sstride]);
+                p0 +=  tmp2                << 3;
+                p1 += (tmp2 + b1_1 + b1_2) << 2;
+                p2 +=  tmp3                << 2;
+                p3 += (tmp3 + b1_3)        << 1;
+
+                b2_3 = src[idx2 + x + 1];
+                b2_6 = src[idx2 + x + 1 + sstride];
+                let tmp0 = filt_lo(b2_1, b2_2);
+                let tmp1 = filt_hi(b2_1, b2_2, b2_3);
+                p0 +=  tmp0                              << 3;
+                p1 +=  tmp1                              << 2;
+                p2 += (tmp0 + filt_lo(b2_4, b2_5))       << 2;
+                p3 += (tmp1 + filt_hi(b2_4, b2_5, b2_6)) << 1;
+
+                b3_6 = src[idx3 + x + 1];
+                b3_3 = src[bidx3 + x + 1];
+                b3_9 = filt_hi(b3_3, b3_6, src[idx3 + x + 1 + sstride]);
+                let tmp0 = b3_1 + b3_4;
+                let tmp1 = b3_2 + b3_5;
+                let tmp2 = b3_3 + b3_6;
+                p0 += filt_lo(tmp0, tmp1)       << 2;
+                p1 += filt_hi(tmp0, tmp1, tmp2) << 1;
+                p2 += filt_lo(b3_7, b3_8)       << 1;
+                p3 += filt_hi(b3_7, b3_8, b3_9) << 0;
+
+                dst[oidx0 + x * 2 + 0] = clip8((p0 >> 6) + 128);
+                dst[oidx0 + x * 2 + 1] = clip8((p1 >> 6) + 128);
+                dst[oidx1 + x * 2 + 0] = clip8((p2 >> 6) + 128);
+                dst[oidx1 + x * 2 + 1] = clip8((p3 >> 6) + 128);
+            }
+            bidx1 = idx1;
+            bidx3 = idx3;
+            idx0 += sstride;
+            idx1 += sstride;
+            idx2 += sstride;
+            idx3 += sstride;
+            oidx0 += dstride * 2;
+            oidx1 += dstride * 2;
+        }
+    }
+}
+
+struct Indeo5Decoder {
+    info:   Rc<NACodecInfo>,
+    dec:    IVIDecoder,
+    ip:     Indeo5Parser,
+}
+
+impl Indeo5Decoder {
+    fn new() -> Self {
+        Indeo5Decoder {
+            info:   NACodecInfo::new_dummy(),
+            dec:    IVIDecoder::new(),
+            ip:     Indeo5Parser::new(),
+        }
+    }
+}
+
+impl NADecoder for Indeo5Decoder {
+    fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            let w = vinfo.get_width();
+            let h = vinfo.get_height();
+            let f = vinfo.is_flipped();
+            let fmt = formats::YUV410_FORMAT;
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, fmt));
+            self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        let mut br = BitReader::new(src.as_slice(), src.len(), BitReaderMode::LE);
+
+        let bufinfo = self.dec.decode_frame(&mut self.ip, &mut br)?;
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+        frm.set_keyframe(self.dec.is_intra());
+        frm.set_frame_type(self.dec.get_frame_type());
+        Ok(Rc::new(RefCell::new(frm)))
+    }
+}
+
+const INDEO5_PICTURE_SIZE_TAB: [[usize; 2]; 15] = [
+    [640, 480], [320, 240], [160, 120], [704, 480], [352, 240], [352, 288], [176, 144],
+    [240, 180], [640, 240], [704, 240], [80, 60], [88, 72], [0, 0], [0, 0], [0, 0]
+];
+
+const INDEO5_FRAME_TYPE: [IVIFrameType; 5] = [
+    IVIFrameType::Intra, IVIFrameType::Inter, IVIFrameType::InterScal,
+    IVIFrameType::InterDroppable, IVIFrameType::NULL,
+];
+
+const INDEO5_QUANT8X8_INTRA: [[u16; 64]; 5] = [
+  [
+    0x1a, 0x2e, 0x36, 0x42, 0x46, 0x4a, 0x4e, 0x5a,
+    0x2e, 0x32, 0x3e, 0x42, 0x46, 0x4e, 0x56, 0x6a,
+    0x36, 0x3e, 0x3e, 0x44, 0x4a, 0x54, 0x66, 0x72,
+    0x42, 0x42, 0x44, 0x4a, 0x52, 0x62, 0x6c, 0x7a,
+    0x46, 0x46, 0x4a, 0x52, 0x5e, 0x66, 0x72, 0x8e,
+    0x4a, 0x4e, 0x54, 0x62, 0x66, 0x6e, 0x86, 0xa6,
+    0x4e, 0x56, 0x66, 0x6c, 0x72, 0x86, 0x9a, 0xca,
+    0x5a, 0x6a, 0x72, 0x7a, 0x8e, 0xa6, 0xca, 0xfe,
+  ], [
+    0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
+    0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+    0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
+    0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+    0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
+    0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+    0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
+    0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+  ], [
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+  ], [
+    0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+    0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+    0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
+    0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+    0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+    0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+  ], [
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+  ]
+];
+const INDEO5_QUANT8X8_INTER: [[u16; 64]; 5] = [
+  [
+    0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
+    0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+    0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
+    0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+    0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
+    0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+    0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
+    0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+  ], [
+    0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
+    0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+    0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
+    0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+    0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
+    0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+    0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
+    0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+  ], [
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+    0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+  ], [
+    0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
+    0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+    0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+    0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+    0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
+    0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+    0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+    0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+  ], [
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+    0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+  ]
+];
+const INDEO5_QUANT4X4_INTRA: [u16; 16] = [
+    0x1e, 0x3e, 0x4a, 0x52,
+    0x3e, 0x4a, 0x52, 0x5e,
+    0x4a, 0x52, 0x5e, 0x7a,
+    0x52, 0x5e, 0x7a, 0x92
+];
+const INDEO5_QUANT4X4_INTER: [u16; 16] = [
+    0x1e, 0x3e, 0x4a, 0x52,
+    0x3e, 0x4a, 0x52, 0x56,
+    0x4a, 0x52, 0x56, 0x5e,
+    0x52, 0x56, 0x5e, 0x66
+];
+const INDEO5_Q8_INTRA: [&[u16; 64]; 5] = [
+    &INDEO5_QUANT8X8_INTRA[0], &INDEO5_QUANT8X8_INTRA[1], &INDEO5_QUANT8X8_INTRA[2],
+    &INDEO5_QUANT8X8_INTRA[3], &INDEO5_QUANT8X8_INTRA[4],
+];
+const INDEO5_Q8_INTER: [&[u16; 64]; 5] = [
+    &INDEO5_QUANT8X8_INTER[0], &INDEO5_QUANT8X8_INTER[1], &INDEO5_QUANT8X8_INTER[2],
+    &INDEO5_QUANT8X8_INTER[3], &INDEO5_QUANT8X8_INTER[4],
+];
+const INDEO5_Q4_INTRA: &[u16; 16] = &INDEO5_QUANT4X4_INTRA;
+const INDEO5_Q4_INTER: &[u16; 16] = &INDEO5_QUANT4X4_INTER;
+
+const INDEO5_SCAN8X8: [&[usize; 64]; 4] = [
+    &IVI_ZIGZAG, &IVI_SCAN_8X8_VER, &IVI_SCAN_8X8_HOR, &IVI_SCAN_8X8_HOR
+];
+const INDEO5_SCAN4X4: &[usize; 16] = &IVI_SCAN_4X4;
+
+const INDEO5_QSCALE8_INTRA: [[u8; 24]; 5] = [
+  [
+    0x0b, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20,
+    0x22, 0x24, 0x27, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x37, 0x39, 0x3c,
+  ], [
+    0x01, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x28, 0x2c,
+    0x30, 0x34, 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x52, 0x58, 0x5e, 0x65, 0x6c,
+  ], [
+    0x13, 0x22, 0x27, 0x2a, 0x2d, 0x33, 0x36, 0x3c, 0x41, 0x45, 0x49, 0x4e,
+    0x53, 0x58, 0x5d, 0x63, 0x69, 0x6f, 0x75, 0x7c, 0x82, 0x88, 0x8e, 0x95,
+  ], [
+    0x13, 0x1f, 0x21, 0x24, 0x27, 0x29, 0x2d, 0x2f, 0x34, 0x37, 0x3a, 0x3d,
+    0x40, 0x44, 0x48, 0x4c, 0x4f, 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6b,
+  ], [
+    0x31, 0x42, 0x47, 0x47, 0x4d, 0x52, 0x58, 0x58, 0x5d, 0x63, 0x67, 0x6b,
+    0x6f, 0x73, 0x78, 0x7c, 0x80, 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa4,
+  ]
+];
+const INDEO5_QSCALE8_INTER: [[u8; 24]; 5] = [
+  [
+    0x0b, 0x11, 0x13, 0x14, 0x15, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x20, 0x22,
+    0x23, 0x25, 0x28, 0x2a, 0x2e, 0x32, 0x35, 0x39, 0x3d, 0x41, 0x44, 0x4a,
+  ], [
+    0x07, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
+    0x3a, 0x3f, 0x44, 0x4a, 0x50, 0x56, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x7e,
+  ], [
+    0x15, 0x25, 0x28, 0x2d, 0x30, 0x34, 0x3a, 0x3d, 0x42, 0x48, 0x4c, 0x51,
+    0x56, 0x5b, 0x60, 0x65, 0x6b, 0x70, 0x76, 0x7c, 0x82, 0x88, 0x8f, 0x97,
+  ], [
+    0x13, 0x1f, 0x20, 0x22, 0x25, 0x28, 0x2b, 0x2d, 0x30, 0x33, 0x36, 0x39,
+    0x3c, 0x3f, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x62,
+  ], [
+    0x3c, 0x52, 0x58, 0x5d, 0x63, 0x68, 0x68, 0x6d, 0x73, 0x78, 0x7c, 0x80,
+    0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa3, 0xa9, 0xad, 0xb1, 0xb5, 0xba
+  ]
+];
+const INDEO5_QSCALE4_INTRA: [u8; 24] = [
+    0x01, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x13, 0x14,
+    0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+];
+const INDEO5_QSCALE4_INTER: [u8; 24] = [
+    0x0b, 0x0d, 0x0d, 0x0e, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+    0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
+];
+
+pub fn get_decoder() -> Box<NADecoder> {
+    Box::new(Indeo5Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use test::dec_video::test_file_decoding;
+    #[test]
+    fn test_indeo5() {
+         test_file_decoding("avi", "assets/IV5/sample.avi", /*None*/Some(2), true, false, None);
+//         test_file_decoding("avi", "assets/IV5/W32mdl_1.avi", None/*Some(2)*/, true, false, Some("iv5"));
+//panic!("the end");
+    }
+}
diff --git a/src/codecs/indeo/ivi.rs b/src/codecs/indeo/ivi.rs
new file mode 100644 (file)
index 0000000..064da0b
--- /dev/null
@@ -0,0 +1,287 @@
+use super::ivibr::{IVICodebook,IVI_CB_ZERO,RVMap,IVI_ZERO_RVMAP,IVI_RVMAPS};
+
+pub fn clip8(a: i16) -> u8 {
+    if a < 0 { 0 }
+    else if a > 255 { 255 }
+    else { a as u8 }
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum IVIFrameType {
+    Intra,
+    Inter,
+    Bidir,
+    Intra1,
+    InterDroppable,
+    InterScal,
+    NULL,
+    NULL2,
+}
+
+impl IVIFrameType {
+    pub fn is_intra(self) -> bool {
+        (self == IVIFrameType::Intra) || (self == IVIFrameType::Intra1)
+    }
+    pub fn is_null(self) -> bool {
+        (self == IVIFrameType::NULL) || (self == IVIFrameType::NULL2)
+    }
+    pub fn is_bidir(self) -> bool {
+        self == IVIFrameType::Bidir
+    }
+}
+
+#[derive(Clone,Copy)]
+pub struct PictureHeader {
+    pub ftype:          IVIFrameType,
+    pub width:          usize,
+    pub height:         usize,
+    pub slice_w:        usize,
+    pub slice_h:        usize,
+    pub transparent:    bool,
+    pub luma_bands:     usize,
+    pub chroma_bands:   usize,
+    pub in_q:           bool,
+}
+
+impl PictureHeader {
+    pub fn new(ftype: IVIFrameType, width: usize, height: usize, slice_w: usize, slice_h: usize, transparent: bool, luma_bands: usize, chroma_bands: usize, in_q: bool) -> Self {
+        PictureHeader {
+            ftype: ftype,
+            width: width, height: height, slice_w: slice_w, slice_h: slice_h,
+            transparent: transparent,
+            luma_bands: luma_bands, chroma_bands: chroma_bands,
+            in_q: in_q,
+        }
+    }
+    pub fn new_null(ftype: IVIFrameType) -> Self {
+        PictureHeader {
+            ftype: ftype,
+            width: 0, height: 0, slice_w: 0, slice_h: 0,
+            transparent: false,
+            luma_bands: 0, chroma_bands: 0,
+            in_q: false,
+        }
+    }
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum TSize {
+    T8x8,
+    T4x4,
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum TDir {
+    TwoD,
+    Row,
+    Col,
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum IVITransformType {
+    Haar (TSize, TDir),
+    Slant(TSize, TDir),
+    DCT  (TSize, TDir),
+    None (TSize),
+}
+
+pub type TrFunc   = fn (&mut [i32; 64]);
+pub type TrFuncDC = fn (&mut [i32; 64], i32);
+
+impl IVITransformType {
+    pub fn is_8x8(&self) -> bool {
+        match *self {
+            IVITransformType::Haar (ref sz, _) => { *sz == TSize::T8x8 },
+            IVITransformType::Slant(ref sz, _) => { *sz == TSize::T8x8 },
+            IVITransformType::DCT  (ref sz, _) => { *sz == TSize::T8x8 },
+            IVITransformType::None (ref sz)    => { *sz == TSize::T8x8 },
+        }
+    }
+    pub fn is_2d(&self) -> bool {
+        match *self {
+            IVITransformType::Haar (_, ref dir) => { *dir == TDir::TwoD },
+            IVITransformType::Slant(_, ref dir) => { *dir == TDir::TwoD },
+            IVITransformType::DCT  (_, ref dir) => { *dir == TDir::TwoD },
+            _                                   => { false },
+        }
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct TxParams4x4 {
+    pub quant_intra:    &'static [u16; 16],
+    pub quant_inter:    &'static [u16; 16],
+    pub scan:           &'static [usize; 16],
+}
+
+impl TxParams4x4 {
+    pub fn new(quant_intra: &'static [u16; 16], quant_inter: &'static [u16; 16], scan: &'static [usize; 16]) -> Self {
+        TxParams4x4 {
+            quant_intra: quant_intra, quant_inter: quant_inter, scan: scan,
+        }
+    }
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct TxParams8x8 {
+    pub quant_intra:    &'static [u16; 64],
+    pub quant_inter:    &'static [u16; 64],
+    pub scan:           &'static [usize; 64],
+}
+
+impl TxParams8x8 {
+    pub fn new(quant_intra: &'static [u16; 64], quant_inter: &'static [u16; 64], scan: &'static [usize; 64]) -> Self {
+        TxParams8x8 {
+            quant_intra: quant_intra, quant_inter: quant_inter, scan: scan,
+        }
+    }
+}
+
+#[derive(Clone)]
+pub enum TxType {
+    Transform4(TxParams4x4),
+    Transform8(TxParams8x8),
+    None,
+}
+
+pub const CORR_MAP_SIZE: usize = 122;
+
+#[derive(Clone)]
+pub struct BandHeader {
+    pub plane_no:   usize,
+    pub band_no:    usize,
+    pub empty:      bool,
+    pub mb_size:    usize,
+    pub blk_size:   usize,
+    pub halfpel:    bool,
+    pub inherit_mv: bool,
+    pub has_qdelta: bool,
+    pub inherit_qd: bool,
+    pub quant:      u32,
+    pub blk_cb:     IVICodebook,
+    pub rvmap:      RVMap,
+    pub tr:         IVITransformType,
+    pub ttype:      TxType,
+}
+
+impl BandHeader {
+    pub fn new(plane_no: usize, band_no: usize, mb_size: usize, blk_size: usize, halfpel: bool, inherit_mv: bool, has_qdelta: bool, inherit_qd: bool, quant: u32, rvmap_idx: usize, num_corr: usize, corr_map: [u8; CORR_MAP_SIZE], blk_cb: IVICodebook, tr: IVITransformType, ttype: TxType) -> Self {
+        let mut rvmap = IVI_RVMAPS[rvmap_idx].clone();
+        for i in 0..num_corr {
+            let pos1 = corr_map[i * 2 + 0] as usize;
+            let pos2 = corr_map[i * 2 + 1] as usize;
+            let t              = rvmap.runtab[pos1];
+            rvmap.runtab[pos1] = rvmap.runtab[pos2];
+            rvmap.runtab[pos2] = t;
+            let t              = rvmap.valtab[pos1];
+            rvmap.valtab[pos1] = rvmap.valtab[pos2];
+            rvmap.valtab[pos2] = t;
+        }
+        BandHeader {
+            plane_no: plane_no, band_no: band_no,
+            empty: false, halfpel: halfpel,
+            inherit_mv: inherit_mv,
+            has_qdelta: has_qdelta, inherit_qd: inherit_qd, quant: quant,
+            mb_size: mb_size, blk_size: blk_size,
+            rvmap: rvmap, blk_cb: blk_cb,
+            tr: tr, ttype: ttype,
+        }
+    }
+    pub fn new_empty(plane_no: usize, band_no: usize) -> Self {
+        BandHeader {
+            plane_no: plane_no, band_no: band_no,
+            empty: true, halfpel: true,
+            inherit_mv: false, has_qdelta: false, inherit_qd: false, quant: 0,
+            mb_size: 0, blk_size: 0,
+            rvmap: IVI_ZERO_RVMAP, blk_cb: IVI_CB_ZERO,
+            tr: IVITransformType::None(TSize::T8x8), ttype: TxType::None,
+        }
+    }
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum MBType {
+    Intra,
+    Inter,
+    Backward,
+    Bidir,
+}
+
+#[derive(Clone,Copy)]
+pub struct MB {
+    pub mtype:  MBType,
+    pub pos_x:  usize,
+    pub pos_y:  usize,
+    pub mv_x:   i32,
+    pub mv_y:   i32,
+    pub mv2_x:  i32,
+    pub mv2_y:  i32,
+    pub qd:     i16,
+    pub q:      u8,
+    pub cbp:    u8,
+}
+
+impl MB {
+    pub fn new(x: usize, y: usize) -> Self {
+        MB {
+            mtype: MBType::Intra,
+            pos_x: x, pos_y: y,
+            mv_x: 0, mv_y: 0,
+            mv2_x: 0, mv2_y: 0,
+            cbp: 0, q: 0, qd: 0,
+        }
+    }
+}
+
+pub struct IVITile {
+    pub pos_x:  usize,
+    pub pos_y:  usize,
+    pub mb_w:   usize,
+    pub mb_h:   usize,
+    pub w:      usize,
+    pub h:      usize,
+    pub mb:     Vec<MB>,
+}
+
+impl IVITile {
+    pub fn new(pos_x: usize, pos_y: usize, w: usize, h: usize) -> Self {
+        IVITile {
+            pos_x: pos_x, pos_y: pos_y, w: w, h: h,
+            mb_w: 0, mb_h: 0, mb: Vec::new(),
+        }
+    }
+}
+
+pub const IVI_ZIGZAG: [usize; 64] = [
+     0,  1,  8, 16,  9,  2,  3, 10,
+    17, 24, 32, 25, 18, 11,  4,  5,
+    12, 19, 26, 33, 40, 48, 41, 34,
+    27, 20, 13,  6,  7, 14, 21, 28,
+    35, 42, 49, 56, 57, 50, 43, 36,
+    29, 22, 15, 23, 30, 37, 44, 51,
+    58, 59, 52, 45, 38, 31, 39, 46,
+    53, 60, 61, 54, 47, 55, 62, 63
+];
+pub const IVI_SCAN_8X8_VER: [usize; 64] = [
+    0,  8, 16, 24, 32, 40, 48, 56,
+    1,  9, 17, 25, 33, 41, 49, 57,
+    2, 10, 18, 26, 34, 42, 50, 58,
+    3, 11, 19, 27, 35, 43, 51, 59,
+    4, 12, 20, 28, 36, 44, 52, 60,
+    5, 13, 21, 29, 37, 45, 53, 61,
+    6, 14, 22, 30, 38, 46, 54, 62,
+    7, 15, 23, 31, 39, 47, 55, 63
+];
+pub const IVI_SCAN_8X8_HOR: [usize; 64] = [
+     0,  1,  2,  3,  4,  5,  6,  7,
+     8,  9, 10, 11, 12, 13, 14, 15,
+    16, 17, 18, 19, 20, 21, 22, 23,
+    24, 25, 26, 27, 28, 29, 30, 31,
+    32, 33, 34, 35, 36, 37, 38, 39,
+    40, 41, 42, 43, 44, 45, 46, 47,
+    48, 49, 50, 51, 52, 53, 54, 55,
+    56, 57, 58, 59, 60, 61, 62, 63
+];
+pub const IVI_SCAN_4X4: [usize; 16] = [ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 ];
diff --git a/src/codecs/indeo/ivibr.rs b/src/codecs/indeo/ivibr.rs
new file mode 100644 (file)
index 0000000..35e1781
--- /dev/null
@@ -0,0 +1,1247 @@
+use std::mem;
+use std::rc::Rc;
+use std::cell::{Ref,RefCell};
+use io::bitreader::*;
+use io::intcode::*;
+use super::super::*;
+use formats::*;
+use super::ivi::*;
+use super::ividsp::*;
+
+pub fn scale_mv(val: i32, scale: u8) -> i32 {
+    (val + (if val > 0 { 1 } else { 0 }) + (scale as i32) - 1) >> scale
+}
+
+#[derive(Clone,Copy)]
+pub struct IVICodebook {
+    len:    usize,
+    bits:   [u8; 16],
+//    offs:   [u32; 16],
+}
+
+/*impl IVICodebook {
+    pub fn init(&self) -> Self {
+        let mut cb = self;
+        let mut base: u32 = 0;
+        for i in 0..cb.len {
+            cb.offs[i] = base;
+            base += 1 << cb.bits[i];
+        }
+        cb
+    }
+}*/
+
+pub const IVI_CB_ZERO: IVICodebook = IVICodebook { len: 0, bits: [0; 16] };
+
+pub trait IVICodebookReader {
+    fn read_ivi_codebook_desc(&mut self, mb_cb: bool, try_default: bool) -> DecoderResult<IVICodebook>;
+    fn read_ivi_cb(&mut self, cb: &IVICodebook) -> BitReaderResult<u32>;
+    fn read_ivi_cb_s(&mut self, cb: &IVICodebook) -> BitReaderResult<i32>;
+}
+
+impl<'a> IVICodebookReader for BitReader<'a> {
+    fn read_ivi_codebook_desc(&mut self, mb_cb: bool, desc_coded: bool) -> DecoderResult<IVICodebook> {
+        if !desc_coded {
+            if mb_cb {
+                Ok(IVI_MB_CB[7])
+            } else {
+                Ok(IVI_BLK_CB[7])
+            }
+        } else {
+            let idx = self.read(3)? as usize;
+            if idx != 7 {
+                if mb_cb {
+                    Ok(IVI_MB_CB[idx])
+                } else {
+                    Ok(IVI_BLK_CB[idx])
+                }
+            } else {
+                let mut cb = IVI_CB_ZERO;
+                cb.len = self.read(4)? as usize;
+                if cb.len == 0 { return Err(DecoderError::InvalidData); }
+                for i in 0..cb.len {
+                    cb.bits[i] = self.read(4)? as u8;
+                }
+                Ok(cb)
+            }
+        }
+    }
+    fn read_ivi_cb(&mut self, cb: &IVICodebook) -> BitReaderResult<u32> {
+        let pfx = if cb.len == 1 { 0 } else {self.read_code(UintCodeType::LimitedUnary((cb.len - 1) as u32, 0))? as usize };
+        let nbits = cb.bits[pfx];
+//todo: cache offsets or maybe convert to proper codebook
+        let mut base: u32 = 0;
+        for i in 0..pfx { base += 1 << cb.bits[i]; }
+        let rval = self.read(nbits)?;
+        let add = reverse_bits(rval, nbits);
+        Ok(base + add)
+    }
+    fn read_ivi_cb_s(&mut self, cb: &IVICodebook) -> BitReaderResult<i32> {
+        let v = self.read_ivi_cb(cb)?;
+        if v == 0 {
+            Ok(0)
+        } else {
+            let sign = (v & 1) == 1;
+            let val = (v >> 1) as i32;
+            if sign {
+                Ok(val + 1)
+            } else {
+                Ok(-val)
+            }
+        }
+    }
+}
+
+pub const IVI_MB_CB: &[IVICodebook; 8] = &[
+    IVICodebook { len:  8, bits: [ 0, 4, 5, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0 ] },
+    IVICodebook { len: 12, bits: [ 0, 2, 2, 3, 3, 3, 3, 5, 3, 2, 2, 2, 0, 0, 0, 0 ] },
+    IVICodebook { len: 12, bits: [ 0, 2, 3, 4, 3, 3, 3, 3, 4, 3, 2, 2, 0, 0, 0, 0 ] },
+    IVICodebook { len: 12, bits: [ 0, 3, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 0, 0, 0, 0 ] },
+    IVICodebook { len: 13, bits: [ 0, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1, 0, 0, 0 ] },
+    IVICodebook { len:  9, bits: [ 0, 4, 4, 4, 4, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0 ] },
+    IVICodebook { len: 10, bits: [ 0, 4, 4, 4, 4, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0 ] },
+    IVICodebook { len: 12, bits: [ 0, 4, 4, 4, 3, 3, 2, 3, 2, 2, 2, 2, 0, 0, 0, 0 ] }
+];
+
+pub const IVI_BLK_CB: &[IVICodebook; 8] = &[
+    IVICodebook { len: 10, bits: [ 1, 2, 3, 4, 4, 7, 5, 5, 4, 1, 0, 0, 0, 0, 0, 0 ] },
+    IVICodebook { len: 11, bits: [ 2, 3, 4, 4, 4, 7, 5, 4, 3, 3, 2, 0, 0, 0, 0, 0 ] },
+    IVICodebook { len: 12, bits: [ 2, 4, 5, 5, 5, 5, 6, 4, 4, 3, 1, 1, 0, 0, 0, 0 ] },
+    IVICodebook { len: 13, bits: [ 3, 3, 4, 4, 5, 6, 6, 4, 4, 3, 2, 1, 1, 0, 0, 0 ] },
+    IVICodebook { len: 11, bits: [ 3, 4, 4, 5, 5, 5, 6, 5, 4, 2, 2, 0, 0, 0, 0, 0 ] },
+    IVICodebook { len: 13, bits: [ 3, 4, 5, 5, 5, 5, 6, 4, 3, 3, 2, 1, 1, 0, 0, 0 ] },
+    IVICodebook { len: 13, bits: [ 3, 4, 5, 5, 5, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0 ] },
+    IVICodebook { len:  9, bits: [ 3, 4, 4, 5, 5, 5, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0 ] }
+];
+
+#[allow(unused_variables)]
+fn read_trans_band_header(br: &mut BitReader, w: usize, h: usize, dst: &mut [i16], dstride: usize) -> DecoderResult<()> {
+    let color_plane     = br.read(2)?;
+    let bit_depth       = br.read(3)?;
+    let dirty_rects     = br.read(8)? as usize;
+    for i in 0..dirty_rects {
+        let x = br.read(16)?;
+        let y = br.read(16)?;
+        let l = br.read(16)?;
+        let r = br.read(16)?;
+    }
+    let has_trans_color = br.read_bool()?;
+    if has_trans_color {
+        let r = br.read(8)?;
+        let g = br.read(8)?;
+        let b = br.read(8)?;
+    }
+    
+    br.skip(1)?;
+
+    let mut cb = IVI_CB_ZERO;
+    cb.len = br.read(4)? as usize;
+    if cb.len == 0 { return Err(DecoderError::InvalidData); }
+    for i in 0..cb.len {
+        cb.bits[i] = br.read(4)? as u8;
+    }
+    br.align();
+
+let tile_start = br.tell();
+    let empty = br.read_bool()?;
+    if !empty {
+        br.read_bool()?;
+        let mut len = br.read(8)? as usize;
+        if len == 255 {
+           len = br.read(24)? as usize;
+        }
+        br.align();
+let tile_end = tile_start + len * 8;
+
+        let first_val = br.read_bool()?;
+
+        let mut dec_size = 0;
+        let mut x = 0;
+        let mut y = 0;
+        let mut fill = if !first_val { 255-128 } else { 0-128 };
+        let tr_w = (w + 31) & !31;
+        while br.tell() < tile_end {
+            let code = br.read_ivi_cb(&cb)? as usize;
+            if code == 0 {
+                dec_size += 255;
+                for _ in 0..255 {
+                    if (x < w) && (y < h) {
+                        dst[x + y * dstride] = fill;
+                    }
+                    x += 1;
+                    if x == tr_w {
+                        x = 0;
+                        y += 1;
+                    }
+                }
+            } else {
+                dec_size += code;
+                for _ in 0..code {
+                    if (x < w) && (y < h) {
+                        dst[x + y * dstride] = fill;
+                    }
+                    x += 1;
+                    if x == tr_w {
+                        x = 0;
+                        y += 1;
+                    }
+                }
+                fill = !fill;
+            }
+        }
+        br.align();
+    } else {
+    }
+
+    Ok(())
+}
+
+fn decode_block8x8(br: &mut BitReader, blk_cb: &IVICodebook, rvmap: &RVMap, tables: &TxParams8x8, is_intra: bool, is_2d: bool, prev_dc: &mut i32, quant: u8, coeffs: &mut [i32; 64], transform: &TrFunc) -> DecoderResult<()> {
+    let mut idx: isize = -1;
+    let quant_mat = if is_intra { tables.quant_intra } else { tables.quant_inter };
+    while idx <= 64 {
+        let c = br.read_ivi_cb(blk_cb)?;
+        if c == rvmap.eob_sym { break; }
+        let run;
+        let val: i32;
+        if c != rvmap.esc_sym {
+            validate!(c < 256);
+            run = rvmap.runtab[c as usize] as isize;
+            val = rvmap.valtab[c as usize] as i32;
+        } else {
+            run = (br.read_ivi_cb(blk_cb)? as isize) + 1;
+            let lo = br.read_ivi_cb(blk_cb)?;
+            let hi = br.read_ivi_cb(blk_cb)?;
+            let v = (hi << 6) + lo;
+            if v == 0 {
+                val = 0; // should not happen but still...
+            } else {
+                if (v & 1) != 0 {
+                    val = ((v >> 1) as i32) + 1;
+                } else {
+                    val = -((v >> 1) as i32);
+                }
+            }
+        }
+        idx += run;
+        validate!((idx >= 0) && (idx < 64));
+
+        let spos = tables.scan[idx as usize];
+        let q = ((quant_mat[spos] as u32) * (quant as u32)) >> 9;
+        if q > 1 {
+            let qq = q as i32;
+            let bias = (((q ^ 1) - 1) >> 1) as i32;
+            coeffs[spos] = val * qq;
+            if val > 0 { coeffs[spos] += bias; }
+            else       { coeffs[spos] -= bias; }
+        } else {
+            coeffs[spos] = val;
+        }
+    }
+    if is_intra && is_2d {
+        *prev_dc += coeffs[0];
+        coeffs[0] = *prev_dc;
+    }
+    (transform)(coeffs);
+    Ok(())
+}
+fn decode_block4x4(br: &mut BitReader, blk_cb: &IVICodebook, rvmap: &RVMap, tables: &TxParams4x4, is_intra: bool, is_2d: bool, prev_dc: &mut i32, quant: u8, coeffs: &mut [i32; 64], transform: &TrFunc) -> DecoderResult<()> {
+    let mut idx: isize = -1;
+    let quant_mat = if is_intra { tables.quant_intra } else { tables.quant_inter };
+    while idx <= 64 {
+        let c = br.read_ivi_cb(blk_cb)?;
+        if c == rvmap.eob_sym { break; }
+        let run;
+        let val: i32;
+        if c != rvmap.esc_sym {
+            validate!(c < 256);
+            run = rvmap.runtab[c as usize] as isize;
+            val = rvmap.valtab[c as usize] as i32;
+        } else {
+            run = (br.read_ivi_cb(blk_cb)? as isize) + 1;
+            let lo = br.read_ivi_cb(blk_cb)?;
+            let hi = br.read_ivi_cb(blk_cb)?;
+            let v = (hi << 5) + lo;
+            if v == 0 {
+                val = 0; // should not happen but still...
+            } else {
+                if (v & 1) != 0 {
+                    val = ((v >> 1) as i32) + 1;
+                } else {
+                    val = -((v >> 1) as i32);
+                }
+            }
+        }
+        idx += run;
+        validate!((idx >= 0) && (idx < 16));
+
+        let spos = tables.scan[idx as usize];
+        let q = ((quant_mat[spos] as u32) * (quant as u32)) >> 9;
+        if q > 1 {
+            let qq = q as i32;
+            let bias = (((q ^ 1) - 1) >> 1) as i32;
+            coeffs[spos] = val * qq;
+            if val > 0 { coeffs[spos] += bias; }
+            else       { coeffs[spos] -= bias; }
+        } else {
+            coeffs[spos] = val;
+        }
+    }
+    if is_intra && is_2d {
+        *prev_dc += coeffs[0];
+        coeffs[0] = *prev_dc;
+    }
+    (transform)(coeffs);
+    Ok(())
+}
+
+fn put_block(frame: &mut [i16], mut offs: usize, stride: usize, blk: &[i32], blk_size: usize) {
+    let mut idx = 0;
+    for _ in 0..blk_size {
+        for i in 0..blk_size {
+            let mut v = blk[idx + i];
+            if v < -32768 { v = -32768; }
+            if v > 32768 { v = 32767; }
+            frame[offs + i] = v as i16;
+        }
+        idx += blk_size;
+        offs += stride;
+    }
+}
+
+fn add_block(frame: &mut [i16], mut offs: usize, stride: usize, blk: &[i32], blk_size: usize) {
+    let mut idx = 0;
+    for _ in 0..blk_size {
+        for i in 0..blk_size {
+            let mut v = blk[idx + i];
+            if v < -32768 { v = -32768; }
+            if v > 32768 { v = 32767; }
+            frame[offs + i] += v as i16;
+        }
+        idx += blk_size;
+        offs += stride;
+    }
+}
+
+struct FrameData {
+    plane_buf:      [Vec<i16>; 4],
+    plane_stride:   [usize; 4],
+    pic_hdr:        PictureHeader,
+}
+
+fn align(val: usize, bits: u8) -> usize {
+    let mask = (1 << bits) - 1;
+    (val + mask) & !mask
+}
+
+impl FrameData {
+    fn new() -> Rc<RefCell<Self>> {
+        Rc::new(RefCell::new(FrameData {
+            plane_buf:      [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
+            plane_stride:   [0, 0, 0, 0],
+            pic_hdr:        PictureHeader::new_null(IVIFrameType::Intra),
+        }))
+    }
+    fn realloc(&mut self, pic_hdr: &PictureHeader) -> DecoderResult<()> {
+        let width  = align(pic_hdr.width,  6);
+        let height = align(pic_hdr.height, 6);
+
+        let stride = width;
+        self.plane_buf[0].resize(stride * height, 0);
+        self.plane_stride[0] = stride;
+        for plane in 1..3 {
+            self.plane_buf[plane].resize((stride >> 1) * (height >> 1), 0);
+            self.plane_stride[plane] = stride >> 1;
+        }
+        if pic_hdr.transparent {
+            self.plane_buf[3].resize(stride * height, 0);
+            self.plane_stride[3] = stride;
+        }
+        self.pic_hdr = *pic_hdr;
+        Ok(())
+    }
+    fn fill_plane(&mut self, vb: &mut NAVideoBuffer<u8>, plane: usize) {
+        let (w, h)   = vb.get_dimensions(plane);
+        let mut didx = vb.get_offset(plane);
+        let dstride  = vb.get_stride(plane);
+        let mut dst  = vb.get_data_mut();
+        let src      = &self.plane_buf[plane];
+        let mut sidx = 0;
+        let sstride  = self.plane_stride[plane];
+        for _ in 0..h {
+            for x in 0..w {
+                dst[didx + x] = clip8(src[sidx + x] + 128);
+            }
+            didx += dstride;
+            sidx += sstride;
+        }
+    }
+}
+
+fn do_mc(dst: &mut [i16], dstride: usize, src: &[i16], sstride: usize, x: usize, y: usize, l: usize, r: usize, t: usize, b: usize, mv_x: i32, mv_y: i32, is_hpel: bool, blk_size: usize) {
+    let (xoff, yoff, mv_mode) = if is_hpel {
+            (mv_x >> 1, mv_y >> 1, ((mv_x & 1) + (mv_y & 1) * 2) as u8)
+        } else{
+            (mv_x, mv_y, 0)
+        };
+    let xpos = (x as isize) + (xoff as isize);
+    let ypos = (y as isize) + (yoff as isize);
+    if (xpos < (l as isize)) || ((xpos as usize) + blk_size + ((mv_mode &  1) as usize) > r) ||
+       (ypos < (t as isize)) || ((ypos as usize) + blk_size + ((mv_mode >> 1) as usize) > b) {
+//println!(" copy from {},{} of {}-{},{}-{} {}x{}!", xpos, ypos, l,r,t,b,blk_size,blk_size);
+        return;
+    }
+    let sidx = (xpos as usize) + (ypos as usize) * sstride;
+    ivi_mc_put(dst, dstride, &src[sidx..], sstride, mv_mode, blk_size, blk_size);
+}
+
+fn do_mc_b(dst: &mut [i16], dstride: usize, src1: &[i16], sstride1: usize, src2: &[i16], sstride2: usize, x: usize, y: usize, l: usize, r: usize, t: usize, b: usize, mv_x: i32, mv_y: i32, mv2_x: i32, mv2_y: i32, is_hpel: bool, blk_size: usize) {
+    let (xoff1, yoff1, mv_mode1) = if is_hpel {
+            (mv_x >> 1, mv_y >> 1, ((mv_x & 1) + (mv_y & 1) * 2) as u8)
+        } else{
+            (mv_x, mv_y, 0)
+        };
+    let xpos1 = (x as isize) + (xoff1 as isize);
+    let ypos1 = (y as isize) + (yoff1 as isize);
+    if (xpos1 < (l as isize)) || ((xpos1 as usize) + blk_size + ((mv_mode1 &  1) as usize) > r) ||
+       (ypos1 < (t as isize)) || ((ypos1 as usize) + blk_size + ((mv_mode1 >> 1) as usize) > b) {
+        return;
+    }
+    let sidx1 = (xpos1 as usize) + (ypos1 as usize) * sstride1;
+    let (xoff2, yoff2, mv_mode2) = if is_hpel {
+            (mv2_x >> 1, mv2_y >> 1, ((mv2_x & 1) + (mv2_y & 1) * 2) as u8)
+        } else{
+            (mv2_x, mv2_y, 0)
+        };
+    let xpos2 = (x as isize) + (xoff2 as isize);
+    let ypos2 = (y as isize) + (yoff2 as isize);
+    if (xpos2 < (l as isize)) || ((xpos2 as usize) + blk_size + ((mv_mode2 &  1) as usize) > r) ||
+       (ypos2 < (t as isize)) || ((ypos2 as usize) + blk_size + ((mv_mode2 >> 1) as usize) > b) {
+        return;
+    }
+    let sidx2 = (xpos2 as usize) + (ypos2 as usize) * sstride2;
+    ivi_mc_avg(dst, dstride, &src1[sidx1..], sstride1, mv_mode1,  &src2[sidx2..], sstride2, mv_mode2, blk_size, blk_size);
+}
+
+pub trait IndeoXParser {
+    fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader>;
+    fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane: usize, band: usize) -> DecoderResult<BandHeader>;
+    fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band_hdr: &BandHeader, tile: &mut IVITile, ref_tile: Option<Ref<IVITile>>, mv_scale: u8) -> DecoderResult<()>;
+    fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize);
+}
+
+const MISSING_REF: usize = 42;
+
+pub struct IVIDecoder {
+    ftype:      IVIFrameType,
+    frames:     [Rc<RefCell<FrameData>>; 4],
+    cur_frame:  usize,
+    prev_frame: usize,
+    next_frame: usize,
+    iref_0:     usize,
+    iref_1:     usize,
+    scal_ref:   usize,
+    vinfo:      NAVideoInfo,
+    vinfoa:     NAVideoInfo,
+    bref:       Option<NABufferType>,
+
+    bands:      Vec<BandHeader>,
+    tiles:      Vec<Rc<RefCell<IVITile>>>,
+    num_tiles:  [[usize; 4]; 4],
+    tile_start: [[usize; 4]; 4],
+}
+
+impl IVIDecoder {
+    pub fn new() -> Self {
+        let mut bands: Vec<BandHeader> = Vec::with_capacity(12);
+        bands.resize(12, BandHeader::new_empty(42, 42));
+        IVIDecoder {
+            ftype:      IVIFrameType::NULL,
+            frames:     [FrameData::new(), FrameData::new(), FrameData::new(), FrameData::new()],
+            cur_frame: 0, prev_frame: MISSING_REF, next_frame: MISSING_REF,
+            iref_0: MISSING_REF, iref_1: MISSING_REF, scal_ref: MISSING_REF,
+            vinfo:  NAVideoInfo::new(0, 0, false, YUV410_FORMAT),
+            vinfoa: NAVideoInfo::new(0, 0, false, YUVA410_FORMAT),
+            bref: None,
+
+            bands: bands,
+            tiles: Vec::new(), tile_start: [[0; 4]; 4], num_tiles: [[0; 4]; 4],
+        }
+    }
+
+    fn realloc(&mut self, pic_hdr: &PictureHeader) -> DecoderResult<()> {
+        let planes = if pic_hdr.transparent { 4 } else { 3 };
+
+        //self.bands.truncate(0);
+        self.tiles.truncate(0);
+        self.num_tiles  = [[0; 4]; 4];
+        self.tile_start = [[0; 4]; 4];
+        let mut tstart: usize = 0;
+        for plane in 0..planes {
+            let is_luma = (plane != 1) && (plane != 2);
+            let bands = if is_luma { pic_hdr.luma_bands } else { pic_hdr.chroma_bands };
+            let mut band_w = if is_luma { pic_hdr.width   } else { (pic_hdr.width   + 3) >> 2 };
+            let mut band_h = if is_luma { pic_hdr.height  } else { (pic_hdr.height  + 3) >> 2 };
+            let mut tile_w = if is_luma { pic_hdr.slice_w } else { (pic_hdr.slice_w + 3) >> 2 };
+            let mut tile_h = if is_luma { pic_hdr.slice_h } else { (pic_hdr.slice_h + 3) >> 2 };
+            if bands > 1 {
+                band_w = (band_w + 1) >> 1;
+                band_h = (band_h + 1) >> 1;
+                if plane == 0 {
+                    tile_w = (tile_w + 1) >> 1;
+                    tile_h = (tile_h + 1) >> 1;
+                }
+            }
+            for band in 0..bands {
+                self.tile_start[plane][band] = tstart;
+                let band_xoff = if (band & 1) == 1 { band_w } else { 0 };
+                let band_yoff = if (band & 2) == 2 { band_h } else { 0 };
+                let mut y = 0;
+                while y < band_h {
+                    let cur_h = if y + tile_h <= band_h { tile_h } else { band_h - y };
+                    let mut x = 0;
+                    while x < band_w {
+                        let cur_w = if x + tile_w <= band_w { tile_w } else { band_w - x };
+                        let tile = IVITile::new(band_xoff + x, band_yoff + y, cur_w, cur_h);
+                        self.tiles.push(Rc::new(RefCell::new(tile)));
+                        self.num_tiles[plane][band] += 1;
+                        tstart += 1;
+                        x += tile_w;
+                    }
+                    y += tile_h;
+                }
+            }
+        }
+        Ok(())
+    }
+    fn decode_band(&mut self, pic_hdr: &PictureHeader, dec: &mut IndeoXParser, br: &mut BitReader, plane_no: usize, band_no: usize) -> DecoderResult<()> {
+        let bidx = match plane_no {
+            0 => { band_no },
+            _ => { pic_hdr.luma_bands + plane_no - 1 },
+        };
+        let prev_band = if bidx >= self.bands.len() { BandHeader::new_empty(plane_no, band_no) } else { self.bands[bidx].clone() };
+        let mut band = dec.decode_band_header(br, pic_hdr, plane_no, band_no)?;
+        if let TxType::None = band.ttype {
+            validate!(band.plane_no == prev_band.plane_no);
+            validate!(band.band_no  == prev_band.band_no);
+            validate!(band.blk_size == prev_band.blk_size);
+            band.tr    = prev_band.tr;
+            band.ttype = prev_band.ttype;
+        };
+
+        let tstart = self.tile_start[band.plane_no][band.band_no];
+        let tend   = tstart + self.num_tiles[band.plane_no][band.band_no];
+        let mb_size = band.mb_size;
+        let (tr, tr_dc) = match band.ttype {
+            TxType::Transform4(_) => { ivi_get_transform4x4_funcs(band.tr) },
+            TxType::Transform8(_) => { ivi_get_transform8x8_funcs(band.tr) },
+            _ => { ivi_get_transform4x4_funcs(band.tr) },
+        };
+        for tile_no in tstart..tend {
+            {
+                let mut tile = self.tiles[tile_no].borrow_mut();
+                let mb_w = (tile.w + mb_size - 1) / mb_size;
+                let mb_h = (tile.h + mb_size - 1) / mb_size;
+                tile.mb_w = mb_w;
+                tile.mb_h = mb_h;
+                tile.mb.truncate(0);
+                tile.mb.resize(mb_w * mb_h, MB::new(0, 0));
+            }
+
+            let tile_start = br.tell();
+            if !br.read_bool()? {
+                let res = br.read_bool()?;
+                validate!(res);
+                let mut len = br.read(8)? as usize;
+                if len == 255 {
+                    len = br.read(24)? as usize;
+                }
+                br.align();
+                validate!(len > 0);
+                let tile_end = tile_start + len * 8;
+                validate!(tile_end > br.tell());
+                validate!(tile_end <= br.tell() + (br.left() as usize));
+                {
+                    let mut tile = self.tiles[tile_no].borrow_mut();
+                    let ref_tile: Option<Ref<IVITile>>;
+                    let mv_scale;
+                    if (plane_no == 0) && (band_no == 0) {
+                        mv_scale = 0;
+                    } else {
+                        mv_scale = (((self.bands[0].mb_size >> 3) as i8) - ((band.mb_size >> 3) as i8)) as u8;
+                    }
+                    if plane_no != 0 || band_no != 0 {
+                        let rtile = self.tiles[0].borrow();
+                        if (tile.mb_w != rtile.mb_w) || (tile.mb_h != rtile.mb_h) {
+                            ref_tile = None;
+                        } else {
+                            ref_tile = Some(rtile);
+                        }
+                    } else {
+                        ref_tile = None;
+                    }
+                    dec.decode_mb_info(br, pic_hdr, &band, &mut tile, ref_tile, mv_scale)?;
+                }
+
+                self.decode_tile(br, &band, tile_no, &tr, &tr_dc)?;
+let skip_part = tile_end - br.tell();
+br.skip(skip_part as u32)?;
+            } else {
+                {
+                    let mut tile = self.tiles[tile_no].borrow_mut();
+                    let ref_tile: Option<Ref<IVITile>>;
+                    let mv_scale;
+                    if (plane_no == 0) && (band_no == 0) {
+                        mv_scale = 0;
+                    } else {
+                        mv_scale = (((self.bands[0].mb_size >> 3) as i8) - ((band.mb_size >> 3) as i8)) as u8;
+                    }
+                    if plane_no != 0 || band_no != 0 {
+                        let rtile = self.tiles[0].borrow();
+                        if (tile.mb_w != rtile.mb_w) || (tile.mb_h != rtile.mb_h) {
+                            ref_tile = None;
+                        } else {
+                            ref_tile = Some(rtile);
+                        }
+                    } else {
+                        ref_tile = None;
+                    }
+                    let mut mb_idx = 0;
+                    for mb_y in 0..tile.mb_h {
+                        for mb_x in 0..tile.mb_w {
+                            let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
+                            mb.mtype = MBType::Inter;
+                            mb.cbp   = 0;
+                            if band.inherit_mv {
+                                if let Some(ref tileref) = ref_tile {
+                                    let mx = tileref.mb[mb_idx].mv_x;
+                                    let my = tileref.mb[mb_idx].mv_y;
+                                    mb.mv_x = scale_mv(mx, mv_scale);
+                                    mb.mv_y = scale_mv(my, mv_scale);
+                                }
+                            }
+                            tile.mb[mb_idx] = mb;
+                            mb_idx += 1;
+                        }
+                    }
+                }
+                self.decode_tile(br, &band, tile_no, &tr, &tr_dc)?;
+            }
+        }
+        self.bands[bidx] = band;
+        br.align();
+        Ok(())
+    }
+    fn decode_tile(&mut self, br: &mut BitReader, band: &BandHeader, tile_no: usize, tr: &TrFunc, transform_dc: &TrFuncDC) -> DecoderResult<()> {
+        let mut mb_idx = 0;
+        let mut prev_dc: i32 = 0;
+        let mut tile = self.tiles[tile_no].borrow_mut();
+        let mut frame = self.frames[self.cur_frame].borrow_mut();
+
+        let stride = frame.plane_stride[band.plane_no];
+        let mut dstidx = tile.pos_x + tile.pos_y * stride;
+        let mut dst = &mut frame.plane_buf[band.plane_no];
+        let pos_x = tile.pos_x;
+        let pos_y = tile.pos_y;
+        let tile_w = (tile.w + 15) & !15;
+        let tile_h = (tile.h + 15) & !15;
+        for mb_y in 0..tile.mb_h {
+            for mb_x in 0..tile.mb_w {
+                let mb = &mut tile.mb[mb_idx];
+
+                let is_intra = mb.mtype == MBType::Intra;
+
+                if band.mb_size != band.blk_size {
+                    let mut cbp = mb.cbp;
+                    for blk_no in 0..4 {
+                        let mut blk: [i32; 64] = [0; 64];
+                        let boff = (blk_no & 1) * 8 + (blk_no & 2) * 4 * stride + mb_x * 16;
+                        if !is_intra {
+                            if mb.mtype != MBType::Bidir {
+                                let idx;
+                                if mb.mtype != MBType::Backward {
+                                    idx = self.prev_frame;
+                                } else {
+                                    idx = self.next_frame;
+                                }
+                                let pf = self.frames[idx].borrow();
+                                do_mc(&mut dst[dstidx + boff..], stride,
+                                      &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+                                      pos_x + mb_x * 16 + (blk_no & 1) * 8,
+                                      pos_y + mb_y * 16 + (blk_no & 2) * 4,
+                                      pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+                                      mb.mv_x, mb.mv_y, band.halfpel, 8);
+                            } else {
+                                let pf = self.frames[self.prev_frame].borrow();
+                                let nf = self.frames[self.next_frame].borrow();
+                                do_mc_b(&mut dst[dstidx + boff..], stride,
+                                      &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+                                      &nf.plane_buf[band.plane_no], nf.plane_stride[band.plane_no],
+                                      pos_x + mb_x * 16 + (blk_no & 1) * 8,
+                                      pos_y + mb_y * 16 + (blk_no & 2) * 4,
+                                      pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+                                      mb.mv_x, mb.mv_y, mb.mv2_x, mb.mv2_y, band.halfpel,
+                                      band.blk_size);
+                            }
+                        }
+                        if (cbp & 1) != 0 {
+                            if let TxType::Transform8(ref params) = band.ttype {
+                                decode_block8x8(br, &band.blk_cb, &band.rvmap, params, is_intra, band.tr.is_2d(), &mut prev_dc, mb.q, &mut blk, tr)?;
+                                if is_intra {
+                                    put_block(&mut dst, dstidx + boff, stride, &blk, 8);
+                                } else {
+                                    add_block(&mut dst, dstidx + boff, stride, &blk, 8);
+                                }
+                            }
+                        } else {
+                            if is_intra {
+                                (transform_dc)(&mut blk, prev_dc);
+                                put_block(&mut dst, dstidx + boff, stride, &blk, 8);
+                            }
+                        }
+                        cbp >>= 1;
+                    }
+                } else {
+                    let mut blk: [i32; 64] = [0; 64];
+                    if !is_intra {
+                        if mb.mtype != MBType::Bidir {
+                            let idx;
+                            if mb.mtype != MBType::Backward {
+                                idx = self.prev_frame;
+                            } else {
+                                idx = self.next_frame;
+                            }
+                            let pf = self.frames[idx].borrow();
+                            do_mc(&mut dst[dstidx + mb_x * band.blk_size..], stride,
+                                  &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+                                  pos_x + mb_x * band.mb_size,
+                                  pos_y + mb_y * band.mb_size,
+                                  pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+                                  mb.mv_x, mb.mv_y, band.halfpel, band.blk_size);
+                        } else {
+                            let pf = self.frames[self.prev_frame].borrow();
+                            let nf = self.frames[self.next_frame].borrow();
+                            do_mc_b(&mut dst[dstidx + mb_x * band.blk_size..], stride,
+                                    &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+                                    &nf.plane_buf[band.plane_no], nf.plane_stride[band.plane_no],
+                                    pos_x + mb_x * band.mb_size,
+                                    pos_y + mb_y * band.mb_size,
+                                    pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+                                    mb.mv_x, mb.mv_y, mb.mv2_x, mb.mv2_y, band.halfpel,
+                                    band.blk_size);
+                        }
+                    }
+                    if mb.cbp != 0 {
+                        if let TxType::Transform8(ref params) = band.ttype {
+                            decode_block8x8(br, &band.blk_cb, &band.rvmap, params, is_intra, band.tr.is_2d(), &mut prev_dc, mb.q, &mut blk, tr)?;
+                        }
+                        if let TxType::Transform4(ref params) = band.ttype {
+                            decode_block4x4(br, &band.blk_cb, &band.rvmap, params, is_intra, band.tr.is_2d(), &mut prev_dc, mb.q, &mut blk, tr)?;
+                        }
+                        if is_intra {
+                            put_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, band.blk_size);
+                        } else {
+                            add_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, band.blk_size);
+                        }
+                    } else {
+                        if is_intra {
+                            (transform_dc)(&mut blk, prev_dc);
+                            put_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, band.blk_size);
+                        }
+                    }
+                }
+                mb_idx += 1;
+            }
+            dstidx += stride * band.mb_size;
+        }
+        br.align();
+        Ok(())
+    }
+
+    fn find_unused_frame(&self) -> usize {
+        for fno in 0..4 {
+            if (fno != self.iref_0) && (fno != self.iref_1) && (fno != self.scal_ref) {
+                return fno;
+            }
+        }
+        unreachable!();
+    }
+
+    fn decode_single_frame<'a>(&mut self, dec: &mut IndeoXParser, br: &mut BitReader<'a>) -> DecoderResult<NABufferType> {
+        let pic_hdr = dec.decode_picture_header(br)?;
+        self.ftype = pic_hdr.ftype;
+        if pic_hdr.ftype.is_null() {
+            return Ok(NABufferType::None);
+        }
+
+        self.cur_frame = self.find_unused_frame();
+        match self.ftype {
+            IVIFrameType::Inter => {
+                    self.prev_frame = self.iref_0;
+                    if self.prev_frame == MISSING_REF {
+                        return Err(DecoderError::MissingReference);
+                    }
+                },
+            IVIFrameType::InterDroppable => {
+                    self.prev_frame = self.scal_ref;
+                    if self.prev_frame == MISSING_REF {
+                        return Err(DecoderError::MissingReference);
+                    }
+                },
+            IVIFrameType::InterScal => {
+                    self.prev_frame = self.scal_ref;
+                    if self.prev_frame == MISSING_REF {
+                        return Err(DecoderError::MissingReference);
+                    }
+                },
+            IVIFrameType::Bidir => {
+                    self.prev_frame = self.iref_1;
+                    self.next_frame = self.iref_0;
+                    if (self.prev_frame == MISSING_REF) || (self.next_frame == MISSING_REF) {
+                        return Err(DecoderError::MissingReference);
+                    }
+                },
+            _ => {},
+        };
+
+        let mut vinfo;
+        if pic_hdr.transparent {
+            vinfo = self.vinfoa.clone();
+        } else {
+            vinfo = self.vinfo.clone();
+        }
+        vinfo.set_width(pic_hdr.width);
+        vinfo.set_height(pic_hdr.height);
+        let mut buftype = alloc_video_buffer(vinfo, 0)?;
+        self.realloc(&pic_hdr)?;
+        self.frames[self.cur_frame].borrow_mut().realloc(&pic_hdr)?;
+
+        for plane in 0..3 {
+            let num_bands = if plane == 0 { pic_hdr.luma_bands } else { pic_hdr.chroma_bands };
+            for band in 0..num_bands {
+                self.decode_band(&pic_hdr, dec, br, plane, band)?;
+            }
+            if let NABufferType::Video(ref mut vb) = buftype {
+                let mut frame = self.frames[self.cur_frame].borrow_mut();
+                if num_bands == 1 {
+                    frame.fill_plane(vb, plane);
+                } else {
+                    let (w, h)  = vb.get_dimensions(plane);
+                    let dstride = vb.get_stride(plane);
+                    let off     = vb.get_offset(plane);
+                    let mut dst = vb.get_data_mut();
+                    dec.recombine_plane(&frame.plane_buf[plane], frame.plane_stride[plane], &mut dst[off..], dstride, w, h);
+                }
+            }
+        }
+        if pic_hdr.transparent {
+            let mut frame = self.frames[self.cur_frame].borrow_mut();
+            let stride = frame.plane_stride[3];
+            read_trans_band_header(br, pic_hdr.width, pic_hdr.height, &mut frame.plane_buf[3], stride)?;
+            if let NABufferType::Video(ref mut vb) = buftype {
+                frame.fill_plane(vb, 3);
+            }
+        }
+
+        match self.ftype {
+            IVIFrameType::Intra | IVIFrameType::Inter => {
+                    self.iref_1   = self.iref_0;
+                    self.iref_0   = self.cur_frame;
+                    self.scal_ref = self.cur_frame;
+                },
+            IVIFrameType::InterScal => {
+                    self.scal_ref = self.cur_frame;
+                },
+            _ => {},
+        };
+
+        Ok(buftype)
+    }
+
+    pub fn decode_frame<'a>(&mut self, dec: &mut IndeoXParser, br: &mut BitReader<'a>) -> DecoderResult<NABufferType> {
+        let res = self.decode_single_frame(dec, br);
+        if res.is_err() { return res; }
+        if (self.ftype == IVIFrameType::Intra) && (br.left() > 16) {
+            loop {
+                if br.left() < 8 { break; }
+                if br.read(8)? == 0 { break; }
+            }
+            loop {
+                if br.left() < 8 { break; }
+                if br.peek(8) != 0 { break; }
+                br.skip(8)?;
+            }
+            if br.left() > 24 {
+                let seq = br.peek(21);
+                if seq == 0xBFFF8 {
+                    let res2 = self.decode_single_frame(dec, br);
+                    if res2.is_ok() {
+                        self.bref = Some(res2.unwrap());
+                    }
+                }
+                self.ftype = IVIFrameType::Intra;
+            }
+        }
+        if let Ok(NABufferType::None) = res {
+            if self.bref.is_some() {
+                let mut bref: Option<NABufferType> = None;
+                mem::swap(&mut bref, &mut self.bref);
+                self.ftype = IVIFrameType::Inter;
+                return Ok(bref.unwrap());
+            }
+        }
+        res
+    }
+
+    pub fn is_intra(&mut self) -> bool {
+        self.ftype.is_intra()
+    }
+    pub fn get_frame_type(&mut self) -> FrameType {
+        match self.ftype {
+            IVIFrameType::Intra             => { FrameType::I },
+            IVIFrameType::Intra1            => { FrameType::I },
+            IVIFrameType::Inter             => { FrameType::P },
+            IVIFrameType::InterDroppable    => { FrameType::P },
+            IVIFrameType::InterScal         => { FrameType::P },
+            IVIFrameType::Bidir             => { FrameType::B },
+            _                               => { FrameType::Skip },
+        }
+    }
+}
+
+pub struct RVMap {
+    pub eob_sym:    u32,
+    pub esc_sym:    u32,
+    pub runtab:     [u8; 256],
+    pub valtab:     [i8; 256],
+}
+
+impl Clone for RVMap {
+    fn clone(&self) -> RVMap {
+        let mut runtab: [u8; 256] = [0; 256];
+        let mut valtab: [i8; 256] = [0; 256];
+        runtab.copy_from_slice(&self.runtab);
+        valtab.copy_from_slice(&self.valtab);
+        RVMap { eob_sym: self.eob_sym, esc_sym: self.esc_sym, runtab: runtab, valtab: valtab }
+    }
+}
+
+pub const IVI_ZERO_RVMAP: RVMap = RVMap { eob_sym: 0, esc_sym: 0, runtab: [0; 256], valtab: [0; 256] };
+
+pub static IVI_RVMAPS: [RVMap; 9] = [
+    RVMap { eob_sym: 5, esc_sym: 2, runtab: [
+     1,  1,  0,  1,  1,  0,  1,  1,  2,  2,  1,  1,  1,  1,  3,  3,
+     1,  1,  2,  2,  1,  1,  4,  4,  1,  1,  1,  1,  2,  2,  5,  5,
+     1,  1,  3,  3,  1,  1,  6,  6,  1,  2,  1,  2,  7,  7,  1,  1,
+     8,  8,  1,  1,  4,  2,  1,  4,  2,  1,  3,  3,  1,  1,  1,  9,
+     9,  1,  2,  1,  2,  1,  5,  5,  1,  1, 10, 10,  1,  1,  3,  3,
+     2,  2,  1,  1, 11, 11,  6,  4,  4,  1,  6,  1,  2,  1,  2, 12,
+     8,  1, 12,  7,  8,  7,  1, 16,  1, 16,  1,  3,  3, 13,  1, 13,
+     2,  2,  1, 15,  1,  5, 14, 15,  1,  5, 14,  1, 17,  8, 17,  8,
+     1,  4,  4,  2,  2,  1, 25, 25, 24, 24,  1,  3,  1,  3,  1,  8,
+     6,  7,  6,  1, 18,  8, 18,  1,  7, 23,  2,  2, 23,  1,  1, 21,
+    22,  9,  9, 22, 19,  1, 21,  5, 19,  5,  1, 33, 20, 33, 20,  8,
+     4,  4,  1, 32,  2,  2,  8,  3, 32, 26,  3,  1,  7,  7, 26,  6,
+     1,  6,  1,  1, 16,  1, 10,  1, 10,  2, 16, 29, 28,  2, 29, 28,
+     1, 27,  5,  8,  5, 27,  1,  8,  3,  7,  3, 31, 41, 31,  1, 41,
+     6,  1,  6,  7,  4,  4,  1,  1,  2,  1,  2, 11, 34, 30, 11,  1,
+    30, 15, 15, 34, 36, 40, 36, 40, 35, 35, 37, 37, 39, 39, 38, 38 ],
+        valtab: [
+      1,  -1,   0,   2,  -2,   0,   3,  -3,   1,  -1,   4,  -4,   5,  -5,   1,  -1,
+      6,  -6,   2,  -2,   7,  -7,   1,  -1,   8,  -8,   9,  -9,   3,  -3,   1,  -1,
+     10, -10,   2,  -2,  11, -11,   1,  -1,  12,   4, -12,  -4,   1,  -1,  13, -13,
+      1,  -1,  14, -14,   2,   5,  15,  -2,  -5, -15,  -3,   3,  16, -16,  17,   1,
+     -1, -17,   6,  18,  -6, -18,   2,  -2,  19, -19,   1,  -1,  20, -20,   4,  -4,
+      7,  -7,  21, -21,   1,  -1,   2,   3,  -3,  22,  -2, -22,   8,  23,  -8,   1,
+      2, -23,  -1,   2,  -2,  -2,  24,   1, -24,  -1,  25,   5,  -5,   1, -25,  -1,
+      9,  -9,  26,   1, -26,   3,   1,  -1,  27,  -3,  -1, -27,   1,   3,  -1,  -3,
+     28,  -4,   4,  10, -10, -28,   1,  -1,   1,  -1,  29,   6, -29,  -6,  30,  -4,
+      3,   3,  -3, -30,   1,   4,  -1,  31,  -3,   1,  11, -11,  -1, -31,  32,  -1,
+     -1,   2,  -2,   1,   1, -32,   1,   4,  -1,  -4,  33,  -1,   1,   1,  -1,   5,
+      5,  -5, -33,  -1, -12,  12,  -5,  -7,   1,   1,   7,  34,   4,  -4,  -1,   4,
+    -34,  -4,  35,  36,  -2, -35,  -2, -36,   2,  13,   2,  -1,   1, -13,   1,  -1,
+     37,   1,  -5,   6,   5,  -1,  38,  -6,  -8,   5,   8,  -1,   1,   1, -37,  -1,
+      5,  39,  -5,  -5,   6,  -6, -38, -39, -14,  40,  14,   2,   1,   1,  -2, -40,
+     -1,  -2,   2,  -1,  -1,  -1,   1,   1,   1,  -1,   1,  -1,   1,  -1,   1,  -1 ],
+    },
+    RVMap { eob_sym: 0, esc_sym: 38, runtab: [
+     0,  1,  1,  2,  2,  3,  3,  4,  4,  5,  5,  6,  8,  6,  8,  7,
+     7,  9,  9, 10, 10, 11, 11,  1, 12,  1, 12, 13, 13, 16, 14, 16,
+    14, 15, 15, 17, 17, 18,  0, 18, 19, 20, 21, 19, 22, 21, 20, 22,
+    25, 24,  2, 25, 24, 23, 23,  2, 26, 28, 26, 28, 29, 27, 29, 27,
+    33, 33,  1, 32,  1,  3, 32, 30, 36,  3, 36, 30, 31, 31, 35, 34,
+    37, 41, 34, 35, 37,  4, 41,  4, 49,  8,  8, 49, 40, 38,  5, 38,
+    40, 39,  5, 39, 42, 43, 42,  7, 57,  6, 43, 44,  6, 50,  7, 44,
+    57, 48, 50, 48, 45, 45, 46, 47, 51, 46, 47, 58,  1, 51, 58,  1,
+    52, 59, 53,  9, 52, 55, 55, 59, 53, 56, 54, 56, 54,  9, 64, 64,
+    60, 63, 60, 63, 61, 62, 61, 62,  2, 10,  2, 10, 11,  1, 11, 13,
+    12,  1, 12, 13, 16, 16,  8,  8, 14,  3,  3, 15, 14, 15,  4,  4,
+     1, 17, 17,  5,  1,  7,  7,  5,  6,  1,  2,  2,  6, 22,  1, 25,
+    21, 22,  8, 24,  1, 21, 25, 24,  8, 18, 18, 23,  9, 20, 23, 33,
+    29, 33, 20,  1, 19,  1, 29, 36,  9, 36, 19, 41, 28, 57, 32,  3,
+    28,  3,  1, 27, 49, 49,  1, 32, 26, 26,  2,  4,  4,  7, 57, 41,
+     2,  7, 10,  5, 37, 16, 10, 27,  8,  8, 13, 16, 37, 13,  1,  5 ],
+        valtab: [
+     0,   1,  -1,   1,  -1,   1,  -1,   1,  -1,   1,  -1,   1,   1,  -1,  -1,   1,
+    -1,   1,  -1,   1,  -1,   1,  -1,   2,   1,  -2,  -1,   1,  -1,   1,   1,  -1,
+    -1,   1,  -1,   1,  -1,   1,   0,  -1,   1,   1,   1,  -1,   1,  -1,  -1,  -1,
+     1,   1,   2,  -1,  -1,   1,  -1,  -2,   1,   1,  -1,  -1,   1,   1,  -1,  -1,
+     1,  -1,   3,   1,  -3,   2,  -1,   1,   1,  -2,  -1,  -1,  -1,   1,   1,   1,
+     1,   1,  -1,  -1,  -1,   2,  -1,  -2,   1,   2,  -2,  -1,   1,   1,   2,  -1,
+    -1,   1,  -2,  -1,   1,   1,  -1,   2,   1,   2,  -1,   1,  -2,  -1,  -2,  -1,
+    -1,   1,   1,  -1,   1,  -1,   1,   1,   1,  -1,  -1,   1,   4,  -1,  -1,  -4,
+     1,   1,   1,   2,  -1,  -1,   1,  -1,  -1,   1,  -1,  -1,   1,  -2,   1,  -1,
+     1,   1,  -1,  -1,   1,   1,  -1,  -1,   3,   2,  -3,  -2,   2,   5,  -2,   2,
+     2,  -5,  -2,  -2,  -2,   2,  -3,   3,   2,   3,  -3,   2,  -2,  -2,   3,  -3,
+     6,   2,  -2,   3,  -6,   3,  -3,  -3,   3,   7,  -4,   4,  -3,   2,  -7,   2,
+     2,  -2,  -4,   2,   8,  -2,  -2,  -2,   4,   2,  -2,   2,   3,   2,  -2,  -2,
+     2,   2,  -2,  -8,  -2,   9,  -2,   2,  -3,  -2,   2,  -2,   2,   2,   2,   4,
+    -2,  -4,  10,   2,   2,  -2,  -9,  -2,   2,  -2,   5,   4,  -4,   4,  -2,   2,
+    -5,  -4,  -3,   4,   2,  -3,   3,  -2,  -5,   5,   3,   3,  -2,  -3, -10,  -4 ],
+    },
+    RVMap { eob_sym: 2, esc_sym: 11, runtab: [
+     1,  1,  0,  2,  2,  1,  1,  3,  3,  4,  4,  0,  1,  1,  5,  5,
+     2,  2,  6,  6,  7,  7,  1,  8,  1,  8,  3,  3,  9,  9,  1,  2,
+     2,  1,  4, 10,  4, 10, 11, 11,  1,  5, 12, 12,  1,  5, 13, 13,
+     3,  3,  6,  6,  2,  2, 14, 14, 16, 16, 15,  7, 15,  8,  8,  7,
+     1,  1, 17, 17,  4,  4,  1,  1, 18, 18,  2,  2,  5,  5, 25,  3,
+     9,  3, 25,  9, 19, 24, 19, 24,  1, 21, 20,  1, 21, 22, 20, 22,
+    23, 23,  8,  6, 33,  6,  8, 33,  7,  7, 26, 26,  1, 32,  1, 32,
+    28,  4, 28, 10, 29, 27, 27, 10, 41,  4, 29,  2,  2, 41, 36, 31,
+    49, 31, 34, 30, 34, 36, 30, 35,  1, 49, 11,  5, 35, 11,  1,  3,
+     3,  5, 37, 37,  8, 40,  8, 40, 12, 12, 42, 42,  1, 38, 16, 57,
+     1,  6, 16, 39, 38,  6,  7,  7, 13, 13, 39, 43,  2, 43, 57,  2,
+    50,  9, 44,  9, 50,  4, 15, 48, 44,  4,  1, 15, 48, 14, 14,  1,
+    45, 45,  8,  3,  5,  8, 51, 47,  3, 46, 46, 47,  5, 51,  1, 17,
+    17, 58,  1, 58,  2, 52, 52,  2, 53,  7, 59,  6,  6, 56, 53, 55,
+     7, 55,  1, 54, 59, 56, 54, 10,  1, 10,  4, 60,  1, 60,  8,  4,
+     8, 64, 64, 61,  1, 63,  3, 63, 62, 61,  5, 11,  5,  3, 11, 62 ],
+        valtab: [
+      1,  -1,   0,   1,  -1,   2,  -2,   1,  -1,   1,  -1,   0,   3,  -3,   1,  -1,
+      2,  -2,   1,  -1,   1,  -1,   4,   1,  -4,  -1,   2,  -2,   1,  -1,   5,   3,
+     -3,  -5,   2,   1,  -2,  -1,   1,  -1,   6,   2,   1,  -1,  -6,  -2,   1,  -1,
+      3,  -3,   2,  -2,   4,  -4,   1,  -1,   1,  -1,   1,   2,  -1,   2,  -2,  -2,
+      7,  -7,   1,  -1,   3,  -3,   8,  -8,   1,  -1,   5,  -5,   3,  -3,   1,   4,
+      2,  -4,  -1,  -2,   1,   1,  -1,  -1,   9,   1,   1,  -9,  -1,   1,  -1,  -1,
+      1,  -1,   3,  -3,   1,   3,  -3,  -1,   3,  -3,   1,  -1,  10,   1, -10,  -1,
+      1,   4,  -1,   2,   1,  -1,   1,  -2,   1,  -4,  -1,   6,  -6,  -1,   1,   1,
+      1,  -1,   1,   1,  -1,  -1,  -1,   1,  11,  -1,  -2,   4,  -1,   2, -11,   5,
+     -5,  -4,  -1,   1,   4,   1,  -4,  -1,  -2,   2,   1,  -1,  12,   1,  -2,   1,
+    -12,   4,   2,   1,  -1,  -4,   4,  -4,   2,  -2,  -1,   1,   7,  -1,  -1,  -7,
+     -1,  -3,   1,   3,   1,   5,   2,   1,  -1,  -5,  13,  -2,  -1,   2,  -2, -13,
+      1,  -1,   5,   6,   5,  -5,   1,   1,  -6,   1,  -1,  -1,  -5,  -1,  14,   2,
+     -2,   1, -14,  -1,   8,   1,  -1,  -8,   1,   5,   1,   5,  -5,   1,  -1,   1,
+     -5,  -1,  15,   1,  -1,  -1,  -1,   3, -15,  -3,   6,   1,  16,  -1,   6,  -6,
+     -6,   1,  -1,   1, -16,   1,   7,  -1,   1,  -1,  -6,  -3,   6,  -7,   3,  -1 ]
+    },
+    RVMap { eob_sym: 0, esc_sym: 35, runtab: [
+     0,  1,  1,  2,  2,  3,  3,  4,  4,  1,  1,  5,  5,  6,  6,  7,
+     7,  8,  8,  9,  9,  2,  2, 10, 10,  1,  1, 11, 11, 12, 12,  3,
+     3, 13, 13,  0, 14, 14, 16, 15, 16, 15,  4,  4, 17,  1, 17,  1,
+     5,  5, 18, 18,  2,  2,  6,  6,  8, 19,  7,  8,  7, 19, 20, 20,
+    21, 21, 22, 24, 22, 24, 23, 23,  1,  1, 25, 25,  3,  3, 26, 26,
+     9,  9, 27, 27, 28, 28, 33, 29,  4, 33, 29,  1,  4,  1, 32, 32,
+     2,  2, 31, 10, 30, 10, 30, 31, 34, 34,  5,  5, 36, 36, 35, 41,
+    35, 11, 41, 11, 37,  1,  8,  8, 37,  6,  1,  6, 40,  7,  7, 40,
+    12, 38, 12, 39, 39, 38, 49, 13, 49, 13,  3, 42,  3, 42, 16, 16,
+    43, 43, 14, 14,  1,  1, 44, 15, 44, 15,  2,  2, 57, 48, 50, 48,
+    57, 50,  4, 45, 45,  4, 46, 47, 47, 46,  1, 51,  1, 17, 17, 51,
+     8,  9,  9,  5, 58,  8, 58,  5, 52, 52, 55, 56, 53, 56, 55, 59,
+    59, 53, 54,  1,  6, 54,  7,  7,  6,  1,  2,  3,  2,  3, 64, 60,
+    60, 10, 10, 64, 61, 62, 61, 63,  1, 63, 62,  1, 18, 24, 18,  4,
+    25,  4,  8, 21, 21,  1, 24, 22, 25, 22,  8, 11, 19, 11, 23,  1,
+    20, 23, 19, 20,  5, 12,  5,  1, 16,  2, 12, 13,  2, 13,  1, 16 ],
+        valtab: [
+      0,   1,  -1,   1,  -1,   1,  -1,   1,  -1,   2,  -2,   1,  -1,   1,  -1,   1,
+     -1,   1,  -1,   1,  -1,   2,  -2,   1,  -1,   3,  -3,   1,  -1,   1,  -1,   2,
+     -2,   1,  -1,   0,   1,  -1,   1,   1,  -1,  -1,   2,  -2,   1,   4,  -1,  -4,
+      2,  -2,   1,  -1,  -3,   3,   2,  -2,   2,   1,   2,  -2,  -2,  -1,   1,  -1,
+      1,  -1,   1,   1,  -1,  -1,   1,  -1,   5,  -5,   1,  -1,   3,  -3,   1,  -1,
+      2,  -2,   1,  -1,   1,  -1,   1,   1,   3,  -1,  -1,   6,  -3,  -6,  -1,   1,
+      4,  -4,   1,   2,   1,  -2,  -1,  -1,   1,  -1,   3,  -3,   1,  -1,   1,   1,
+     -1,   2,  -1,  -2,   1,   7,  -3,   3,  -1,   3,  -7,  -3,   1,  -3,   3,  -1,
+      2,   1,  -2,   1,  -1,  -1,   1,   2,  -1,  -2,  -4,  -1,   4,   1,   2,  -2,
+      1,  -1,  -2,   2,   8,  -8,  -1,   2,   1,  -2,  -5,   5,   1,  -1,  -1,   1,
+     -1,   1,   4,  -1,   1,  -4,  -1,  -1,   1,   1,   9,   1,  -9,   2,  -2,  -1,
+     -4,   3,  -3,  -4,  -1,   4,   1,   4,   1,  -1,   1,  -1,   1,   1,  -1,   1,
+     -1,  -1,  -1,  10,   4,   1,   4,  -4,  -4, -10,   6,   5,  -6,  -5,   1,  -1,
+      1,   3,  -3,  -1,   1,  -1,  -1,  -1,  11,   1,   1, -11,  -2,  -2,   2,   5,
+     -2,  -5,  -5,   2,  -2,  12,   2,  -2,   2,   2,   5,  -3,  -2,   3,  -2, -12,
+     -2,   2,   2,   2,  -5,   3,   5,  13,  -3,   7,  -3,  -3,  -7,   3, -13,   3 ]
+    },
+    RVMap { eob_sym: 0, esc_sym: 34, runtab: [
+     0,  1,  1,  1,  2,  2,  1,  3,  3,  1,  1,  1,  4,  4,  1,  5,
+     2,  1,  5,  2,  1,  1,  6,  6,  1,  1,  1,  1,  1,  7,  3,  1,
+     2,  3,  0,  1,  2,  7,  1,  1,  1,  8,  1,  1,  8,  1,  1,  1,
+     9,  1,  9,  1,  2,  1,  1,  2,  1,  1, 10,  4,  1, 10,  1,  4,
+     1,  1,  1,  1,  1,  3,  1,  1,  1,  3,  2,  1,  5,  1,  1,  1,
+     2,  5,  1, 11,  1, 11,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
+     2,  1,  6,  1,  6,  1,  1,  2,  1,  1,  1,  1,  1,  1,  1, 12,
+     3,  1, 12,  1,  1,  1,  2,  1,  1,  3,  1,  1,  1,  1,  1,  1,
+     4,  1,  1,  1,  2,  1,  1,  4,  1,  1,  1,  1,  1,  1,  2,  1,
+     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  3,  1,  2,  1,  1,  5,
+     1,  1,  1,  1,  1,  7,  1,  7,  1,  1,  2,  3,  1,  1,  1,  1,
+     5,  1,  1,  1,  1,  1,  1,  2, 13,  1,  1,  1,  1,  1,  1,  1,
+     1,  1,  1,  1,  1,  1,  1,  1, 13,  2,  1,  1,  4,  1,  1,  1,
+     3,  1,  6,  1,  1,  1, 14,  1,  1,  1,  1,  1, 14,  6,  1,  1,
+     1,  1, 15,  2,  4,  1,  2,  3, 15,  1,  1,  1,  8,  1,  1,  8,
+     1,  1,  1,  1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,  1,  1 ],
+        valtab: [
+      0,   1,  -1,   2,   1,  -1,  -2,   1,  -1,   3,  -3,   4,   1,  -1,  -4,   1,
+      2,   5,  -1,  -2,  -5,   6,   1,  -1,  -6,   7,  -7,   8,  -8,   1,   2,   9,
+      3,  -2,   0,  -9,  -3,  -1,  10, -10,  11,   1, -11,  12,  -1, -12,  13, -13,
+      1,  14,  -1, -14,   4,  15, -15,  -4,  16, -16,   1,   2,  17,  -1, -17,  -2,
+     18, -18,  19, -19,  20,   3, -20,  21, -21,  -3,   5,  22,   2, -22, -23,  23,
+     -5,  -2,  24,   1, -24,  -1,  25, -25,  26, -26, -27,  27,  28,  29, -28, -29,
+      6,  30,   2, -31,  -2, -30,  31,  -6, -32,  32,  33, -33,  34, -35, -34,   1,
+      4, -36,  -1,  35,  37,  36,   7, -37,  38,  -4, -38,  39,  41,  40, -40, -39,
+      3,  42, -43, -41,  -7, -42,  43,  -3,  44, -44,  45, -45,  46,  47,   8, -47,
+    -48, -46,  50, -50,  48,  49,  51, -49,  52, -52,   5, -51,  -8, -53,  53,   3,
+    -56,  56,  55,  54, -54,   2,  60,  -2, -55,  58,   9,  -5,  59,  57, -57, -63,
+     -3, -58, -60, -61,  61, -59, -62,  -9,   1,  64,  62,  69, -64,  63,  65, -67,
+    -68,  66, -65,  68, -66, -69,  67, -70,  -1,  10,  71, -71,   4,  73,  72,  70,
+      6, -76,  -3,  74, -78, -74,   1,  78,  80, -72, -75,  76,  -1,   3, -73,  79,
+     75,  77,   1,  11,  -4, -79, -10,  -6,  -1, -77, -83, -80,   2,  81, -84,  -2,
+     83, -81,  82, -82,  84, -87, -86,  85, -11, -85,  86, -89,  87, -88,  88,  89 ]
+    },
+    RVMap { eob_sym: 2, esc_sym: 33, runtab: [
+     1,  1,  0,  2,  1,  2,  1,  3,  3,  1,  1,  4,  4,  2,  2,  1,
+     1,  5,  5,  6,  1,  6,  1,  7,  7,  3,  3,  2,  8,  2,  8,  1,
+     1,  0,  9,  9,  1,  1, 10,  4, 10,  4, 11, 11,  2,  1,  2,  1,
+    12, 12,  3,  3,  1,  1, 13,  5,  5, 13, 14,  1,  1, 14,  2,  2,
+     6,  6, 15,  1,  1, 15, 16,  4,  7, 16,  4,  7,  1,  1,  3,  3,
+     8,  8,  2,  2,  1,  1, 17, 17,  1,  1, 18, 18,  5,  5,  2,  2,
+     1,  1,  9, 19,  9, 19, 20,  3,  3, 20,  1, 10, 21,  1, 10,  4,
+     4, 21, 22,  6,  6, 22,  1,  1, 23, 24,  2,  2, 23, 24, 11,  1,
+     1, 11,  7, 25,  7,  1,  1, 25,  8,  8,  3, 26,  3,  1, 12,  2,
+     2, 26,  1, 12,  5,  5, 27,  4,  1,  4,  1, 27, 28,  1, 28, 13,
+     1, 13,  2, 29,  2,  1, 32,  6,  1, 30, 14, 29, 14,  6,  3, 31,
+     3,  1, 30,  1, 32, 31, 33,  9, 33,  1,  1,  7,  9,  7,  2,  2,
+     1,  1,  4, 36, 34,  4,  5, 10, 10,  5, 34,  1,  1, 35,  8,  8,
+    36,  3, 35,  1, 15,  3,  2,  1, 16, 15, 16,  2, 37,  1, 37,  1,
+     1,  1,  6,  6, 38,  1, 38, 11,  1, 39, 39, 40, 11,  2, 41,  4,
+    40,  1,  2,  4,  1,  1,  1, 41,  3,  1,  3,  1,  5,  7,  5,  7 ],
+        valtab: [
+      1,  -1,   0,   1,   2,  -1,  -2,   1,  -1,   3,  -3,   1,  -1,   2,  -2,   4,
+     -4,   1,  -1,   1,   5,  -1,  -5,   1,  -1,   2,  -2,   3,   1,  -3,  -1,   6,
+     -6,   0,   1,  -1,   7,  -7,   1,   2,  -1,  -2,   1,  -1,   4,   8,  -4,  -8,
+      1,  -1,   3,  -3,   9,  -9,   1,   2,  -2,  -1,   1,  10, -10,  -1,   5,  -5,
+      2,  -2,   1,  11, -11,  -1,   1,   3,   2,  -1,  -3,  -2,  12, -12,   4,  -4,
+      2,  -2,  -6,   6,  13, -13,   1,  -1,  14, -14,   1,  -1,   3,  -3,   7,  -7,
+     15, -15,   2,   1,  -2,  -1,   1,   5,  -5,  -1, -16,   2,   1,  16,  -2,   4,
+     -4,  -1,   1,   3,  -3,  -1,  17, -17,   1,   1,  -8,   8,  -1,  -1,   2,  18,
+    -18,  -2,   3,   1,  -3,  19, -19,  -1,   3,  -3,   6,   1,  -6,  20,   2,   9,
+     -9,  -1, -20,  -2,   4,  -4,   1,  -5,  21,   5, -21,  -1,   1, -22,  -1,   2,
+     22,  -2,  10,   1, -10,  23,   1,   4, -23,   1,   2,  -1,  -2,  -4,  -7,   1,
+      7, -24,  -1,  24,  -1,  -1,   1,   3,  -1, -25,  25,   4,  -3,  -4,  11, -11,
+     26, -26,   6,   1,   1,  -6,  -5,  -3,   3,   5,  -1, -27,  27,   1,   4,  -4,
+     -1,  -8,  -1,  28,   2,   8, -12, -28,  -2,  -2,   2,  12,  -1,  29,   1, -29,
+     30, -30,   5,  -5,   1, -31,  -1,   3,  31,  -1,   1,   1,  -3, -13,   1,  -7,
+     -1, -32,  13,   7,  32,  33, -33,  -1,  -9, -34,   9,  34,  -6,   5,   6,  -5 ]
+    },
+    RVMap { eob_sym: 2, esc_sym: 13, runtab: [
+     1,  1,  0,  1,  1,  2,  2,  1,  1,  3,  3,  1,  1,  0,  2,  2,
+     4,  1,  4,  1,  1,  1,  5,  5,  1,  1,  6,  6,  2,  2,  1,  1,
+     3,  3,  7,  7,  1,  1,  8,  8,  1,  1,  2,  2,  1,  9,  1,  9,
+     4,  4, 10,  1,  1, 10,  1,  1, 11, 11,  3,  3,  1,  2,  1,  2,
+     1,  1, 12, 12,  5,  5,  1,  1, 13,  1,  1, 13,  2,  2,  1,  1,
+     6,  6,  1,  1,  4, 14,  4, 14,  3,  1,  3,  1,  1,  1, 15,  7,
+    15,  2,  2,  7,  1,  1,  1,  8,  1,  8, 16, 16,  1,  1,  1,  1,
+     2,  1,  1,  2,  1,  1,  3,  5,  5,  3,  4,  1,  1,  4,  1,  1,
+    17, 17,  9,  1,  1,  9,  2,  2,  1,  1, 10, 10,  1,  6,  1,  1,
+     6, 18,  1,  1, 18,  1,  1,  1,  2,  2,  3,  1,  3,  1,  1,  1,
+     4,  1, 19,  1, 19,  7,  1,  1, 20,  1,  4, 20,  1,  7, 11,  2,
+     1, 11, 21,  2,  8,  5,  1,  8,  1,  5, 21,  1,  1,  1, 22,  1,
+     1, 22,  1,  1,  3,  3,  1, 23,  2, 12, 24,  1,  1,  2,  1,  1,
+    12, 23,  1,  1, 24,  1,  1,  1,  4,  1,  1,  1,  2,  1,  6,  6,
+     4,  2,  1,  1,  1,  1,  1,  1,  1, 14, 13,  3,  1, 25,  9, 25,
+    14,  1,  9,  3, 13,  1,  1,  1,  1,  1, 10,  1,  1,  2, 10,  2 ],
+        valtab: [
+     -20,  -1,   0,   2,  -2,   1,  -1,   3,  -3,   1,  -1,   4,  -4,   0,   2,  -2,
+       1,   5,  -1,  -5,   6,  -6,   1,  -1,   7,  -7,   1,  -1,   3,  -3,   8,  -8,
+       2,  -2,   1,  -1,   9,  -9,   1,  -1,  10, -10,   4,  -4,  11,   1, -11,  -1,
+       2,  -2,   1,  12, -12,  -1,  13, -13,   1,  -1,   3,  -3,  14,   5, -14,  -5,
+     -15,  15,  -1,   1,   2,  -2,  16, -16,   1,  17, -17,  -1,   6,  -6,  18, -18,
+       2,  -2, -19,  19,  -3,   1,   3,  -1,   4,  20,  -4,   1, -21,  21,   1,   2,
+      -1,  -7,   7,  -2,  22, -22,  23,   2, -23,  -2,   1,  -1, -24,  24, -25,  25,
+      -8, -26,  26,   8, -27,  27,   5,   3,  -3,  -5,  -4,  28, -28,   4,  29, -29,
+       1,  -1,  -2, -30,  30,   2,   9,  -9, -31,  31,   2,  -2, -32,   3,  32, -33,
+      -3,   1,  33, -34,  -1,  34, -35,  35, -10,  10,  -6,  36,   6, -36,  37, -37,
+      -5,  38,   1, -38,  -1,   3,  39, -39,  -1,  40,   5,   1, -40,  -3,   2, -11,
+     -41,  -2,   1,  11,  -3,  -4,  41,   3,  42,   4,  -1, -43, -42,  43,   1, -44,
+      45,  -1,  44, -45,  -7,   7, -46,   1, -12,   2,   1, -47,  46,  12,  47,  48,
+      -2,  -1, -48,  49,  -1, -50, -49,  50,  -6, -51,  51,  52, -13,  53,  -4,   4,
+       6,  13, -53, -52, -54,  55,  54, -55, -56,  -2,   2,  -8,  56,   1,  -3,  -1,
+       2,  58,   3,   8,  -2,  57, -58, -60, -59, -57,  -3,  60,  59, -14,   3,  14 ]
+    },
+    RVMap { eob_sym: 2, esc_sym: 38, runtab: [
+     1,  1,  0,  2,  2,  1,  1,  3,  3,  4,  4,  5,  5,  1,  1,  6,
+     6,  2,  2,  7,  7,  8,  8,  1,  1,  3,  3,  9,  9, 10, 10,  1,
+     1,  2,  2,  4,  4, 11,  0, 11, 12, 12, 13, 13,  1,  1,  5,  5,
+    14, 14, 15, 16, 15, 16,  3,  3,  1,  6,  1,  6,  2,  2,  7,  7,
+     8,  8, 17, 17,  1,  1,  4,  4, 18, 18,  2,  2,  1, 19,  1, 20,
+    19, 20, 21, 21,  3,  3, 22, 22,  5,  5, 24,  1,  1, 23,  9, 23,
+    24,  9,  2,  2, 10,  1,  1, 10,  6,  6, 25,  4,  4, 25,  7,  7,
+    26,  8,  1,  8,  3,  1, 26,  3, 11, 11, 27, 27,  2, 28,  1,  2,
+    28,  1, 12, 12,  5,  5, 29, 13, 13, 29, 32,  1,  1, 33, 31, 30,
+    32,  4, 30, 33,  4, 31,  3, 14,  1,  1,  3, 34, 34,  2,  2, 14,
+     6,  6, 35, 36, 35, 36,  1, 15,  1, 16, 16, 15,  7,  9,  7,  9,
+    37,  8,  8, 37,  1,  1, 39,  2, 38, 39,  2, 40,  5, 38, 40,  5,
+     3,  3,  4,  4, 10, 10,  1,  1,  1,  1, 41,  2, 41,  2,  6,  6,
+     1,  1, 11, 42, 11, 43,  3, 42,  3, 17,  4, 43,  1, 17,  7,  1,
+     8, 44,  4,  7, 44,  5,  8,  2,  5,  1,  2, 48, 45,  1, 12, 45,
+    12, 48, 13, 13,  1,  9,  9, 46,  1, 46, 47, 47, 49, 18, 18, 49 ],
+        valtab: [
+      1,  -1,   0,   1,  -1,   2,  -2,   1,  -1,   1,  -1,   1,  -1,   3,  -3,   1,
+     -1,  -2,   2,   1,  -1,   1,  -1,   4,  -4,  -2,   2,   1,  -1,   1,  -1,   5,
+     -5,  -3,   3,   2,  -2,   1,   0,  -1,   1,  -1,   1,  -1,   6,  -6,   2,  -2,
+      1,  -1,   1,   1,  -1,  -1,  -3,   3,   7,   2,  -7,  -2,  -4,   4,   2,  -2,
+      2,  -2,   1,  -1,   8,  -8,   3,  -3,   1,  -1,  -5,   5,   9,   1,  -9,   1,
+     -1,  -1,   1,  -1,  -4,   4,   1,  -1,   3,  -3,   1, -10,  10,   1,   2,  -1,
+     -1,  -2,   6,  -6,   2,  11, -11,  -2,   3,  -3,   1,  -4,   4,  -1,   3,  -3,
+      1,   3,  12,  -3,  -5, -12,  -1,   5,   2,  -2,   1,  -1,  -7,   1,  13,   7,
+     -1, -13,   2,  -2,   4,  -4,   1,   2,  -2,  -1,   1,  14, -14,   1,   1,   1,
+     -1,  -5,  -1,  -1,   5,  -1,  -6,   2, -15,  15,   6,   1,  -1,  -8,   8,  -2,
+     -4,   4,   1,   1,  -1,  -1,  16,   2, -16,  -2,   2,  -2,   4,   3,  -4,  -3,
+     -1,  -4,   4,   1, -17,  17,  -1,  -9,   1,   1,   9,   1,  -5,  -1,  -1,   5,
+     -7,   7,   6,  -6,   3,  -3,  18, -18,  19, -19,   1, -10,  -1,  10,  -5,   5,
+     20, -20,  -3,   1,   3,   1,   8,  -1,  -8,   2,   7,  -1, -21,  -2,   5,  21,
+      5,  -1,  -7,  -5,   1,  -6,  -5, -11,   6,  22,  11,   1,   1, -22,  -3,  -1,
+      3,  -1,   3,  -3, -23,   4,  -4,   1,  23,  -1,   1,  -1,   1,  -2,   2,  -1 ]
+    },
+    RVMap { eob_sym: 4, esc_sym: 11, runtab: [
+     1,  1,  1,  1,  0,  2,  2,  1,  1,  3,  3,  0,  1,  1,  2,  2,
+     4,  4,  1,  1,  5,  5,  1,  1,  2,  2,  3,  3,  6,  6,  1,  1,
+     7,  7,  8,  1,  8,  2,  2,  1,  4,  4,  1,  3,  1,  3,  9,  9,
+     2,  2,  1,  5,  1,  5, 10, 10,  1,  1, 11, 11,  3,  6,  3,  4,
+     4,  6,  2,  2,  1, 12,  1, 12,  7, 13,  7, 13,  1,  1,  8,  8,
+     2,  2, 14, 14, 16, 15, 16,  5,  5,  1,  3, 15,  1,  3,  4,  4,
+     1,  1, 17, 17,  2,  2,  6,  6,  1, 18,  1, 18, 22, 21, 22, 21,
+    25, 24, 25, 19,  9, 20,  9, 23, 19, 24, 20,  3, 23,  7,  3,  1,
+     1,  7, 28, 26, 29,  5, 28, 26,  5,  8, 29,  4,  8, 27,  2,  2,
+     4, 27,  1,  1, 10, 36, 10, 33, 33, 36, 30,  1, 32, 32,  1, 30,
+     6, 31, 31, 35,  3,  6, 11, 11,  3,  2, 35,  2, 34,  1, 34,  1,
+    37, 37, 12,  7, 12,  5, 41,  5,  4,  7,  1,  8, 13,  4,  1, 41,
+    13, 38,  8, 38,  9,  1, 40, 40,  9,  1, 39,  2,  2, 49, 39, 42,
+     3,  3, 14, 16, 49, 14, 16, 42, 43, 43,  6,  6, 15,  1,  1, 15,
+    44, 44,  1,  1, 50, 48,  4,  5,  4,  7,  5,  2, 10, 10, 48,  7,
+    50, 45,  2,  1, 45,  8,  8,  1, 46, 46,  3, 47, 47,  3,  1,  1 ],
+        valtab: [
+      1,  -1,   2,  -2,   0,   1,  -1,   3,  -3,   1,  -1,   0,   4,  -4,   2,  -2,
+      1,  -1,   5,  -5,   1,  -1,   6,  -6,   3,  -3,   2,  -2,   1,  -1,   7,  -7,
+      1,  -1,   1,   8,  -1,   4,  -4,  -8,   2,  -2,   9,   3,  -9,  -3,   1,  -1,
+      5,  -5,  10,   2, -10,  -2,   1,  -1,  11, -11,   1,  -1,  -4,   2,   4,   3,
+     -3,  -2,   6,  -6,  12,   1, -12,  -1,   2,   1,  -2,  -1,  13, -13,   2,  -2,
+      7,  -7,   1,  -1,   1,   1,  -1,   3,  -3,  14,   5,  -1, -14,  -5,   4,  -4,
+     15, -15,   1,  -1,   8,  -8,  -3,   3,  16,   1, -16,  -1,   1,   1,  -1,  -1,
+      1,   1,  -1,   1,   2,   1,  -2,   1,  -1,  -1,  -1,   6,  -1,   3,  -6,  17,
+    -17,  -3,   1,   1,   1,   4,  -1,  -1,  -4,   3,  -1,   5,  -3,  -1,  -9,   9,
+     -5,   1,  18, -18,   2,   1,  -2,   1,  -1,  -1,   1,  19,  -1,   1, -19,  -1,
+      4,   1,  -1,   1,   7,  -4,  -2,   2,  -7,  10,  -1, -10,   1,  20,  -1, -20,
+      1,  -1,   2,   4,  -2,   5,   1,  -5,   6,  -4,  21,   4,   2,  -6, -21,  -1,
+     -2,   1,  -4,  -1,  -3,  22,  -1,   1,   3, -22,  -1,  11, -11,   1,   1,   1,
+      8,  -8,   2,   2,  -1,  -2,  -2,  -1,   1,  -1,  -5,   5,   2,  23, -23,  -2,
+      1,  -1,  24, -24,  -1,  -1,   7,   6,  -7,   5,  -6,  12,  -3,   3,   1,  -5,
+      1,   1, -12,  25,  -1,  -5,   5, -25,  -1,   1,   9,   1,  -1,  -9,  26, -26 ]
+    }
+];
diff --git a/src/codecs/indeo/ividsp.rs b/src/codecs/indeo/ividsp.rs
new file mode 100644 (file)
index 0000000..842bb3e
--- /dev/null
@@ -0,0 +1,415 @@
+use super::ivi::{IVITransformType,TDir,TrFunc,TrFuncDC};
+
+fn hbutterfly(a: i32, b: i32) -> (i32, i32) {
+    ((a + b) >> 1, (a - b) >> 1)
+}
+fn butterfly(a: i32, b: i32) -> (i32, i32) {
+    (a + b, a - b)
+}
+fn ireflect(a: i32, b: i32) -> (i32, i32) {
+    (((b * 2 - a + 2) >> 2) - a, ((b + 2 * a + 2) >> 2) + b)
+}
+
+macro_rules! haar_transform {
+    ($c0:expr, $c1:expr, $c2:expr, $c3:expr) => {{
+        let (t0, t1) = hbutterfly($c0, $c1);
+        let (t2, t3) = hbutterfly(t0,  $c2);
+        $c0 = t2;
+        $c1 = t3;
+        let (t4, t5) = hbutterfly(t1,  $c3);
+        $c2 = t4;
+        $c3 = t5;
+    }};
+    ($c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr, $c6:expr, $c7:expr) => {{
+        let (a0, a1) = hbutterfly($c0 << 1, $c1 << 1);
+
+        let (t0, t1) = hbutterfly(a0, $c2);
+        let (t2, t3) = hbutterfly(a1, $c3);
+        let (u0, u1) = hbutterfly(t0, $c4);
+        let (u2, u3) = hbutterfly(t1, $c5);
+        let (u4, u5) = hbutterfly(t2, $c6);
+        let (u6, u7) = hbutterfly(t3, $c7);
+
+        $c0 = u0;
+        $c1 = u1;
+        $c2 = u2;
+        $c3 = u3;
+        $c4 = u4;
+        $c5 = u5;
+        $c6 = u6;
+        $c7 = u7;
+    }};
+}
+macro_rules! slant_transform {
+    ($c0:expr, $c1:expr, $c2:expr, $c3:expr, $output:ident) => {{
+        let (t0, t1) = butterfly($c0, $c2);
+        let (t2, t3) = ireflect ($c3, $c1);
+        let (t4, t5) = butterfly(t0,  t3);
+        let (t6, t7) = butterfly(t1,  t2);
+        $c0 = $output(t4);
+        $c1 = $output(t6);
+        $c2 = $output(t7);
+        $c3 = $output(t5);
+    }};
+    ($c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr, $c6:expr, $c7:expr, $output:ident) => {{
+        let t0 = $c3 + (($c1 * 4 -  $c3 + 4) >> 3);
+        let t1 = $c1 + ((-$c1 - $c3 * 4 + 4) >> 3);
+
+        let (t2, t3) = butterfly($c0, t1);
+        let (t4, t5) = butterfly($c4, $c5);
+        let (t6, t7) = butterfly($c7, $c6);
+        let (t8, t9) = butterfly(t0,  $c2);
+
+        let (u0, u1) = butterfly(t2, t4);
+        let (u2, u3) = ireflect (t7, t8);
+        let (u4, u5) = butterfly(t3, t5);
+        let (u6, u7) = ireflect (t6, t9);
+
+        let (t0, t1) = butterfly(u0, u3);
+        let (t2, t3) = butterfly(u1, u2);
+        let (t4, t5) = butterfly(u4, u7);
+        let (t6, t7) = butterfly(u5, u6);
+
+        $c0 = $output(t0);
+        $c1 = $output(t2);
+        $c2 = $output(t3);
+        $c3 = $output(t1);
+        $c4 = $output(t4);
+        $c5 = $output(t6);
+        $c6 = $output(t7);
+        $c7 = $output(t5);
+    }};
+}
+
+fn haar8x8_2d(blk: &mut[i32; 64]) {
+    for i in 0..4 {
+        let mut c0 = blk[i + 0*8] << 1;
+        let mut c1 = blk[i + 1*8] << 1;
+        let mut c2 = blk[i + 2*8] << 1;
+        let mut c3 = blk[i + 3*8] << 1;
+        haar_transform!(c0, c1, c2, c3, 
+                        blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8]);
+        blk[i + 0*8] = c0;
+        blk[i + 1*8] = c1;
+        blk[i + 2*8] = c2;
+        blk[i + 3*8] = c3;
+    }
+    for i in 4..8 {
+        haar_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+                        blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8]);
+    }
+    for i in 0..8 {
+        let mut row = &mut blk[i*8..(i+1)*8];
+        haar_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
+    }
+}
+fn haar8x8_row(blk: &mut[i32; 64]) {
+    for i in 0..8 {
+        let mut row = &mut blk[i*8..(i+1)*8];
+        haar_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
+    }
+}
+fn haar8x8_col(blk: &mut[i32; 64]) {
+    for i in 0..8 {
+        haar_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+                        blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8]);
+    }
+}
+fn haar8x8_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = in0 >> 3;
+    for i in 0..64 { blk[i] = dc; }
+}
+
+fn haar4x4_2d(blk: &mut[i32; 64]) {
+    for i in 0..2 {
+        let mut c0 = blk[i + 0*4] << 1;
+        let mut c1 = blk[i + 1*4] << 1;
+        haar_transform!(c0, c1, blk[i + 2*4], blk[i + 3*4]);
+        blk[i + 0*4] = c0;
+        blk[i + 1*4] = c1;
+    }
+    for i in 2..4 {
+        haar_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4]);
+    }
+    for i in 0..4 {
+        let mut row = &mut blk[i*4..(i+1)*4];
+        haar_transform!(row[0], row[1], row[2], row[3]);
+    }
+}
+fn haar4x4_row(blk: &mut[i32; 64]) {
+    for i in 0..4 {
+        let mut row = &mut blk[i*4..(i+1)*4];
+        haar_transform!(row[0], row[1], row[2], row[3]);
+    }
+}
+fn haar4x4_col(blk: &mut[i32; 64]) {
+    for i in 0..4 {
+        haar_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4]);
+    }
+}
+fn haar4x4_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = in0 >> 3;
+    for i in 0..16 { blk[i] = dc; }
+}
+
+fn slant8x8_2d(blk: &mut[i32; 64]) {
+    let pass1 = |x: i32| x;
+    let pass2 = |x: i32| (x + 1) >> 1;
+
+    for i in 0..8 {
+        let mut s0 = 0;
+        for j in 0..8 { s0 |= blk[i + j*8]; }
+        if s0 == 0 { continue; }
+
+        slant_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+                         blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8], pass1);
+    }
+    for i in 0..8 {
+        let mut row = &mut blk[i*8..(i+1)*8];
+        slant_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], pass2);
+    }
+}
+fn slant8x8_2d_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = (in0 + 1) >> 1;
+    for i in 0..64 { blk[i] = dc; }
+}
+fn slant8x8_row(blk: &mut[i32; 64]) {
+    let pass = |x: i32| (x + 1) >> 1;
+
+    for i in 0..8 {
+        let mut row = &mut blk[i*8..(i+1)*8];
+        slant_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], pass);
+    }
+}
+fn slant8x8_row_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = (in0 + 1) >> 1;
+
+    for i in 0..8  { blk[i] = dc; }
+    for i in 8..64 { blk[i] = 0; }
+}
+fn slant8x8_col(blk: &mut[i32; 64]) {
+    let pass = |x: i32| (x + 1) >> 1;
+
+    for i in 0..8 {
+        slant_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+                         blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8], pass);
+    }
+}
+fn slant8x8_col_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = (in0 + 1) >> 1;
+
+    for i in 0..8 {
+        blk[i * 8] = dc;
+        for j in 1..8 { blk[i * 8 + j] = 0; }
+    }
+}
+
+fn slant4x4_2d(blk: &mut[i32; 64]) {
+    let pass1 = |x: i32| x;
+    let pass2 = |x: i32| (x + 1) >> 1;
+
+    for i in 0..4 {
+        slant_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4], pass1);
+    }
+    for i in 0..4 {
+        let mut row = &mut blk[i*4..(i+1)*4];
+        slant_transform!(row[0], row[1], row[2], row[3], pass2);
+    }
+}
+fn slant4x4_2d_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = (in0 + 1) >> 1;
+    for i in 0..16 { blk[i] = dc; }
+}
+fn slant4x4_row(blk: &mut[i32; 64]) {
+    let pass = |x: i32| (x + 1) >> 1;
+
+    for i in 0..4 {
+        let mut row = &mut blk[i*4..(i+1)*4];
+        slant_transform!(row[0], row[1], row[2], row[3], pass);
+    }
+}
+fn slant4x4_row_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = (in0 + 1) >> 1;
+
+    for i in 0..4  { blk[i] = dc; }
+    for i in 4..16 { blk[i] = 0; }
+}
+fn slant4x4_col(blk: &mut[i32; 64]) {
+    let pass = |x: i32| (x + 1) >> 1;
+
+    for i in 0..4 {
+        slant_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4], pass);
+    }
+}
+fn slant4x4_col_dc(blk: &mut[i32; 64], in0: i32) {
+    let dc = (in0 + 1) >> 1;
+
+    for i in 0..4 {
+        blk[i * 4] = dc;
+        for j in 1..4 { blk[i * 4 + j] = 0; }
+    }
+}
+
+#[allow(unused_variables)]
+fn none8x8(blk: &mut[i32; 64]) {
+}
+fn none8x8_dc(blk: &mut[i32; 64], dc: i32) {
+    for i in 1..8  { blk[i] = dc; }
+    for i in 8..64 { blk[i] = 0; }
+}
+#[allow(unused_variables)]
+fn none4x4(blk: &mut[i32; 64]) {
+}
+fn none4x4_dc(blk: &mut[i32; 64], dc: i32) {
+    for i in 1..4  { blk[i] = dc; }
+    for i in 4..16 { blk[i] = 0; }
+}
+
+pub fn ivi_get_transform8x8_funcs(ttype: IVITransformType) -> (TrFunc, TrFuncDC) {
+    match ttype {
+        IVITransformType::Haar(_, ref dir) => {
+            match *dir {
+                TDir::TwoD => { (haar8x8_2d,  haar8x8_dc) },
+                TDir::Row  => { (haar8x8_row, haar8x8_dc) },
+                TDir::Col  => { (haar8x8_col, haar8x8_dc) },
+            } },
+        IVITransformType::Slant(_, ref dir) => {
+            match *dir {
+                TDir::TwoD => { (slant8x8_2d,  slant8x8_2d_dc) },
+                TDir::Row  => { (slant8x8_row, slant8x8_row_dc) },
+                TDir::Col  => { (slant8x8_col, slant8x8_col_dc) },
+            } },
+        IVITransformType::DCT(_, _) => { unimplemented!() },
+        IVITransformType::None(_) => { (none8x8, none8x8_dc) }
+    }
+}
+pub fn ivi_get_transform4x4_funcs(ttype: IVITransformType) -> (TrFunc, TrFuncDC) {
+    match ttype {
+        IVITransformType::Haar(_, ref dir) => {
+            match *dir {
+                TDir::TwoD => { (haar4x4_2d,  haar4x4_dc) },
+                TDir::Row  => { (haar4x4_row, haar4x4_dc) },
+                TDir::Col  => { (haar4x4_col, haar4x4_dc) },
+            } },
+        IVITransformType::Slant(_, ref dir) => {
+            match *dir {
+                TDir::TwoD => { (slant4x4_2d,  slant4x4_2d_dc) },
+                TDir::Row  => { (slant4x4_row, slant4x4_row_dc) },
+                TDir::Col  => { (slant4x4_col, slant4x4_col_dc) },
+            } },
+        IVITransformType::DCT(_, _) => { unimplemented!() },
+        IVITransformType::None(_) => { (none4x4, none4x4_dc) }
+    }
+}
+
+pub fn ivi_mc_put(dst: &mut [i16], dstride: usize, src: &[i16], sstride: usize, mode: u8, w: usize, h: usize) {
+    let mut sidx = 0;
+    let mut didx = 0;
+    if src.len() < w + h * sstride { return; }
+    match mode {
+        0 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    dst[didx + x] = src[sidx + x];
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        1 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    let val = (src[sidx + x] + src[sidx + x + 1]) >> 1;
+                    dst[didx + x] = val;
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        2 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    let val = (src[sidx + x] + src[sidx + x + sstride]) >> 1;
+                    dst[didx + x] = val;
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        3 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    let val = (src[sidx + x + 0] + src[sidx + x + sstride + 0] +
+                               src[sidx + x + 1] + src[sidx + x + sstride + 1]) >> 2;
+                    dst[didx + x] = val;
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        _ => {},
+    }
+}
+fn ivi_mc_add(dst: &mut [i16], dstride: usize, src: &[i16], sstride: usize, mode: u8, w: usize, h: usize) {
+    let mut sidx = 0;
+    let mut didx = 0;
+    match mode {
+        0 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    dst[didx + x] += src[sidx + x];
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        1 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    let val = (src[sidx + x] + src[sidx + x + 1]) >> 1;
+                    dst[didx + x] += val;
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        2 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    let val = (src[sidx + x] + src[sidx + x + sstride]) >> 1;
+                    dst[didx + x] += val;
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        3 => {
+            for _ in 0..h {
+                for x in 0..w {
+                    let val = (src[sidx + x + 0] + src[sidx + x + sstride + 0] +
+                               src[sidx + x + 1] + src[sidx + x + sstride + 1]) >> 2;
+                    dst[didx + x] += val;
+                }
+                sidx += sstride;
+                didx += dstride;
+            }
+        },
+        _ => {},
+    }
+}
+pub fn ivi_mc_avg(dst: &mut [i16], dstride: usize,
+                  src1: &[i16], sstride1: usize, mode1: u8,
+                  src2: &[i16], sstride2: usize, mode2: u8,
+                  w: usize, h: usize) {
+    let mut tidx = 0;
+    let tstride = 8;
+    let mut didx = 0;
+    let mut tmp: [i16; 64] = [0; 64];
+    ivi_mc_add(&mut tmp, tstride, src1, sstride1, mode1, w, h);
+    ivi_mc_add(&mut tmp, tstride, src2, sstride2, mode2, w, h);
+    for _ in 0..h {
+       for x in 0..w { dst[didx + x] = tmp[tidx + x] >> 1; }
+       tidx += tstride;
+       didx += dstride;
+    }
+}
index 43da6ed0affdcf686f1bc87f985167e8c88e8bc9..e1fcdcd0f9b2b91f9f56a3487930c2b57780786f 100644 (file)
@@ -2,7 +2,17 @@
 pub mod indeo2;
 #[cfg(feature="decoder_indeo3")]
 pub mod indeo3;
+#[cfg(feature="decoder_indeo4")]
+pub mod indeo4;
+#[cfg(feature="decoder_indeo5")]
+pub mod indeo5;
+
+#[cfg(any(feature="decoder_indeo4", feature="decoder_indeo5"))]
+mod ivi;
+#[cfg(any(feature="decoder_indeo4", feature="decoder_indeo5"))]
+mod ivibr;
+#[cfg(any(feature="decoder_indeo4", feature="decoder_indeo5"))]
+mod ividsp;
 
 #[cfg(feature="decoder_imc")]
 pub mod imc;
-
index 45005a39e0a100f684b19b438ce56a4b8cf27815..c6cbcd3ace89072ff2401eb5e45580d67141d54e 100644 (file)
@@ -118,7 +118,7 @@ mod blockdsp;
 
 #[cfg(feature="decoder_gdvvid")]
 mod gremlinvideo;
-#[cfg(any(feature="decoder_indeo2", feature="decoder_indeo3", feature="decoder_imc"))]
+#[cfg(any(feature="decoder_indeo2", feature="decoder_indeo3", feature="decoder_indeo4", feature="decoder_indeo5", feature="decoder_imc"))]
 mod indeo;
 #[cfg(feature="h263")]
 mod h263;
@@ -133,6 +133,10 @@ const DECODERS: &[DecoderInfo] = &[
     DecoderInfo { name: "indeo2", get_decoder: indeo::indeo2::get_decoder },
 #[cfg(feature="decoder_indeo3")]
     DecoderInfo { name: "indeo3", get_decoder: indeo::indeo3::get_decoder },
+#[cfg(feature="decoder_indeo4")]
+    DecoderInfo { name: "indeo4", get_decoder: indeo::indeo4::get_decoder },
+#[cfg(feature="decoder_indeo5")]
+    DecoderInfo { name: "indeo5", get_decoder: indeo::indeo5::get_decoder },
 #[cfg(feature="decoder_intel263")]
     DecoderInfo { name: "intel263", get_decoder: h263::intel263::get_decoder },