From: Kostya Shishkov Date: Sun, 10 Feb 2019 17:47:51 +0000 (+0100) Subject: TrueMotion 1 decoder X-Git-Url: https://git.nihav.org/?p=nihav.git;a=commitdiff_plain;h=2d90e8b606894b7586e58985b2a6fbd52ca159df TrueMotion 1 decoder --- diff --git a/nihav-duck/src/codecs/truemotion1.rs b/nihav-duck/src/codecs/truemotion1.rs index df0bb5b..c43f7d8 100644 --- a/nihav-duck/src/codecs/truemotion1.rs +++ b/nihav-duck/src/codecs/truemotion1.rs @@ -1,6 +1,1519 @@ use nihav_core::codecs::*; +use nihav_core::io::byteio::*; + +struct MaskState<'a> { + is_intra: bool, + pos: usize, + row_pos: usize, + row_size: usize, + mask: u8, + src: &'a [u8], +} + +impl<'a> MaskState<'a> { + fn new(is_intra: bool, src: &'a [u8], row_size: usize) -> Self { + Self { is_intra, src, pos: 0, row_pos: 0, row_size, mask: 0x01 } + } + fn get_next(&mut self) -> bool { + if self.is_intra { + true + } else { + let res = (self.src[self.pos] & self.mask) == 0; + self.mask <<= 1; + if self.mask == 0 { + self.pos += 1; + self.mask = 0x01; + } + res + } + } + fn reset_row(&mut self) { + self.pos = self.row_pos; + self.mask = 0x01; + } + fn next_row(&mut self) { + self.row_pos += self.row_size; + self.reset_row(); + } +} + +struct IndexState<'a> { + src: &'a [u8], + pos: usize, + vec_idx: usize, + vec_subidx: usize, +} + +impl<'a> IndexState<'a> { + fn new(src: &'a [u8]) -> Self { + Self { src, pos: 0, vec_idx: 0, vec_subidx: 0 } + } + fn get_next(&mut self) -> DecoderResult<()> { + validate!(self.pos < self.src.len()); + self.vec_idx = self.src[self.pos] as usize; + self.vec_subidx = 0; + self.pos += 1; + Ok(()) + } + fn get_pred(&self, dtab: &[[u32; 4]; 256]) -> u32 { dtab[self.vec_idx][self.vec_subidx] } + fn get_diff16(&mut self, dtab: &[[u32; 4]; 256]) -> DecoderResult { + let pred1 = self.get_pred(dtab); + let mut pred = pred1 >> 1; + if (pred1 & 1) != 0 { + self.get_next()?; + if self.vec_idx == 0 { + self.get_next()?; + let pred2 = self.get_pred(dtab); + pred = pred.wrapping_add((pred2 >> 1).wrapping_mul(5)); + if (pred2 & 1) != 0 { + self.get_next()?; + } else { + self.vec_subidx += 1; + } + } + } else { + self.vec_subidx += 1; + } + Ok(pred) + } + fn get_diff16_noesc(&mut self, dtab: &[[u32; 4]; 256]) -> DecoderResult { + let pred1 = self.get_pred(dtab); + let pred = pred1 >> 1; + if (pred1 & 1) != 0 { + self.get_next()?; + } else { + self.vec_subidx += 1; + } + Ok(pred) + } + fn get_diff24(&mut self, dtab: &[[u32; 4]; 256], esctab: &[[u32; 4]; 256]) -> DecoderResult { + let pred1 = self.get_pred(dtab); + let mut pred = pred1 >> 1; + if (pred1 & 1) != 0 { + self.get_next()?; + if self.vec_idx == 0 { + self.get_next()?; + let pred2 = self.get_pred(esctab); + pred = pred.wrapping_add(pred2 >> 1); + if (pred2 & 1) != 0 { + self.get_next()?; + } else { + self.vec_subidx += 1; + } + } + } else { + self.vec_subidx += 1; + } + Ok(pred) + } +} + +struct DeltaTables { + ydt: [[u32; 4]; 256], + cdt: [[u32; 4]; 256], + fat_ydt: [[u32; 4]; 256], + fat_cdt: [[u32; 4]; 256], + adt: [[u32; 4]; 256], +} + +impl Default for DeltaTables { + fn default() -> Self { + Self { + ydt: [[0; 4]; 256], + cdt: [[0; 4]; 256], + fat_ydt: [[0; 4]; 256], + fat_cdt: [[0; 4]; 256], + adt: [[0; 4]; 256], + } + } +} + +struct FrameBuf { + last16: Option>, + last24: Option>, +} + +impl FrameBuf { + fn set16(&mut self, buf: NAVideoBuffer) { self.last16 = Some(buf); } + fn set24(&mut self, buf: NAVideoBuffer) { self.last24 = Some(buf); } + fn get16(&mut self) -> Option> { + if let Some(ref mut frm) = self.last16 { + let newfrm = frm.copy_buffer(); + *frm = newfrm.clone(); + Some(newfrm) + } else { + None + } + } + fn get24(&mut self) -> Option> { + if let Some(ref mut frm) = self.last24 { + let newfrm = frm.copy_buffer(); + *frm = newfrm.clone(); + Some(newfrm) + } else { + None + } + } + fn reset(&mut self) { + self.last16 = None; + self.last24 = None; + } +} + +impl Default for FrameBuf { + fn default() -> Self { + Self { last16: None, last24: None } + } +} + +#[derive(Default)] +struct TM1Decoder { + info: Rc, + last_delta_set: usize, + last_table_idx: usize, + delta_tables: DeltaTables, + blk_w: usize, + blk_h: usize, + vert_pred: Vec, + lastframe: FrameBuf, +} + +const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3, + comp_info: [ + Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }), + Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 5, comp_offs: 0, next_elem: 2 }), + Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 0, comp_offs: 0, next_elem: 2 }), + None, None], + elem_size: 2, be: false, alpha: false, palette: false }; +const BGR0_FORMAT: NAPixelFormaton = NAPixelFormaton { model: ColorModel::RGB(RGBSubmodel::RGB), components: 3, + comp_info: [ + Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }), + Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }), + Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }), + None, None], + elem_size: 4, be: false, alpha: false, palette: false }; + +impl TM1Decoder { + fn new() -> Self { Self::default() } + fn set_delta_tables(&mut self, delta_set: usize, table_idx: usize, is_24bit: bool) { + if (self.last_delta_set == delta_set) && (self.last_table_idx == table_idx) { return; } + let ydt = &DUCK_Y_DELTAS[delta_set]; + let yfdt = DUCK_Y_FAT_DELTAS[delta_set]; + let cdt = &DUCK_C_DELTAS[delta_set]; + let cfdt = DUCK_C_FAT_DELTAS[delta_set]; + let vec = DUCK_VECTABLES[table_idx - 1]; + + let mut vec_iter = vec.into_iter(); + for i in 0..256 { + let len = (*vec_iter.next().unwrap() as usize) >> 1; + for j in 0..len { + let pair = vec_iter.next().unwrap(); + let lo = (pair >> 4) as usize; + let hi = (pair & 0xF) as usize; + if !is_24bit { + let d_lo = ydt[lo] + (ydt[lo] << 5) + (ydt[lo] << 10); + let d_hi = ydt[hi] + (ydt[hi] << 5) + (ydt[hi] << 10); + self.delta_tables.ydt[i][j] = ((d_lo + (d_hi << 16)) << 1) as u32; + let d_c = cdt[hi] + (cdt[lo] << 10); + self.delta_tables.cdt[i][j] = ((d_c + (d_c << 16)) << 1) as u32; + let d_a = lo + hi * 5; + self.delta_tables.adt[i][j] = ((d_a << 16) << 1) as u32; + } else { + self.delta_tables.ydt[i][j] = ((ydt [lo] + (ydt [hi] << 8) + (ydt [hi] << 16)) << 1) as u32; + self.delta_tables.fat_ydt[i][j] = ((yfdt[lo] + (yfdt[hi] << 8) + (yfdt[hi] << 16)) << 1) as u32; + self.delta_tables.cdt[i][j] = ((cdt [hi] + (cdt [lo] << 16)) << 1) as u32; + self.delta_tables.fat_cdt[i][j] = ((cfdt[hi] + (cfdt[lo] << 16)) << 1) as u32; + } + } + self.delta_tables.ydt[i][len - 1] |= 1; + self.delta_tables.cdt[i][len - 1] |= 1; + self.delta_tables.adt[i][len - 1] |= 1; + self.delta_tables.fat_ydt[i][len - 1] |= 1; + self.delta_tables.fat_cdt[i][len - 1] |= 1; + } + + self.last_delta_set = delta_set; + self.last_table_idx = table_idx; + } + fn decode_16bit(&mut self, dst: &mut [u16], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> { + let mut off = 0; + index.get_next()?; + for y in 0..height { + let mut hor_pred: u32 = 0; + for x in (0..width).step_by(4) { + if mask.get_next() { + match y & 3 { + 0 => { + let dc0 = index.get_diff16(&self.delta_tables.cdt)?; + let dy0 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dc0); + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); + self.vert_pred[(x >> 1) + 0] = cur; + dst[off + x + 0] = cur as u16; + dst[off + x + 1] = (cur >> 16) as u16; + if self.blk_w == 2 { + let dc1 = index.get_diff16(&self.delta_tables.cdt)?; + hor_pred = hor_pred.wrapping_add(dc1); + } + let dy1 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + dst[off + x + 2] = cur as u16; + dst[off + x + 3] = (cur >> 16) as u16; + }, + 1 | 3 => { + let dy0 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); + self.vert_pred[(x >> 1) + 0] = cur; + dst[off + x + 0] = cur as u16; + dst[off + x + 1] = (cur >> 16) as u16; + let dy1 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + dst[off + x + 2] = cur as u16; + dst[off + x + 3] = (cur >> 16) as u16; + }, + 2 => { + if self.blk_h == 2 { + let dc0 = index.get_diff16(&self.delta_tables.cdt)?; + let dy0 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dc0); + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); + self.vert_pred[(x >> 1) + 0] = cur; + dst[off + x + 0] = cur as u16; + dst[off + x + 1] = (cur >> 16) as u16; + if self.blk_w == 2 { + let dc1 = index.get_diff16(&self.delta_tables.cdt)?; + hor_pred = hor_pred.wrapping_add(dc1); + } + let dy1 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + dst[off + x + 2] = cur as u16; + dst[off + x + 3] = (cur >> 16) as u16; + } else { + let dy0 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); + self.vert_pred[(x >> 1) + 0] = cur; + dst[off + x + 0] = cur as u16; + dst[off + x + 1] = (cur >> 16) as u16; + let dy1 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + dst[off + x + 2] = cur as u16; + dst[off + x + 3] = (cur >> 16) as u16; + } + }, + _ => unreachable!(), + }; + } else { + let cur = (dst[off + x + 0] as u32) | ((dst[off + x + 1] as u32) << 16); + self.vert_pred[(x >> 1) + 0] = cur; + let cur = (dst[off + x + 2] as u32) | ((dst[off + x + 3] as u32) << 16); + hor_pred = cur.wrapping_sub(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + } + } + if (y & 3) != 3 { + mask.reset_row(); + } else { + mask.next_row(); + } + off += stride; + } + Ok(()) + } + fn decode_sprite(&mut self, dst: &mut [u16], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> { + let mut off = 0; + let _ = index.get_next(); + for y in 0..height { + let mut hor_pred: u32 = 0; + for x in (0..width).step_by(4) { + let is_tm = !mask.get_next(); + let is_sprite = !mask.get_next(); + if is_tm { + if (y & 3) == 0 { + let dc0 = index.get_diff16(&self.delta_tables.cdt)?; + hor_pred = hor_pred.wrapping_add(dc0); + } + let dy0 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); + self.vert_pred[(x >> 1) + 0] = cur; + dst[off + x + 0] = cur as u16; + dst[off + x + 1] = (cur >> 16) as u16; + let dy1 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + dst[off + x + 2] = cur as u16; + dst[off + x + 3] = (cur >> 16) as u16; + } else if is_sprite { + if (y & 3) == 0 { + let dc0 = index.get_diff16(&self.delta_tables.cdt)?; + hor_pred = hor_pred.wrapping_add(dc0); + } + let dy0 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy0); + let _da0 = index.get_diff16_noesc(&self.delta_tables.adt)?; + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 0]); + self.vert_pred[(x >> 1) + 0] = cur; + dst[off + x + 0] = cur as u16; + dst[off + x + 1] = (cur >> 16) as u16; + let dy1 = index.get_diff16(&self.delta_tables.ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let _da1 = index.get_diff16_noesc(&self.delta_tables.adt)?; + let cur = hor_pred.wrapping_add(self.vert_pred[(x >> 1) + 1]); + self.vert_pred[(x >> 1) + 1] = cur; + dst[off + x + 2] = cur as u16; + dst[off + x + 3] = (cur >> 16) as u16; + } else { + hor_pred = 0; + dst[off + x + 0] = 0; + dst[off + x + 1] = 0; + dst[off + x + 2] = 0; + dst[off + x + 3] = 0; + self.vert_pred[(x >> 1) + 0] = 0; + self.vert_pred[(x >> 1) + 1] = 0; + } + } + if (y & 3) != 3 { + mask.reset_row(); + } else { + mask.next_row(); + } + off += stride; + } + Ok(()) + } + fn decode_24bit(&mut self, dst: &mut [u8], stride: usize, width: usize, height: usize, mask: &mut MaskState<'_>, index: &mut IndexState<'_>) -> DecoderResult<()> { + let mut off = 0; + index.get_next()?; + for y in 0..height { + let mut hor_pred: u32 = 0; + for x in (0..width).step_by(2) { + if mask.get_next() { + match y & 3 { + 0 => { + let dc0 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; + let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dc0); + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); + self.vert_pred[x + 0] = cur; + dst[off + x*4 + 0] = cur as u8; + dst[off + x*4 + 1] = (cur >> 8) as u8; + dst[off + x*4 + 2] = (cur >> 16) as u8; + dst[off + x*4 + 3] = 0; + if self.blk_w == 2 { + let dc1 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; + hor_pred = hor_pred.wrapping_add(dc1); + } + let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); + self.vert_pred[x + 1] = cur; + dst[off + x*4 + 4] = cur as u8; + dst[off + x*4 + 5] = (cur >> 8) as u8; + dst[off + x*4 + 6] = (cur >> 16) as u8; + dst[off + x*4 + 7] = 0; + }, + 1 | 3 => { + let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); + self.vert_pred[x + 0] = cur; + dst[off + x*4 + 0] = cur as u8; + dst[off + x*4 + 1] = (cur >> 8) as u8; + dst[off + x*4 + 2] = (cur >> 16) as u8; + dst[off + x*4 + 3] = 0; + let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); + self.vert_pred[x + 1] = cur; + dst[off + x*4 + 4] = cur as u8; + dst[off + x*4 + 5] = (cur >> 8) as u8; + dst[off + x*4 + 6] = (cur >> 16) as u8; + dst[off + x*4 + 7] = 0; + }, + 2 => { + if self.blk_h == 2 { + let dc0 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; + let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dc0); + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); + self.vert_pred[x + 0] = cur; + dst[off + x*4 + 0] = cur as u8; + dst[off + x*4 + 1] = (cur >> 8) as u8; + dst[off + x*4 + 2] = (cur >> 16) as u8; + dst[off + x*4 + 3] = 0; + if self.blk_w == 2 { + let dc1 = index.get_diff24(&self.delta_tables.cdt, &self.delta_tables.fat_cdt)?; + hor_pred = hor_pred.wrapping_add(dc1); + } + let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); + self.vert_pred[x + 1] = cur; + dst[off + x*4 + 4] = cur as u8; + dst[off + x*4 + 5] = (cur >> 8) as u8; + dst[off + x*4 + 6] = (cur >> 16) as u8; + dst[off + x*4 + 7] = 0; + } else { + let dy0 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dy0); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 0]); + self.vert_pred[x + 0] = cur; + dst[off + x*4 + 0] = cur as u8; + dst[off + x*4 + 1] = (cur >> 8) as u8; + dst[off + x*4 + 2] = (cur >> 16) as u8; + dst[off + x*4 + 3] = 0; + let dy1 = index.get_diff24(&self.delta_tables.ydt, &self.delta_tables.fat_ydt)?; + hor_pred = hor_pred.wrapping_add(dy1); + let cur = hor_pred.wrapping_add(self.vert_pred[x + 1]); + self.vert_pred[x + 1] = cur; + dst[off + x*4 + 4] = cur as u8; + dst[off + x*4 + 5] = (cur >> 8) as u8; + dst[off + x*4 + 6] = (cur >> 16) as u8; + dst[off + x*4 + 7] = 0; + } + }, + _ => unreachable!(), + }; + } else { + let cur = (dst[off + x*4 + 0] as u32) + | ((dst[off + x*4 + 1] as u32) << 8) + | ((dst[off + x*4 + 2] as u32) << 16) + | ((dst[off + x*4 + 3] as u32) << 24); + self.vert_pred[x + 0] = cur; + let cur = (dst[off + x*4 + 4] as u32) + | ((dst[off + x*4 + 5] as u32) << 8) + | ((dst[off + x*4 + 6] as u32) << 16) + | ((dst[off + x*4 + 7] as u32) << 24); + hor_pred = cur.wrapping_sub(self.vert_pred[x + 1]); + self.vert_pred[x + 1] = cur; + } + } + if (y & 3) != 3 { + mask.reset_row(); + } else { + mask.next_row(); + } + off += stride; + } + Ok(()) + } +} + +impl NADecoder for TM1Decoder { + fn init(&mut self, info: Rc) -> DecoderResult<()> { + if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { + let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT)); + 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(); + validate!(src.len() > 10); + let hdr_size = (src[0].rotate_left(3) & 0x7F) as usize; + validate!(hdr_size >= 12 && hdr_size < src.len()); + let mut hdr: [u8; 127] = [0; 127]; + for i in 1..hdr_size { + hdr[i - 1] = src[i] ^ src[i + 1]; + } + let mut mr = MemoryReader::new_read(&hdr[0..hdr_size-1]); + let mut br = ByteReader::new(&mut mr); + + let tm1type = br.read_byte()? as usize; + let delta_set = br.read_byte()? as usize; + let table_idx = br.read_byte()? as usize; + let height = br.read_u16le()? as usize; + let width = br.read_u16le()? as usize; + let _frameno = br.read_u16le()? as usize; + let version = br.read_byte()?; + let meta_type = br.read_byte()?; + validate!(width > 0 && height > 0); + let is_intra; + let mut is_sprite = false; + let mut spr_xoff = 0; + let mut spr_yoff = 0; + let mut spr_width = 0; + let mut spr_height = 0; + if version >= 2 { + validate!(meta_type <= 3); + if meta_type >= 2 { + let frameinfo = br.read_byte()?; + let _control = br.read_byte()?; + + is_intra = ((frameinfo & 0x10) != 0) || ((frameinfo & 0x08) == 0); + } else { + is_intra = true; + } + if meta_type == 3 { + spr_xoff = br.read_u16le()? as usize; + spr_yoff = br.read_u16le()? as usize; + spr_width = br.read_u16le()? as usize; + spr_height = br.read_u16le()? as usize; + is_sprite = true; + } + } else { + is_intra = true; + } + validate!(tm1type < TM1_COMPR_TYPES.len()); + let cinfo = TM1_COMPR_TYPES[tm1type]; + if cinfo.is_none() { +//check for missing ref + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None); + frm.set_keyframe(false); + frm.set_frame_type(FrameType::Skip); + return Ok(Rc::new(RefCell::new(frm))); + } + let compr_info = cinfo.unwrap(); + let is_24bit = !is_sprite && compr_info.is_24bit; + + let vec_idx = if ((tm1type & 1) != 0) && (meta_type > 0) { 1 } else { table_idx }; + validate!((delta_set < DUCK_Y_DELTAS.len()) && (vec_idx > 0) && (vec_idx <= DUCK_VECTABLES.len())); + self.set_delta_tables(delta_set, vec_idx, is_24bit); + + let out_width = if is_24bit { width >> 1 } else { width }; + let mask_row_size = if is_sprite { + ((spr_width >> 2) + 3) >> 2 + } else if is_intra { + 0 + } else { + ((width >> 2) + 7) >> 3 + }; + let mask_size = mask_row_size * (if is_sprite { spr_height >> 2 } else { height >> 2 }); + let mask_bits = &src[hdr_size..][..mask_size]; + let index_bytes = &src[hdr_size+mask_size..]; + validate!(src.len() >= hdr_size + mask_size); + self.vert_pred.truncate(0); + self.vert_pred.resize(out_width, 0); + + if is_intra || is_sprite { + let fmt = if is_24bit { BGR0_FORMAT } else { RGB555_FORMAT }; + let myinfo = NAVideoInfo::new(out_width, height, false, fmt); + let bufret = alloc_video_buffer(myinfo, 2); + if let Err(_) = bufret { return Err(DecoderError::InvalidData); } + let mut bufinfo = bufret.unwrap(); + self.lastframe.reset(); + if !is_24bit { + self.lastframe.set16(bufinfo.get_vbuf16().unwrap()); + } else { + self.lastframe.set24(bufinfo.get_vbuf().unwrap()); + } + } + + self.blk_w = compr_info.block_w; + self.blk_h = compr_info.block_h; + let mut mask = MaskState::new(is_intra && !is_sprite, &mask_bits, mask_row_size); + let mut index = IndexState::new(&index_bytes); + let bufinfo; + if !is_24bit { + if let Some(mut buf) = self.lastframe.get16() { + let stride = buf.get_stride(0); + { + let mut data = buf.get_data_mut(); + if !is_sprite { + self.decode_16bit(data.as_mut_slice(), stride, out_width, height, &mut mask, &mut index)?; + } else { + validate!(spr_xoff + spr_width <= out_width); + validate!(spr_yoff + spr_height <= height); + for el in data.iter_mut() { *el = 0; } + let dst = &mut data[spr_xoff + spr_yoff * stride..]; + self.decode_sprite(dst, stride, spr_width, spr_height, &mut mask, &mut index)?; + } + } + bufinfo = NABufferType::Video16(buf); + } else { + return Err(DecoderError::MissingReference); + } + } else { + if let Some(mut buf) = self.lastframe.get24() { + let stride = buf.get_stride(0); + { + let mut data = buf.get_data_mut(); + self.decode_24bit(data.as_mut_slice(), stride, out_width, height, &mut mask, &mut index)?; + } + bufinfo = NABufferType::VideoPacked(buf); + } else { + return Err(DecoderError::MissingReference); + } + } + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(is_intra || is_sprite); + frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); + Ok(Rc::new(RefCell::new(frm))) + } +} pub fn get_decoder() -> Box { -unimplemented!(); + Box::new(TM1Decoder::new()) } +#[cfg(test)] +mod test { + use nihav_core::codecs::RegisteredDecoders; + use nihav_core::demuxers::RegisteredDemuxers; + use nihav_core::test::dec_video::*; + use crate::codecs::duck_register_all_codecs; + use nihav_commonfmt::demuxers::generic_register_all_demuxers; + #[test] + fn test_tm1() { + let mut dmx_reg = RegisteredDemuxers::new(); + generic_register_all_demuxers(&mut dmx_reg); + let mut dec_reg = RegisteredDecoders::new(); + duck_register_all_codecs(&mut dec_reg); + + //let file = "assets/Duck/AVI-DUCK-dk3.duk"; + let file = "assets/Duck/phant2-940.duk"; + //let file = "assets/Duck/bugsampler-m01-16bit.avi"; + //let file = "assets/Duck/sonic3dblast_intro.avi"; + //let file = "assets/Duck/BUTTONS.AVI"; + //let file = "assets/Duck/SPRITES.AVI"; + //let file = "assets/Duck/TRICORD.AVI"; + test_file_decoding("avi", file, Some(42), true, false, None/*Some("tm1-")*/, &dmx_reg, &dec_reg); + } +} + +#[derive(Clone,Copy)] +struct TM1ComprInfo { + is_24bit: bool, + block_w: usize, + block_h: usize, +} + +const TM1_COMPR_TYPES: [Option; 17] = [ + None, + Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 4 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 4 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 2 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 4, block_h: 2 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 4 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 4 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 2 }), + Some(TM1ComprInfo { is_24bit: false, block_w: 2, block_h: 2 }), + None, + Some(TM1ComprInfo { is_24bit: true, block_w: 4, block_h: 4 }), + None, + Some(TM1ComprInfo { is_24bit: true, block_w: 4, block_h: 2 }), + None, + Some(TM1ComprInfo { is_24bit: true, block_w: 2, block_h: 4 }), + None, + Some(TM1ComprInfo { is_24bit: true, block_w: 2, block_h: 2 }), +]; + +const DUCK_Y_DELTAS: [[i32; 8]; 4] = [ + [ 0, -1, 1, -3, 3, -6, 6, -6 ], + [ 0, -1, 2, -3, 4, -6, 6, -6 ], + [ 2, -3, 10, -10, 23, -23, 47, -47 ], + [ 0, -2, 2, -8, 8, -18, 18, -40 ] +]; +const DUCK_Y_FAT_DELTA3: [i32; 8] = [ 0, -15, 50, -50, 115, -115, 235, -235 ]; +const DUCK_Y_FAT_DELTA4: [i32; 8] = [ 0, 40, 80, -76, 160, -154, 236, -236 ]; +const DUCK_Y_FAT_DELTAS: [&[i32]; 4] = [ + &DUCK_Y_FAT_DELTA3, &DUCK_Y_FAT_DELTA3, &DUCK_Y_FAT_DELTA3, &DUCK_Y_FAT_DELTA4 +]; + +const DUCK_C_DELTAS: [[i32; 8]; 4] = [ + [ 0, -1, 1, -2, 3, -4, 5, -4 ], + [ 0, -1, 1, -2, 3, -4, 5, -4 ], + [ 0, -4, 3, -16, 20, -32, 36, -32 ], + [ 0, -2, 2, -8, 8, -18, 18, -40 ] +]; +const DUCK_C_FAT_DELTA3: [i32; 8] = [ 0, -20, 15, -80, 100, -160, 180, -160 ]; +const DUCK_C_FAT_DELTAS: [&[i32]; 4] = [ + &DUCK_C_FAT_DELTA3, &DUCK_C_FAT_DELTA3, &DUCK_C_FAT_DELTA3, &DUCK_Y_FAT_DELTA4 +]; + +const DUCK_VECTBL2: &[u8] = &[ +0x8,0x00,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x00, +0x8,0x10,0x00,0x00,0x00, +0x8,0x01,0x00,0x00,0x00, +0x8,0x00,0x10,0x00,0x00, +0x8,0x00,0x01,0x00,0x00, +0x8,0x00,0x00,0x10,0x00, +0x8,0x00,0x00,0x01,0x00, +0x8,0x00,0x00,0x00,0x10, +0x8,0x00,0x00,0x00,0x01, +0x6,0x00,0x00,0x00, +0x6,0x10,0x00,0x00, +0x6,0x01,0x00,0x00, +0x6,0x00,0x10,0x00, +0x6,0x00,0x01,0x00, +0x6,0x00,0x00,0x01, +0x6,0x00,0x00,0x10, +0x6,0x00,0x00,0x02, +0x6,0x00,0x00,0x20, +0x6,0x20,0x10,0x00, +0x6,0x00,0x02,0x01, +0x6,0x00,0x20,0x10, +0x6,0x02,0x01,0x00, +0x6,0x11,0x00,0x00, +0x6,0x00,0x20,0x00, +0x6,0x00,0x02,0x00, +0x6,0x20,0x00,0x00, +0x6,0x01,0x10,0x00, +0x6,0x02,0x00,0x00, +0x6,0x01,0x00,0x02, +0x6,0x10,0x00,0x20, +0x6,0x00,0x01,0x02, +0x6,0x10,0x01,0x00, +0x6,0x00,0x10,0x20, +0x6,0x10,0x10,0x00, +0x6,0x10,0x00,0x01, +0x6,0x20,0x00,0x10, +0x6,0x02,0x00,0x01, +0x6,0x01,0x01,0x00, +0x6,0x01,0x00,0x10, +0x6,0x00,0x11,0x00, +0x6,0x10,0x00,0x02, +0x6,0x00,0x01,0x10, +0x6,0x00,0x00,0x11, +0x6,0x10,0x00,0x10, +0x6,0x01,0x00,0x01, +0x6,0x00,0x00,0x22, +0x6,0x02,0x01,0x01, +0x6,0x10,0x20,0x10, +0x6,0x01,0x02,0x01, +0x6,0x20,0x10,0x10, +0x6,0x01,0x00,0x20, +0x6,0x00,0x10,0x01, +0x6,0x21,0x10,0x00, +0x6,0x10,0x02,0x01, +0x6,0x12,0x01,0x00, +0x6,0x01,0x20,0x10, +0x6,0x01,0x02,0x00, +0x6,0x10,0x20,0x00, +0x6,0x00,0x10,0x02, +0x6,0x00,0x01,0x20, +0x6,0x00,0x02,0x21, +0x6,0x00,0x02,0x20, +0x6,0x00,0x00,0x12, +0x6,0x00,0x00,0x21, +0x6,0x20,0x11,0x00, +0x6,0x00,0x01,0x01, +0x6,0x11,0x10,0x00, +0x6,0x00,0x20,0x12, +0x6,0x00,0x20,0x11, +0x6,0x20,0x10,0x02, +0x6,0x02,0x01,0x20, +0x6,0x00,0x22,0x11, +0x6,0x00,0x10,0x10, +0x6,0x02,0x11,0x00, +0x6,0x00,0x21,0x10, +0x6,0x00,0x02,0x03, +0x6,0x20,0x10,0x01, +0x6,0x00,0x12,0x01, +0x4,0x11,0x00, +0x4,0x00,0x22, +0x4,0x20,0x00, +0x4,0x01,0x10, +0x4,0x02,0x20, +0x4,0x00,0x20, +0x4,0x02,0x00, +0x4,0x10,0x01, +0x4,0x00,0x11, +0x4,0x02,0x01, +0x4,0x02,0x21, +0x4,0x00,0x02, +0x4,0x20,0x02, +0x4,0x01,0x01, +0x4,0x10,0x10, +0x4,0x10,0x02, +0x4,0x22,0x00, +0x4,0x10,0x00, +0x4,0x01,0x00, +0x4,0x21,0x00, +0x4,0x12,0x00, +0x4,0x00,0x10, +0x4,0x20,0x12, +0x4,0x01,0x11, +0x4,0x00,0x01, +0x4,0x01,0x02, +0x4,0x11,0x02, +0x4,0x11,0x01, +0x4,0x10,0x20, +0x4,0x20,0x01, +0x4,0x22,0x11, +0x4,0x00,0x12, +0x4,0x20,0x10, +0x4,0x22,0x01, +0x4,0x01,0x20, +0x4,0x00,0x21, +0x4,0x10,0x11, +0x4,0x21,0x10, +0x4,0x10,0x22, +0x4,0x02,0x03, +0x4,0x12,0x01, +0x4,0x20,0x11, +0x4,0x11,0x10, +0x4,0x20,0x30, +0x4,0x11,0x20, +0x4,0x02,0x10, +0x4,0x22,0x10, +0x4,0x11,0x11, +0x4,0x30,0x20, +0x4,0x30,0x00, +0x4,0x01,0x22, +0x4,0x01,0x12, +0x4,0x02,0x11, +0x4,0x03,0x02, +0x4,0x03,0x00, +0x4,0x10,0x21, +0x4,0x12,0x20, +0x4,0x00,0x00, +0x4,0x12,0x21, +0x4,0x21,0x11, +0x4,0x02,0x22, +0x4,0x10,0x12, +0x4,0x31,0x00, +0x4,0x20,0x20, +0x4,0x00,0x03, +0x4,0x02,0x02, +0x4,0x22,0x20, +0x4,0x01,0x21, +0x4,0x21,0x02, +0x4,0x21,0x12, +0x4,0x11,0x22, +0x4,0x00,0x30, +0x4,0x12,0x11, +0x4,0x20,0x22, +0x4,0x31,0x20, +0x4,0x21,0x30, +0x4,0x22,0x02, +0x4,0x22,0x22, +0x4,0x20,0x31, +0x4,0x13,0x02, +0x4,0x03,0x10, +0x4,0x11,0x12, +0x4,0x00,0x13, +0x4,0x21,0x01, +0x4,0x12,0x03, +0x4,0x13,0x00, +0x4,0x13,0x10, +0x4,0x02,0x13, +0x4,0x30,0x01, +0x4,0x12,0x10, +0x4,0x22,0x13, +0x4,0x03,0x12, +0x4,0x31,0x01, +0x4,0x30,0x22, +0x4,0x00,0x31, +0x4,0x01,0x31, +0x4,0x02,0x23, +0x4,0x01,0x30, +0x4,0x11,0x21, +0x4,0x22,0x21, +0x4,0x01,0x13, +0x4,0x10,0x03, +0x4,0x22,0x03, +0x4,0x30,0x21, +0x4,0x21,0x31, +0x4,0x33,0x00, +0x4,0x13,0x12, +0x4,0x11,0x31, +0x4,0x30,0x02, +0x4,0x12,0x02, +0x4,0x11,0x13, +0x4,0x12,0x22, +0x4,0x20,0x32, +0x4,0x10,0x13, +0x4,0x22,0x31, +0x4,0x21,0x20, +0x4,0x01,0x33, +0x4,0x33,0x10, +0x4,0x20,0x13, +0x4,0x31,0x22, +0x4,0x13,0x30, +0x4,0x01,0x03, +0x4,0x11,0x33, +0x4,0x20,0x21, +0x4,0x13,0x31, +0x4,0x03,0x22, +0x4,0x31,0x02, +0x4,0x00,0x24, +0x2,0x00, +0x2,0x10, +0x2,0x20, +0x2,0x30, +0x2,0x40, +0x2,0x50, +0x2,0x60, +0x2,0x01, +0x2,0x11, +0x2,0x21, +0x2,0x31, +0x2,0x41, +0x2,0x51, +0x2,0x61, +0x2,0x02, +0x2,0x12, +0x2,0x22, +0x2,0x32, +0x2,0x42, +0x2,0x52, +0x2,0x62, +0x2,0x03, +0x2,0x13, +0x2,0x23, +0x2,0x33, +0x2,0x43, +0x2,0x53, +0x2,0x63, +0x2,0x04, +0x2,0x14, +0x2,0x24, +0x2,0x34, +0x2,0x44, +0x2,0x54, +0x2,0x64, +0x2,0x05, +0x2,0x15, +0x2,0x25, +0x2,0x35, +0x2,0x45, +0x2,0x55, +0x2,0x65, +0x2,0x06, +0x2,0x16, +0x2,0x26, +0x2,0x36, +0x2,0x46, +0x2,0x56, +0x2,0x66 +]; + +const DUCK_VECTBL3: &[u8] = &[ +0x6,0x00,0x00,0x00, +0x6,0x00,0x00,0x00, +0x6,0x00,0x00,0x01, +0x6,0x00,0x00,0x10, +0x6,0x00,0x00,0x11, +0x6,0x00,0x01,0x00, +0x6,0x00,0x01,0x01, +0x6,0x00,0x01,0x10, +0x6,0x00,0x01,0x11, +0x6,0x00,0x10,0x00, +0x6,0x00,0x10,0x01, +0x6,0x00,0x10,0x10, +0x6,0x00,0x10,0x11, +0x6,0x00,0x11,0x00, +0x6,0x00,0x11,0x01, +0x6,0x00,0x11,0x10, +0x6,0x00,0x11,0x11, +0x6,0x01,0x00,0x00, +0x6,0x01,0x00,0x01, +0x6,0x01,0x00,0x10, +0x6,0x01,0x00,0x11, +0x6,0x01,0x01,0x00, +0x6,0x01,0x01,0x01, +0x6,0x01,0x01,0x10, +0x6,0x01,0x01,0x11, +0x6,0x01,0x10,0x00, +0x6,0x01,0x10,0x01, +0x6,0x01,0x10,0x10, +0x6,0x01,0x10,0x11, +0x6,0x01,0x11,0x00, +0x6,0x01,0x11,0x01, +0x6,0x01,0x11,0x10, +0x6,0x01,0x11,0x11, +0x6,0x10,0x00,0x00, +0x6,0x10,0x00,0x01, +0x6,0x10,0x00,0x10, +0x6,0x10,0x00,0x11, +0x6,0x10,0x01,0x00, +0x6,0x10,0x01,0x01, +0x6,0x10,0x01,0x10, +0x6,0x10,0x01,0x11, +0x6,0x10,0x10,0x00, +0x6,0x10,0x10,0x01, +0x6,0x10,0x10,0x10, +0x6,0x10,0x10,0x11, +0x6,0x10,0x11,0x00, +0x6,0x10,0x11,0x01, +0x6,0x10,0x11,0x10, +0x6,0x10,0x11,0x11, +0x6,0x11,0x00,0x00, +0x6,0x11,0x00,0x01, +0x6,0x11,0x00,0x10, +0x6,0x11,0x00,0x11, +0x6,0x11,0x01,0x00, +0x6,0x11,0x01,0x01, +0x6,0x11,0x01,0x10, +0x6,0x11,0x01,0x11, +0x6,0x11,0x10,0x00, +0x6,0x11,0x10,0x01, +0x6,0x11,0x10,0x10, +0x6,0x11,0x10,0x11, +0x6,0x11,0x11,0x00, +0x6,0x11,0x11,0x01, +0x6,0x11,0x11,0x10, +0x4,0x00,0x00, +0x4,0x00,0x01, +0x4,0x00,0x02, +0x4,0x00,0x03, +0x4,0x00,0x10, +0x4,0x00,0x11, +0x4,0x00,0x12, +0x4,0x00,0x13, +0x4,0x00,0x20, +0x4,0x00,0x21, +0x4,0x00,0x22, +0x4,0x00,0x23, +0x4,0x00,0x30, +0x4,0x00,0x31, +0x4,0x00,0x32, +0x4,0x00,0x33, +0x4,0x01,0x00, +0x4,0x01,0x01, +0x4,0x01,0x02, +0x4,0x01,0x03, +0x4,0x01,0x10, +0x4,0x01,0x11, +0x4,0x01,0x12, +0x4,0x01,0x13, +0x4,0x01,0x20, +0x4,0x01,0x21, +0x4,0x01,0x22, +0x4,0x01,0x23, +0x4,0x01,0x30, +0x4,0x01,0x31, +0x4,0x01,0x32, +0x4,0x01,0x33, +0x4,0x02,0x00, +0x4,0x02,0x01, +0x4,0x02,0x02, +0x4,0x02,0x03, +0x4,0x02,0x10, +0x4,0x02,0x11, +0x4,0x02,0x12, +0x4,0x02,0x13, +0x4,0x02,0x20, +0x4,0x02,0x21, +0x4,0x02,0x22, +0x4,0x02,0x23, +0x4,0x02,0x30, +0x4,0x02,0x31, +0x4,0x02,0x32, +0x4,0x02,0x33, +0x4,0x03,0x00, +0x4,0x03,0x01, +0x4,0x03,0x02, +0x4,0x03,0x03, +0x4,0x03,0x10, +0x4,0x03,0x11, +0x4,0x03,0x12, +0x4,0x03,0x13, +0x4,0x03,0x20, +0x4,0x03,0x21, +0x4,0x03,0x22, +0x4,0x03,0x23, +0x4,0x03,0x30, +0x4,0x03,0x31, +0x4,0x03,0x32, +0x4,0x03,0x33, +0x4,0x10,0x00, +0x4,0x10,0x01, +0x4,0x10,0x02, +0x4,0x10,0x03, +0x4,0x10,0x10, +0x4,0x10,0x11, +0x4,0x10,0x12, +0x4,0x10,0x13, +0x4,0x10,0x20, +0x4,0x10,0x21, +0x4,0x10,0x22, +0x4,0x10,0x23, +0x4,0x10,0x30, +0x4,0x10,0x31, +0x4,0x10,0x32, +0x4,0x10,0x33, +0x4,0x11,0x00, +0x4,0x11,0x01, +0x4,0x11,0x02, +0x4,0x11,0x03, +0x4,0x11,0x10, +0x4,0x11,0x11, +0x4,0x11,0x12, +0x4,0x11,0x13, +0x4,0x11,0x20, +0x4,0x11,0x21, +0x4,0x11,0x22, +0x4,0x11,0x23, +0x4,0x11,0x30, +0x4,0x11,0x31, +0x4,0x11,0x32, +0x4,0x11,0x33, +0x4,0x12,0x00, +0x4,0x12,0x01, +0x4,0x12,0x02, +0x4,0x12,0x03, +0x4,0x12,0x10, +0x4,0x12,0x11, +0x4,0x12,0x12, +0x4,0x12,0x13, +0x4,0x12,0x20, +0x4,0x12,0x21, +0x4,0x12,0x22, +0x4,0x12,0x23, +0x4,0x12,0x30, +0x4,0x12,0x31, +0x4,0x12,0x32, +0x4,0x12,0x33, +0x4,0x13,0x00, +0x4,0x13,0x01, +0x4,0x13,0x02, +0x4,0x13,0x03, +0x4,0x13,0x10, +0x4,0x13,0x11, +0x4,0x13,0x12, +0x4,0x13,0x13, +0x4,0x13,0x20, +0x4,0x13,0x21, +0x4,0x13,0x22, +0x4,0x13,0x23, +0x4,0x13,0x30, +0x4,0x13,0x31, +0x4,0x13,0x32, +0x4,0x13,0x33, +0x2,0x00, +0x2,0x10, +0x2,0x20, +0x2,0x30, +0x2,0x40, +0x2,0x50, +0x2,0x60, +0x2,0x70, +0x2,0x01, +0x2,0x11, +0x2,0x21, +0x2,0x31, +0x2,0x41, +0x2,0x51, +0x2,0x61, +0x2,0x71, +0x2,0x02, +0x2,0x12, +0x2,0x22, +0x2,0x32, +0x2,0x42, +0x2,0x52, +0x2,0x62, +0x2,0x72, +0x2,0x03, +0x2,0x13, +0x2,0x23, +0x2,0x33, +0x2,0x43, +0x2,0x53, +0x2,0x63, +0x2,0x73, +0x2,0x04, +0x2,0x14, +0x2,0x24, +0x2,0x34, +0x2,0x44, +0x2,0x54, +0x2,0x64, +0x2,0x74, +0x2,0x05, +0x2,0x15, +0x2,0x25, +0x2,0x35, +0x2,0x45, +0x2,0x55, +0x2,0x65, +0x2,0x75, +0x2,0x06, +0x2,0x16, +0x2,0x26, +0x2,0x36, +0x2,0x46, +0x2,0x56, +0x2,0x66, +0x2,0x76, +0x2,0x07, +0x2,0x17, +0x2,0x27, +0x2,0x37, +0x2,0x47, +0x2,0x57, +0x2,0x67, +0x2,0x77 +]; + +const DUCK_VECTBL4: &[u8] = &[ +0x8,0x00,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x00, +0x8,0x20,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x01, +0x8,0x10,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x02, +0x8,0x01,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x10, +0x8,0x02,0x00,0x00,0x00, +0x6,0x00,0x00,0x00, +0x6,0x20,0x00,0x00, +0x6,0x00,0x00,0x01, +0x6,0x10,0x00,0x00, +0x6,0x00,0x00,0x02, +0x6,0x00,0x10,0x00, +0x6,0x00,0x20,0x00, +0x6,0x00,0x02,0x00, +0x6,0x00,0x01,0x00, +0x6,0x01,0x00,0x00, +0x6,0x00,0x00,0x20, +0x6,0x02,0x00,0x00, +0x6,0x00,0x00,0x10, +0x6,0x10,0x00,0x20, +0x6,0x01,0x00,0x02, +0x6,0x20,0x00,0x10, +0x6,0x02,0x00,0x01, +0x6,0x20,0x10,0x00, +0x6,0x00,0x12,0x00, +0x6,0x00,0x02,0x01, +0x6,0x02,0x01,0x00, +0x6,0x00,0x21,0x00, +0x6,0x00,0x01,0x02, +0x6,0x00,0x20,0x10, +0x6,0x00,0x00,0x21, +0x6,0x00,0x00,0x12, +0x6,0x00,0x01,0x20, +0x6,0x12,0x00,0x00, +0x6,0x00,0x10,0x20, +0x6,0x01,0x20,0x00, +0x6,0x02,0x10,0x00, +0x6,0x10,0x20,0x00, +0x6,0x01,0x02,0x00, +0x6,0x21,0x00,0x00, +0x6,0x00,0x02,0x10, +0x6,0x20,0x01,0x00, +0x6,0x00,0x22,0x00, +0x6,0x10,0x02,0x00, +0x6,0x00,0x10,0x02, +0x6,0x11,0x00,0x00, +0x6,0x00,0x11,0x00, +0x6,0x22,0x00,0x00, +0x6,0x20,0x00,0x02, +0x6,0x10,0x00,0x01, +0x6,0x00,0x20,0x01, +0x6,0x02,0x20,0x00, +0x6,0x01,0x10,0x00, +0x6,0x01,0x00,0x20, +0x6,0x00,0x20,0x02, +0x6,0x01,0x20,0x02, +0x6,0x10,0x01,0x00, +0x6,0x02,0x00,0x10, +0x6,0x00,0x10,0x01, +0x6,0x10,0x01,0x20, +0x6,0x20,0x02,0x10, +0x6,0x00,0x00,0x22, +0x6,0x10,0x00,0x02, +0x6,0x00,0x02,0x20, +0x6,0x20,0x02,0x00, +0x6,0x00,0x00,0x11, +0x6,0x02,0x10,0x01, +0x6,0x00,0x01,0x10, +0x6,0x00,0x02,0x11, +0x4,0x01,0x02, +0x4,0x02,0x01, +0x4,0x01,0x00, +0x4,0x10,0x20, +0x4,0x20,0x10, +0x4,0x20,0x00, +0x4,0x11,0x00, +0x4,0x02,0x00, +0x4,0x12,0x00, +0x4,0x00,0x21, +0x4,0x22,0x00, +0x4,0x00,0x12, +0x4,0x21,0x00, +0x4,0x02,0x11, +0x4,0x00,0x01, +0x4,0x10,0x02, +0x4,0x02,0x20, +0x4,0x20,0x11, +0x4,0x01,0x10, +0x4,0x21,0x10, +0x4,0x10,0x00, +0x4,0x10,0x22, +0x4,0x20,0x20, +0x4,0x00,0x22, +0x4,0x01,0x22, +0x4,0x20,0x01, +0x4,0x02,0x02, +0x4,0x00,0x20, +0x4,0x00,0x10, +0x4,0x00,0x11, +0x4,0x22,0x01, +0x4,0x11,0x20, +0x4,0x12,0x01, +0x4,0x12,0x20, +0x4,0x11,0x02, +0x4,0x10,0x10, +0x4,0x01,0x01, +0x4,0x02,0x21, +0x4,0x20,0x12, +0x4,0x01,0x12, +0x4,0x22,0x11, +0x4,0x21,0x12, +0x4,0x22,0x10, +0x4,0x21,0x02, +0x4,0x20,0x02, +0x4,0x10,0x01, +0x4,0x00,0x02, +0x4,0x10,0x21, +0x4,0x01,0x20, +0x4,0x11,0x22, +0x4,0x12,0x21, +0x4,0x22,0x20, +0x4,0x02,0x10, +0x4,0x02,0x22, +0x4,0x11,0x10, +0x4,0x22,0x02, +0x4,0x20,0x21, +0x4,0x01,0x11, +0x4,0x11,0x01, +0x4,0x10,0x12, +0x4,0x02,0x12, +0x4,0x20,0x22, +0x4,0x21,0x20, +0x4,0x01,0x21, +0x4,0x12,0x02, +0x4,0x21,0x11, +0x4,0x12,0x22, +0x4,0x12,0x10, +0x4,0x22,0x21, +0x4,0x10,0x11, +0x4,0x21,0x01, +0x4,0x11,0x12, +0x4,0x12,0x11, +0x4,0x66,0x66, +0x4,0x22,0x22, +0x4,0x11,0x21, +0x4,0x11,0x11, +0x4,0x21,0x22, +0x4,0x00,0x00, +0x4,0x22,0x12, +0x4,0x12,0x12, +0x4,0x21,0x21, +0x4,0x42,0x00, +0x4,0x00,0x04, +0x4,0x40,0x00, +0x4,0x30,0x00, +0x4,0x31,0x00, +0x4,0x00,0x03, +0x4,0x00,0x14, +0x4,0x00,0x13, +0x4,0x01,0x24, +0x4,0x20,0x13, +0x4,0x01,0x42, +0x4,0x14,0x20, +0x4,0x42,0x02, +0x4,0x13,0x00, +0x4,0x00,0x24, +0x4,0x31,0x20, +0x4,0x22,0x13, +0x4,0x11,0x24, +0x4,0x12,0x66, +0x4,0x30,0x01, +0x4,0x02,0x13, +0x4,0x12,0x42, +0x4,0x40,0x10, +0x4,0x40,0x02, +0x4,0x01,0x04, +0x4,0x24,0x00, +0x4,0x42,0x10, +0x4,0x21,0x13, +0x4,0x13,0x12, +0x4,0x31,0x21, +0x4,0x21,0x24, +0x4,0x00,0x40, +0x4,0x10,0x24, +0x4,0x10,0x42, +0x4,0x32,0x01, +0x4,0x11,0x42, +0x4,0x20,0x31, +0x4,0x12,0x40, +0x2,0x00, +0x2,0x10, +0x2,0x20, +0x2,0x30, +0x2,0x40, +0x2,0x50, +0x2,0x60, +0x2,0x70, +0x2,0x01, +0x2,0x11, +0x2,0x21, +0x2,0x31, +0x2,0x41, +0x2,0x51, +0x2,0x61, +0x2,0x71, +0x2,0x02, +0x2,0x12, +0x2,0x22, +0x2,0x32, +0x2,0x42, +0x2,0x52, +0x2,0x62, +0x2,0x72, +0x2,0x03, +0x2,0x13, +0x2,0x23, +0x2,0x33, +0x2,0x43, +0x2,0x53, +0x2,0x63, +0x2,0x73, +0x2,0x04, +0x2,0x14, +0x2,0x24, +0x2,0x34, +0x2,0x44, +0x2,0x54, +0x2,0x64, +0x2,0x74, +0x2,0x05, +0x2,0x15, +0x2,0x25, +0x2,0x35, +0x2,0x45, +0x2,0x55, +0x2,0x65, +0x2,0x75, +0x2,0x06, +0x2,0x16, +0x2,0x26, +0x2,0x36, +0x2,0x46, +0x2,0x56, +0x2,0x66, +0x2,0x76, +0x2,0x07, +0x2,0x17, +0x2,0x27, +0x2,0x37, +0x2,0x47, +0x2,0x57, +0x2,0x67, +0x2,0x77 +]; + +const DUCK_VECTABLES: [&[u8]; 3] = [ DUCK_VECTBL2, DUCK_VECTBL3, DUCK_VECTBL4 ];