From 8bde0eaee45d07c3a7280e53cd155ea8728e2536 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 13 Feb 2019 10:29:26 +0100 Subject: [PATCH] Duck TrueMotion2 decoder --- nihav-duck/Cargo.toml | 2 +- nihav-duck/src/codecs/truemotion2.rs | 612 +++++++++++++++++++++++++++ 2 files changed, 613 insertions(+), 1 deletion(-) create mode 100644 nihav-duck/src/codecs/truemotion2.rs diff --git a/nihav-duck/Cargo.toml b/nihav-duck/Cargo.toml index fa4d1cd..e3d8fee 100644 --- a/nihav-duck/Cargo.toml +++ b/nihav-duck/Cargo.toml @@ -14,7 +14,7 @@ nihav_commonfmt = { path = "../nihav-commonfmt" } [features] default = ["all_decoders"] -all_decoders = ["decoder_truemotion1", "decoder_truemotionrt", "decoder_dk3_adpcm", "decoder_dk4_adpcm"]#, "decoder_truemotion2", "decoder_truemotion2x", "decoder_truemotion3", "decoder_truemotion4", "decoder_truemotion5", "decoder_truemotion6", "decoder_truemotion7", "decoder_on2avc"] +all_decoders = ["decoder_truemotion1", "decoder_truemotionrt", "decoder_dk3_adpcm", "decoder_dk4_adpcm", "decoder_truemotion2"]#, "decoder_truemotion2x", "decoder_truemotion3", "decoder_truemotion4", "decoder_truemotion5", "decoder_truemotion6", "decoder_truemotion7", "decoder_on2avc"] decoders = [] decoder_truemotion1 = ["decoders"] diff --git a/nihav-duck/src/codecs/truemotion2.rs b/nihav-duck/src/codecs/truemotion2.rs new file mode 100644 index 0000000..83cdce6 --- /dev/null +++ b/nihav-duck/src/codecs/truemotion2.rs @@ -0,0 +1,612 @@ +use nihav_core::codecs::*; +use nihav_core::io::byteio::*; +use nihav_core::io::bitreader::*; +use nihav_core::io::codebook::*; + +#[repr(u8)] +enum TM2StreamType { + CHigh = 0, + CLow, + LHigh, + LLow, + Update, + Motion, + BlockType, + Num +} + +#[repr(u8)] +#[derive(Debug,Clone,Copy)] +enum TM2BlockType { + HiRes, + MedRes, + LowRes, + NullRes, + Update, + Still, + Motion +} + +const TM2_BLOCK_TYPES: [TM2BlockType; 7] = [ + TM2BlockType::HiRes, TM2BlockType::MedRes, TM2BlockType::LowRes, TM2BlockType::NullRes, + TM2BlockType::Update, TM2BlockType::Still, TM2BlockType::Motion +]; + +trait ReadLenEsc { + fn read_len_esc(&mut self) -> DecoderResult; +} + +const TM2_ESCAPE: usize = 0x80000000; + +impl<'a> ReadLenEsc for ByteReader<'a> { + fn read_len_esc(&mut self) -> DecoderResult { + let len = self.read_u32le()? as usize; + if len == TM2_ESCAPE { + let len2 = self.read_u32le()? as usize; + Ok(len2) + } else { + Ok(len) + } + } +} + +struct HuffDef { + val_bits: u8, + max_bits: u8, + nelems: usize, +} + +impl HuffDef { + fn read(&mut self, br: &mut BitReader, codes: &mut Vec>, prefix: u32, len: u8) -> DecoderResult<()> { + validate!(len <= self.max_bits); + if !br.read_bool()? { + validate!(codes.len() < self.nelems); + let sym = br.read(self.val_bits)? as u8; + codes.push(FullCodebookDesc { code: prefix, bits: len, sym }); + } else { + self.read(br, codes, (prefix << 1) | 0, len + 1)?; + self.read(br, codes, (prefix << 1) | 1, len + 1)?; + } + Ok(()) + } +} + +struct HuffTree { + cb: Option>, + sym0: u8, +} + +impl HuffTree { + fn new() -> Self { + Self { cb: None, sym0: 0 } + } +} + +const TM2_MAX_DELTAS: usize = 64; + +struct TM2Stream { + tokens: Vec, + deltas: [i32; TM2_MAX_DELTAS], + pos: usize, +} + +impl Default for TM2Stream { + fn default() -> Self { + Self { + tokens: Vec::new(), + deltas: [0; TM2_MAX_DELTAS], + pos: 0, + } + } +} + +impl TM2Stream { + fn read_header(&mut self, src: &[u8], br: &mut ByteReader) -> DecoderResult<()> { + self.tokens.truncate(0); + self.pos = 0; + + let len = br.read_u32le()? as usize; + let endpos = br.tell() + (len as u64) * 4; + if len == 0 { + return Ok(()); + } + let ntoks = br.read_u32le()? as usize; + validate!(ntoks < (1 << 24)); + if (ntoks & 1) != 0 { + let dlen = br.read_len_esc()?; + if (dlen as i32) > 0 { + let rest_size = (endpos - br.tell()) as usize; + let skip_size = self.read_deltas(&src[br.tell() as usize..][..rest_size])?; + validate!(skip_size == dlen * 4); + br.read_skip(skip_size)?; + } + } + let _len = br.read_len_esc()?; + let _algo = br.read_u32le()?; + + let mut htree = HuffTree::new(); + let rest_size = (endpos - br.tell()) as usize; + let skip_size = self.read_huff_tree(&src[br.tell() as usize..][..rest_size], &mut htree)?; + br.read_skip(skip_size)?; + + let len = br.read_u32le()? as usize; + validate!(br.tell() + (len as u64) * 4 <= endpos); + if len > 0 { + self.tokens.reserve(ntoks >> 1); + let rest_size = (endpos - br.tell()) as usize; + let skip_size = self.read_tokens(&src[br.tell() as usize..][..rest_size], &htree, ntoks >> 1)?; + br.read_skip(skip_size)?; + } else { + self.tokens.resize(ntoks >> 1, htree.sym0); + } + + + let pos = br.tell(); + validate!(pos <= endpos); + let toskip = endpos - pos; + br.read_skip(toskip as usize)?; + + Ok(()) + } + fn read_deltas(&mut self, src: &[u8]) -> DecoderResult { + let mut br = BitReader::new(src, src.len(), BitReaderMode::LE32MSB); + let coded_deltas = br.read(9)? as usize; + let bits = br.read(5)? as u8; + validate!((coded_deltas <= TM2_MAX_DELTAS) && (bits > 0)); + let mask = 1 << (bits - 1); + let bias = 1 << bits; + self.deltas = [0; TM2_MAX_DELTAS]; + for i in 0..coded_deltas { + let val = br.read(bits)?; + if (val & mask) != 0 { + self.deltas[i] = (val as i32) - bias; + } else { + self.deltas[i] = val as i32; + } + } + + Ok(((br.tell() + 31) >> 5) << 2) + } + fn read_huff_tree(&mut self, src: &[u8], htree: &mut HuffTree) -> DecoderResult { + let mut br = BitReader::new(src, src.len(), BitReaderMode::LE32MSB); + + let val_bits = br.read(5)? as u8; + let max_bits = br.read(5)? as u8; + let min_bits = br.read(5)? as u8; + let nelems = br.read(17)? as usize; + validate!(val_bits > 0 && val_bits <= 6); + validate!(nelems > 0); + validate!((max_bits < 25) && (min_bits <= max_bits)); + + let mut codes: Vec> = Vec::with_capacity(nelems); + let mut hdef = HuffDef { val_bits, max_bits, nelems }; + hdef.read(&mut br, &mut codes, 0, 0)?; + htree.sym0 = codes[0].sym; + if nelems > 1 { + let mut cr = FullCodebookDescReader::new(codes); + htree.cb = Some(Codebook::new(&mut cr, CodebookMode::MSB)?); + } + + Ok(((br.tell() + 31) >> 5) << 2) + } + fn read_tokens(&mut self, src: &[u8], htree: &HuffTree, ntoks: usize) -> DecoderResult { + let mut br = BitReader::new(src, src.len(), BitReaderMode::LE32MSB); + + if let Some(ref cb) = htree.cb { + for _ in 0..ntoks { + let tok = br.read_cb(cb)?; + self.tokens.push(tok); + } + } + + Ok(((br.tell() + 31) >> 5) << 2) + } + + fn get_block_type(&mut self) -> DecoderResult { + validate!(self.pos < self.tokens.len()); + let res = self.tokens[self.pos]; + self.pos += 1; + Ok(res) + } + fn get_token(&mut self) -> DecoderResult { + validate!(self.pos < self.tokens.len()); + let idx = self.tokens[self.pos] as usize; + validate!(idx < TM2_MAX_DELTAS); + self.pos += 1; + Ok(self.deltas[idx]) + } +} + +#[derive(Default)] +struct DeltaState { + dy: [i32; 4], + dc: [[i32; 2]; 2], +} + +impl DeltaState { + fn apply_y(&mut self, dst: &mut [u8], mut yoff: usize, ystride: usize, ydeltas: &[i32; 16], last: &mut [i32]) { + for y in 0..4 { + let mut d = self.dy[y]; + for x in 0..4 { + d += ydeltas[x + y * 4]; + last[x] += d; + dst[yoff + x] = last[x].max(0).min(255) as u8; + } + self.dy[y] = d; + yoff += ystride; + } + } + fn apply_c(&mut self, dst: &mut [i16], mut coff: usize, cstride: usize, cdeltas: &[i32; 4], idx: usize, last: &mut [i32]) { + for y in 0..2 { + let mut d = self.dc[idx][y]; + for x in 0..2 { + d += cdeltas[x + y * 2]; + last[x] += d; + dst[coff + x] = last[x] as i16; + } + self.dc[idx][y] = d; + coff += cstride; + } + } + fn interpolate_y_low(&mut self, last: &mut [i32]) { + let dsum = self.dy[0] + self.dy[1] + self.dy[2] + self.dy[3]; + last[1] = (last[0] - dsum + last[2]) >> 1; + last[3] = (last[2] + last[4]) >> 1; + + let t0 = self.dy[0] + self.dy[1]; + let t1 = self.dy[2] + self.dy[3]; + self.dy[0] = t0 >> 1; + self.dy[1] = t0 - (t0 >> 1); + self.dy[2] = t1 >> 1; + self.dy[3] = t1 - (t1 >> 1); + } + fn interpolate_y_null(&mut self, last: &mut [i32]) { + let dsum = self.dy[0] + self.dy[1] + self.dy[2] + self.dy[3]; + let left = last[0] - dsum; + let right = last[4]; + let diff = right - left; + last[1] = left + (diff >> 2); + last[2] = left + (diff >> 1); + last[3] = right - (diff >> 2); + + let mut sum = left; + self.dy[0] = (left + (dsum >> 2)) - sum; + sum += self.dy[0]; + self.dy[1] = (left + (dsum >> 1)) - sum; + sum += self.dy[1]; + self.dy[2] = (left + dsum - (dsum >> 2)) - sum; + sum += self.dy[2]; + self.dy[3] = (left + dsum) - sum; + } + fn interpolate_c(&mut self, idx: usize, last: &mut [i32]) { + let dsum = self.dc[idx][0] + self.dc[idx][1]; + let l = (last[0] + last[2] - dsum) >> 1; + self.dc[idx][0] = dsum >> 1; + self.dc[idx][1] = dsum - (dsum >> 1); + last[1] = l; + } + fn recalc_y(&mut self, dst: &[u8], yoff: usize, ystride: usize, last: &mut [i32]) { + let src = &dst[yoff+3..]; + self.dy[0] = (src[ystride * 0] as i32) - last[3]; + self.dy[1] = (src[ystride * 1] as i32) - (src[ystride * 0] as i32); + self.dy[2] = (src[ystride * 2] as i32) - (src[ystride * 1] as i32); + self.dy[3] = (src[ystride * 3] as i32) - (src[ystride * 2] as i32); + let src = &dst[yoff + 3 * ystride..]; + for x in 0..4 { + last[x] = src[x] as i32; + } + } + fn recalc_c(&mut self, dst: &[i16], coff: usize, cstride: usize, idx: usize, last: &mut [i32]) { + self.dc[idx][0] = (dst[coff + 1] as i32) - last[1]; + self.dc[idx][1] = (dst[coff + 1 + cstride] as i32) - (dst[coff + 1] as i32); + last[0] = dst[coff + cstride + 0] as i32; + last[1] = dst[coff + cstride + 1] as i32; + } +} + +#[derive(Default)] +struct TM2Frame { + ydata: Vec, + udata: Vec, + vdata: Vec, + ystride: usize, + cstride: usize, +} + +impl TM2Frame { + fn alloc(width: usize, height: usize) -> Self { + let ystride = (width + 3) & !3; + let ysize = ystride * ((height + 3) & !3); + let mut ydata = Vec::with_capacity(ysize); + ydata.resize(ysize, 0); + let cstride = ystride >> 1; + let csize = cstride * (((height + 3) & !3) >> 1); + let mut udata = Vec::with_capacity(csize); + udata.resize(csize, 0); + let mut vdata = Vec::with_capacity(csize); + vdata.resize(csize, 0); + Self { ydata, udata, vdata, ystride, cstride } + } +} + +#[derive(Default)] +struct TM2Decoder { + info: Rc, + streams: [TM2Stream; TM2StreamType::Num as usize], + width: usize, + height: usize, + cur_frame: TM2Frame, + prev_frame: TM2Frame, +} + +impl TM2Decoder { + fn new() -> Self { Self::default() } + fn decode_blocks(&mut self) -> DecoderResult { + let ydst = &mut self.cur_frame.ydata; + let udst = &mut self.cur_frame.udata; + let vdst = &mut self.cur_frame.vdata; + let ystride = self.cur_frame.ystride; + let cstride = self.cur_frame.cstride; + let mut offs: [usize; 2] = [0; 2]; + let mut is_intra = true; + + let bw = self.width >> 2; + let bh = self.height >> 2; + validate!(self.streams[TM2StreamType::BlockType as usize].tokens.len() == bw * bh); + + let mut ydeltas: [i32; 16] = [0; 16]; + let mut cdeltas: [[i32; 4]; 2] = [[0; 4]; 2]; + let mut lasty: Vec = Vec::with_capacity(self.width + 1); + lasty.resize(self.width + 1, 0); + let mut lastu: Vec = Vec::with_capacity(self.width/2 + 1); + lastu.resize(self.width/2 + 1, 0); + let mut lastv: Vec = Vec::with_capacity(self.width/2 + 1); + lastv.resize(self.width/2 + 1, 0); + for by in 0..bh { + let mut dstate = DeltaState::default(); + for bx in 0..bw { + let bidx = self.streams[TM2StreamType::BlockType as usize].get_block_type()? as usize; + validate!(bidx < TM2_BLOCK_TYPES.len()); + let btype = TM2_BLOCK_TYPES[bidx]; + match btype { + TM2BlockType::HiRes => { + for i in 0..4 { + cdeltas[0][i] = self.streams[TM2StreamType::CHigh as usize].get_token()?; + cdeltas[1][i] = self.streams[TM2StreamType::CHigh as usize].get_token()?; + } + dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); + dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); + for i in 0..4*4 { + ydeltas[i] = self.streams[TM2StreamType::LHigh as usize].get_token()?; + } + dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); + }, + TM2BlockType::MedRes => { + cdeltas = [[0; 4]; 2]; + cdeltas[0][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; + cdeltas[1][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; + dstate.interpolate_c(0, &mut lastu[bx*2..]); + dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); + dstate.interpolate_c(1, &mut lastv[bx*2..]); + dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); + for i in 0..4*4 { + ydeltas[i] = self.streams[TM2StreamType::LHigh as usize].get_token()?; + } + dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); + }, + TM2BlockType::LowRes => { + cdeltas = [[0; 4]; 2]; + cdeltas[0][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; + cdeltas[1][0] = self.streams[TM2StreamType::CLow as usize].get_token()?; + dstate.interpolate_c(0, &mut lastu[bx*2..]); + dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); + dstate.interpolate_c(1, &mut lastv[bx*2..]); + dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); + ydeltas = [0; 16]; + ydeltas[ 0] = self.streams[TM2StreamType::LLow as usize].get_token()?; + ydeltas[ 2] = self.streams[TM2StreamType::LLow as usize].get_token()?; + ydeltas[ 8] = self.streams[TM2StreamType::LLow as usize].get_token()?; + ydeltas[10] = self.streams[TM2StreamType::LLow as usize].get_token()?; + dstate.interpolate_y_low(&mut lasty[bx*4..]); + dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); + }, + TM2BlockType::NullRes => { + cdeltas = [[0; 4]; 2]; + dstate.interpolate_c(0, &mut lastu[bx*2..]); + dstate.apply_c(udst, offs[1] + bx * 2, cstride, &cdeltas[0], 0, &mut lastu[bx*2+1..]); + dstate.interpolate_c(1, &mut lastv[bx*2..]); + dstate.apply_c(vdst, offs[1] + bx * 2, cstride, &cdeltas[1], 1, &mut lastv[bx*2+1..]); + ydeltas = [0; 16]; + dstate.interpolate_y_null(&mut lasty[bx*4..]); + dstate.apply_y(ydst, offs[0] + bx * 4, ystride, &ydeltas, &mut lasty[bx*4+1..]); + }, + TM2BlockType::Update => { + is_intra = false; + + let mut coff = offs[1] + bx * 2; + let usrc = &self.prev_frame.udata; + let vsrc = &self.prev_frame.vdata; + for _ in 0..2 { + for x in 0..2 { + let du = self.streams[TM2StreamType::Update as usize].get_token()?; + let dv = self.streams[TM2StreamType::Update as usize].get_token()?; + udst[coff + x] = usrc[coff + x] + (du as i16); + vdst[coff + x] = vsrc[coff + x] + (dv as i16); + } + coff += cstride; + } + dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); + dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); + let mut yoff = offs[0] + bx * 4; + let ysrc = &self.prev_frame.ydata; + for _ in 0..4 { + for x in 0..4 { + let dy = self.streams[TM2StreamType::Update as usize].get_token()?; + ydst[yoff + x] = ((ysrc[yoff + x] as i32) + dy) as u8; + } + yoff += ystride; + } + dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); + }, + TM2BlockType::Still => { + is_intra = false; + + let mut coff = offs[1] + bx * 2; + let usrc = &self.prev_frame.udata; + let vsrc = &self.prev_frame.vdata; + for _ in 0..2 { + for x in 0..2 { + udst[coff + x] = usrc[coff + x]; + vdst[coff + x] = vsrc[coff + x]; + } + coff += cstride; + } + dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); + dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); + let mut yoff = offs[0] + bx * 4; + let ysrc = &self.prev_frame.ydata; + for _ in 0..4 { + for x in 0..4 { + ydst[yoff + x] = ysrc[yoff + x]; + } + yoff += ystride; + } + dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); + }, + TM2BlockType::Motion => { + is_intra = false; + + let mx = self.streams[TM2StreamType::Motion as usize].get_token()?; + let my = self.streams[TM2StreamType::Motion as usize].get_token()?; + let xpos = (((bx as i32) * 4) + mx).max(0).min((self.width - 4) as i32) as usize; + let ypos = (((by as i32) * 4) + my).max(0).min((self.height - 4) as i32) as usize; + let mut coff = offs[1] + bx * 2; + let mut csoff = (xpos >> 1) + (ypos >> 1) * cstride; + let usrc = &self.prev_frame.udata; + let vsrc = &self.prev_frame.vdata; + for _ in 0..2 { + for x in 0..2 { + udst[coff + x] = usrc[csoff + x]; + vdst[coff + x] = vsrc[csoff + x]; + } + coff += cstride; + csoff += cstride; + } + dstate.recalc_c(udst, offs[1] + bx * 2, cstride, 0, &mut lastu[bx*2+1..]); + dstate.recalc_c(vdst, offs[1] + bx * 2, cstride, 1, &mut lastv[bx*2+1..]); + let mut yoff = offs[0] + bx * 4; + let mut ysoff = xpos + ypos * ystride; + let ysrc = &self.prev_frame.ydata; + for _ in 0..4 { + for x in 0..4 { + ydst[yoff + x] = ysrc[ysoff + x]; + } + yoff += ystride; + ysoff += ystride; + } + dstate.recalc_y(ydst, offs[0] + bx * 4, ystride, &mut lasty[bx*4+1..]); + }, + }; + } + offs[0] += ystride * 4; + offs[1] += cstride * 2; + } + + Ok(is_intra) + } + fn output_frame(&mut self, buf: &mut NAVideoBuffer) { + let fmt = buf.get_info().get_format(); + let offs = [fmt.get_chromaton(0).unwrap().get_offset() as usize, + fmt.get_chromaton(1).unwrap().get_offset() as usize, + fmt.get_chromaton(2).unwrap().get_offset() as usize]; + let stride = buf.get_stride(0); + let mut data = buf.get_data_mut(); + let dst = data.as_mut_slice(); + + let mut off = 0; + let mut ysrc = 0; + let mut csrc = 0; + for y in 0..self.height { + let out = &mut dst[off..]; + for (x, pic) in out.chunks_exact_mut(3).take(self.width).enumerate() { + let y = self.cur_frame.ydata[ysrc + x] as i16; + let u = self.cur_frame.udata[csrc + (x >> 1)]; + let v = self.cur_frame.vdata[csrc + (x >> 1)]; + pic[offs[0]] = (y + u).max(0).min(255) as u8; + pic[offs[1]] = y.max(0).min(255) as u8; + pic[offs[2]] = (y + v).max(0).min(255) as u8; + } + off += stride; + ysrc += self.cur_frame.ystride; + if (y & 1) != 0 { + csrc += self.cur_frame.cstride; + } + } + } +} + +impl NADecoder for TM2Decoder { + 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.width = vinfo.get_width(); + self.height = vinfo.get_height(); + self.cur_frame = TM2Frame::alloc(self.width, self.height); + self.prev_frame = TM2Frame::alloc(self.width, self.height); + 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() >= 40 + (TM2StreamType::Num as usize) * 4 + 4); + let mut mr = MemoryReader::new_read(&src); + let mut br = ByteReader::new(&mut mr); + + let magic = br.read_u32be()?; + validate!(magic == 0x100 || magic == 0x101); + br.read_skip(36)?; + for str in self.streams.iter_mut() { + str.read_header(&src, &mut br)?; + } + + let myinfo = NAVideoInfo::new(self.width, self.height, false, RGB24_FORMAT); + let bufret = alloc_video_buffer(myinfo, 2); + if let Err(_) = bufret { return Err(DecoderError::InvalidData); } + let mut bufinfo = bufret.unwrap(); + let mut buf = bufinfo.get_vbuf().unwrap(); + + let is_intra = self.decode_blocks()?; + self.output_frame(&mut buf); + std::mem::swap(&mut self.cur_frame, &mut self.prev_frame); + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(is_intra); + frm.set_frame_type(if is_intra { FrameType::I } else { FrameType::P }); + Ok(Rc::new(RefCell::new(frm))) + } +} + +pub fn get_decoder() -> Box { + Box::new(TM2Decoder::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_tm2() { + 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); + + test_file_decoding("avi", "assets/Duck/tm20.avi", Some(16), true, false, None/*Some("tm2")*/, &dmx_reg, &dec_reg); + } +} -- 2.30.2