From: Kostya Shishkov Date: Fri, 14 Jul 2017 16:29:33 +0000 (+0200) Subject: Indeo4/5 decoder X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=01c971c577427ee176b0e613315fa365eccfc536;p=nihav.git Indeo4/5 decoder --- diff --git a/Cargo.toml b/Cargo.toml index ce56480..5995625 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 index 0000000..60c45ab --- /dev/null +++ b/src/codecs/indeo/indeo4.rs @@ -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 { + 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 { + 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>, 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, + 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) -> 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 { + 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 { + 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 index 0000000..ae9113a --- /dev/null +++ b/src/codecs/indeo/indeo5.rs @@ -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 { + 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 { + 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>, 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, + 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) -> 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 { + 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 { + 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 index 0000000..064da0b --- /dev/null +++ b/src/codecs/indeo/ivi.rs @@ -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, +} + +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 index 0000000..35e1781 --- /dev/null +++ b/src/codecs/indeo/ivibr.rs @@ -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; + fn read_ivi_cb(&mut self, cb: &IVICodebook) -> BitReaderResult; + fn read_ivi_cb_s(&mut self, cb: &IVICodebook) -> BitReaderResult; +} + +impl<'a> IVICodebookReader for BitReader<'a> { + fn read_ivi_codebook_desc(&mut self, mb_cb: bool, desc_coded: bool) -> DecoderResult { + 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 { + 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 { + 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; 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> { + 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, 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; + fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane: usize, band: usize) -> DecoderResult; + fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band_hdr: &BandHeader, tile: &mut IVITile, ref_tile: Option>, 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>; 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, + + bands: Vec, + tiles: Vec>>, + num_tiles: [[usize; 4]; 4], + tile_start: [[usize; 4]; 4], +} + +impl IVIDecoder { + pub fn new() -> Self { + let mut bands: Vec = 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>; + 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>; + 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 { + 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 { + 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 = 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 index 0000000..842bb3e --- /dev/null +++ b/src/codecs/indeo/ividsp.rs @@ -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; + } +} diff --git a/src/codecs/indeo/mod.rs b/src/codecs/indeo/mod.rs index 43da6ed..e1fcdcd 100644 --- a/src/codecs/indeo/mod.rs +++ b/src/codecs/indeo/mod.rs @@ -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; - diff --git a/src/codecs/mod.rs b/src/codecs/mod.rs index 45005a3..c6cbcd3 100644 --- a/src/codecs/mod.rs +++ b/src/codecs/mod.rs @@ -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 },