X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-duck%2Fsrc%2Fcodecs%2Ftruemotion2x.rs;h=7f4ac524062903d4129f13ea9405faeaeb66437c;hp=f03152c178a233ab3a99bf4d39f66a71b7a0372b;hb=78fb6560c73965d834b215fb0b49505ae5443288;hpb=2994c841b2b9d62c91d1ce0ca7c8801d03a5f4cf diff --git a/nihav-duck/src/codecs/truemotion2x.rs b/nihav-duck/src/codecs/truemotion2x.rs index f03152c..7f4ac52 100644 --- a/nihav-duck/src/codecs/truemotion2x.rs +++ b/nihav-duck/src/codecs/truemotion2x.rs @@ -35,6 +35,7 @@ struct Deltas { num_vq: usize, vq_idx: usize, vq_pos: usize, + vq_esc: u8, } impl Deltas { @@ -57,10 +58,38 @@ impl Deltas { } Ok(ret) } + fn remap(val: u16) -> i16 { + let hval = (val >> 1) as i16; + if (val & 1) == 0 { + hval + } else { + -1 - hval + } + } fn get_int(&mut self, br: &mut ByteReader) -> DecoderResult { let b = self.get_val(br)?; - if b > 0 { unimplemented!(); } - Ok(b as i16) + if b != self.vq_esc - 1 { + return Ok(Self::remap(u16::from(b))); + } + let mut run = 0; + let mut val; + let mut pow = u16::from(self.vq_esc); + loop { + let b = self.get_val(br)?; + run += 1; + if b != self.vq_esc - 1 { + val = u16::from(b) * pow; + break; + } + pow *= u16::from(self.vq_esc); + } + + for _ in 0..run { + pow /= u16::from(self.vq_esc); + let b = u16::from(self.get_val(br)?); + val += pow * b; + } + Ok(Self::remap(val)) } fn get_dy(&mut self, br: &mut ByteReader) -> DecoderResult { let b = self.get_val(br)?; @@ -81,6 +110,7 @@ impl Default for Deltas { num_vq: 0, vq_idx: 0, vq_pos: 0, + vq_esc: 0, } } } @@ -96,6 +126,7 @@ struct BlkInfo { const NUM_CPARAMS: usize = 25; const CPARAM_NONE: u8 = 42; const CPARAM_MISSING: u8 = 42 * 2; +const CPARAM_MV: u8 = 42 * 3; macro_rules! apply_delta { ($buf:expr, $off:expr, $stride:expr, $hpred: expr, $delta:expr) => { @@ -111,51 +142,61 @@ macro_rules! copy_line { }; } +#[derive(Default)] +struct Frame { + ydata: Vec, + udata: Vec, + vdata: Vec, + stride: usize, +} + +impl Frame { + fn resize(&mut self, w: usize, h: usize) { + self.stride = w; + self.ydata.resize(self.stride * (h + 1), 0x80); + self.udata.resize(self.stride * (h + 1), 0x80); + self.vdata.resize(self.stride * (h + 1), 0x80); + } +} + #[derive(Default)] struct TM2XDecoder { - info: Rc, + info: NACodecInfoRef, width: usize, height: usize, dec_buf: Vec, version: u8, + is_intra: bool, deltas: Deltas, blk_info: Vec, tile_size: usize, cparams: [[u8; 8]; NUM_CPARAMS], - ydata: Vec, - udata: Vec, - vdata: Vec, - ystride: usize, - cstride: usize, + cur_frame: Frame, + ref_frame: Frame, } impl TM2XDecoder { fn new() -> Self { Self::default() } 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 mut offs = [ buf.get_offset(0), buf.get_offset(1), buf.get_offset(2) ]; + let strides = [ buf.get_stride(0), buf.get_stride(1), buf.get_stride(2) ]; + let data = buf.get_data_mut().unwrap(); let dst = data.as_mut_slice(); - let mut off = 0; - let mut ysrc = self.ystride; - let mut csrc = self.cstride; + let mut pos = self.cur_frame.stride; 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.ydata[ysrc + x]; - let u = self.udata[csrc + x] - 128; - let v = self.vdata[csrc + x] - 128; - pic[offs[0]] = (y + v).max(0).min(255) as u8; - pic[offs[1]] = y.max(0).min(255) as u8; - pic[offs[2]] = (y + u).max(0).min(255) as u8; + for x in 0..self.width { + let y = self.cur_frame.ydata[pos + x]; + let u = self.cur_frame.udata[pos + x]; + let v = self.cur_frame.vdata[pos + x]; + dst[offs[0] + x] = y.max(0).min(255) as u8; + dst[offs[1] + x] = u.max(0).min(255) as u8; + dst[offs[2] + x] = v.max(0).min(255) as u8; } - off += stride; - ysrc += self.ystride; - csrc += self.cstride; + for c in 0..3 { + offs[c] += strides[c]; + } + pos += self.cur_frame.stride; } } fn parse_init(&mut self, version: u8) -> DecoderResult<()> { @@ -176,9 +217,7 @@ impl TM2XDecoder { let _nfuncs = br.read_byte()? as usize; let _smth = br.read_u16be()? as usize; let has_mv = br.read_byte()?; - if has_mv != 0 { - unimplemented!(); - } + self.is_intra = has_mv == 0; if version >= 4 { let _flags = br.read_u16be()?; let id_len = br.read_byte()? as usize; @@ -188,7 +227,7 @@ impl TM2XDecoder { br.read_skip(len)?; let _smth = br.read_u32be()?; } - + Ok(()) } fn parse_tabs(&mut self) -> DecoderResult<()> { @@ -210,7 +249,8 @@ impl TM2XDecoder { let mut br = ByteReader::new(&mut mr); if version == 0x0A { - let _esc_val = br.read_byte()?; + self.deltas.vq_esc = br.read_byte()?; + validate!(self.deltas.vq_esc > 1); let _tag = br.read_u16be()?; } let len = br.read_u16be()? as usize; @@ -235,6 +275,9 @@ impl TM2XDecoder { Ok(()) } + #[allow(clippy::int_plus_one)] + #[allow(clippy::manual_memcpy)] + #[allow(clippy::cyclomatic_complexity)] fn decode_frame(&mut self, src: &[u8]) -> DecoderResult<()> { let mut mr = MemoryReader::new_read(src); let mut br = ByteReader::new(&mut mr); @@ -243,16 +286,20 @@ impl TM2XDecoder { let bw = self.width / 8; let bh = self.height / 8; let ntiles = (bw + self.tile_size - 1) / self.tile_size; - let mut ypos = self.ystride; - let mut cpos = self.cstride; - for _by in 0..bh { + let mut pos = self.cur_frame.stride; + let ydata = &mut self.cur_frame.ydata; + let udata = &mut self.cur_frame.udata; + let vdata = &mut self.cur_frame.vdata; + let stride = self.cur_frame.stride; + for by in 0..bh { for tile in 0..ntiles { let xpos = tile * self.tile_size; let len = self.tile_size.min(bw - xpos); + let mut last_x = 0; + let mut last_y = 0; for el in self.blk_info.iter_mut().take(len) { let t1 = self.deltas.get_val(&mut br)?; let t2 = self.deltas.get_val(&mut br)?; - if t2 > 1 { unimplemented!(); } validate!((t1 as usize) < NUM_CPARAMS); validate!(self.cparams[t1 as usize][0] != CPARAM_MISSING); el.btype = t1; @@ -260,9 +307,11 @@ impl TM2XDecoder { if t2 > 0 { el.mv_x = self.deltas.get_int(&mut br)?; el.mv_y = self.deltas.get_int(&mut br)?; + last_x = el.mv_x; + last_y = el.mv_y; } else { - el.mv_x = 0; - el.mv_y = 0; + el.mv_x = last_x; + el.mv_y = last_y; } } for line in 0..8 { @@ -272,16 +321,15 @@ impl TM2XDecoder { for x in 0..len { let bx = xpos + x; let op = self.cparams[self.blk_info[x].btype as usize][line]; - let cur_yoff = ypos + bx * 8 + line * self.ystride; - let cur_coff = cpos + bx * 8 + line * self.cstride; + let cur_off = pos + bx * 8 + line * stride; match op { 0 => { // y4|y4 for i in 0..8 { let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } - copy_line!(self.udata, cur_coff, self.cstride); - copy_line!(self.vdata, cur_coff, self.cstride); + copy_line!(udata, cur_off, stride); + copy_line!(vdata, cur_off, stride); upred = 0; vpred = 0; }, @@ -289,13 +337,13 @@ impl TM2XDecoder { for i in 0..8 { if (i & 1) == 0 { let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } - copy_line!(self.udata, cur_coff, self.cstride); - copy_line!(self.vdata, cur_coff, self.cstride); + copy_line!(udata, cur_off, stride); + copy_line!(vdata, cur_off, stride); upred = 0; vpred = 0; }, @@ -303,54 +351,54 @@ impl TM2XDecoder { for i in 0..8 { if (i & 3) == 0 { let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } - copy_line!(self.udata, cur_coff, self.cstride); - copy_line!(self.vdata, cur_coff, self.cstride); + copy_line!(udata, cur_off, stride); + copy_line!(vdata, cur_off, stride); upred = 0; vpred = 0; }, 3 => { // y1|0 let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off, stride, ypred, delta); for i in 1..8 { - self.ydata[cur_yoff + i] = self.ydata[cur_yoff]; + ydata[cur_off + i] = ydata[cur_off]; } - copy_line!(self.udata, cur_coff, self.cstride); - copy_line!(self.vdata, cur_coff, self.cstride); + copy_line!(udata, cur_off, stride); + copy_line!(vdata, cur_off, stride); upred = 0; vpred = 0; }, 4 => { // c2y2c2y2|c2y2c2y2 for i in (0..8).step_by(2) { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i + 0, self.cstride, upred, delta); - self.udata[cur_coff + i + 1] = self.udata[cur_coff + i]; + apply_delta!(udata, cur_off + i + 0, stride, upred, delta); + udata[cur_off + i + 1] = udata[cur_off + i]; let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i + 0, self.cstride, vpred, delta); - self.vdata[cur_coff + i + 1] = self.vdata[cur_coff + i]; + apply_delta!(vdata, cur_off + i + 0, stride, vpred, delta); + vdata[cur_off + i + 1] = vdata[cur_off + i]; let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i + 0, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i + 0, stride, ypred, delta); let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i + 1, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i + 1, stride, ypred, delta); } }, 5 => { // c2y1|c2y1 for i in 0..8 { if (i & 3) == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } }, @@ -359,33 +407,33 @@ impl TM2XDecoder { for i in 0..8 { if (i & 3) == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; } let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } }, 9 => { // c2y2|c2y2 for i in 0..8 { if (i & 3) == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; } if (i & 1) == 0 { let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } }, @@ -393,15 +441,15 @@ impl TM2XDecoder { for i in 0..8 { if (i & 3) == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } }, @@ -410,33 +458,33 @@ impl TM2XDecoder { for i in 0..8 { if i == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; } let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } }, 13 => { // c2y4 for i in 0..8 { if i == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; } if (i & 1) == 0 { let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } }, @@ -444,18 +492,18 @@ impl TM2XDecoder { for i in 0..8 { if i == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; } if (i & 3) == 0 { let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } }, @@ -463,33 +511,47 @@ impl TM2XDecoder { for i in 0..8 { if i == 0 { let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.udata, cur_coff + i, self.cstride, upred, delta); + apply_delta!(udata, cur_off + i, stride, upred, delta); let delta = self.deltas.get_dc(&mut br)?; - apply_delta!(self.vdata, cur_coff + i, self.cstride, vpred, delta); + apply_delta!(vdata, cur_off + i, stride, vpred, delta); let delta = self.deltas.get_dy(&mut br)?; - apply_delta!(self.ydata, cur_yoff + i, self.ystride, ypred, delta); + apply_delta!(ydata, cur_off + i, stride, ypred, delta); } else { - self.udata[cur_coff + i] = self.udata[cur_coff + i - 1]; - self.vdata[cur_coff + i] = self.vdata[cur_coff + i - 1]; - self.ydata[cur_yoff + i] = self.ydata[cur_yoff + i - 1]; + udata[cur_off + i] = udata[cur_off + i - 1]; + vdata[cur_off + i] = vdata[cur_off + i - 1]; + ydata[cur_off + i] = ydata[cur_off + i - 1]; } } }, CPARAM_NONE => { - copy_line!(self.ydata, cur_yoff, self.ystride); - copy_line!(self.udata, cur_coff, self.cstride); - copy_line!(self.vdata, cur_coff, self.cstride); + copy_line!(ydata, cur_off, stride); + copy_line!(udata, cur_off, stride); + copy_line!(vdata, cur_off, stride); ypred = 0; upred = 0; vpred = 0; }, + CPARAM_MV => { + let src_x = (bx as i16) * 8 + self.blk_info[x].mv_x; + let src_y = ((by * 8 + line) as i16) + self.blk_info[x].mv_y; + validate!(src_x >= 0 && (src_x as usize) + 8 <= self.width); + validate!(src_y >= 0 && (src_y as usize) + 1 <= self.height); + let ref_off = (src_x as usize) + ((src_y + 1) as usize) * stride; + for i in 0..8 { + ydata[cur_off + i] = self.ref_frame.ydata[ref_off + i]; + udata[cur_off + i] = self.ref_frame.udata[ref_off + i]; + vdata[cur_off + i] = self.ref_frame.vdata[ref_off + i]; + } + ypred = ydata[cur_off + 7] - ydata[cur_off + 7 - stride]; + upred = udata[cur_off + 7] - udata[cur_off + 7 - stride]; + vpred = vdata[cur_off + 7] - vdata[cur_off + 7 - stride]; + }, _ => unreachable!(), } } } } - ypos += 8 * self.ystride; - cpos += 8 * self.cstride; + pos += 8 * stride; } Ok(()) @@ -497,23 +559,25 @@ impl TM2XDecoder { } impl NADecoder for TM2XDecoder { - fn init(&mut self, info: Rc) -> DecoderResult<()> { + fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { - let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, RGB24_FORMAT)); + let fmt = NAPixelFormaton::new(ColorModel::YUV(YUVSubmodel::YUVJ), + Some(NAPixelChromaton::new(0, 0, false, 8, 0, 0, 1)), + Some(NAPixelChromaton::new(0, 0, false, 8, 0, 1, 1)), + Some(NAPixelChromaton::new(0, 0, false, 8, 0, 2, 1)), + None, None, 0, 3); + let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt)); self.width = vinfo.get_width(); self.height = vinfo.get_height(); - self.ystride = self.width; - self.cstride = self.width; - self.ydata.resize(self.ystride * (self.height + 1), 0x80); - self.udata.resize(self.cstride * (self.height + 1), 0x80); - self.vdata.resize(self.cstride * (self.height + 1), 0x80); - self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata())); + self.cur_frame.resize(self.width, self.height); + self.ref_frame.resize(self.width, self.height); + self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); Ok(()) } else { Err(DecoderError::InvalidData) } } - fn decode(&mut self, pkt: &NAPacket) -> DecoderResult { + fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult { let src = pkt.get_buffer(); validate!(src.len() > 8); let mut mr = MemoryReader::new_read(&src); @@ -524,6 +588,7 @@ impl NADecoder for TM2XDecoder { let mut got_key = false; let mut data_size = 0; self.cparams = [[CPARAM_MISSING; 8]; NUM_CPARAMS]; + self.is_intra = false; while br.left() >= 8 { let magic = br.read_u24be()?; let ctype = br.read_byte()?; @@ -577,23 +642,26 @@ impl NADecoder for TM2XDecoder { validate!(self.dec_buf.len() == 4); let idx = self.dec_buf[3] as usize; validate!(idx < NUM_CPARAMS); - validate!(self.dec_buf[0] != 0); validate!((self.dec_buf[0] as usize) < TM2X_CODING_PARAMS.len()); - let tab = &TM2X_CODING_PARAMS[self.dec_buf[0] as usize]; - let m0 = tab[0] as usize; - let m1 = tab[1] as usize; - let m2 = tab[2] as usize; - let m3 = tab[3] as usize; - let full_mode = (m2 * 4 + m0) as u8; - let lores_mode = m0 as u8; - for i in 0..8 { - if (i % m1) == 0 && (i % m3) == 0 { - self.cparams[idx][i] = full_mode; - } else if (i % m1) == 0 { - self.cparams[idx][i] = lores_mode; - } else { - self.cparams[idx][i] = CPARAM_NONE; + if self.dec_buf[0] != 0 { + let tab = &TM2X_CODING_PARAMS[self.dec_buf[0] as usize]; + let m0 = tab[0] as usize; + let m1 = tab[1] as usize; + let m2 = tab[2] as usize; + let m3 = tab[3] as usize; + let full_mode = (m2 * 4 + m0) as u8; + let lores_mode = m0 as u8; + for i in 0..8 { + if (i % m1) == 0 && (i % m3) == 0 { + self.cparams[idx][i] = full_mode; + } else if (i % m1) == 0 { + self.cparams[idx][i] = lores_mode; + } else { + self.cparams[idx][i] = CPARAM_NONE; + } } + } else { + for i in 0..8 { self.cparams[idx][i] = CPARAM_MV; } } }, 0x02 => { @@ -607,25 +675,33 @@ impl NADecoder for TM2XDecoder { _ => { unimplemented!(); }, }; } + if !self.is_intra { + std::mem::swap(&mut self.cur_frame, &mut self.ref_frame); + } self.decode_frame(&src[12..][..data_size])?; - 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 bufinfo = bufret.unwrap(); + let myinfo = self.info.get_properties().get_video_info().unwrap(); + let bufinfo = alloc_video_buffer(myinfo, 2)?; let mut buf = bufinfo.get_vbuf().unwrap(); - let is_intra = true; self.output_frame(&mut buf); 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))) + frm.set_keyframe(self.is_intra); + frm.set_frame_type(if self.is_intra { FrameType::I } else { FrameType::P }); + Ok(frm.into_ref()) } + fn flush(&mut self) { + } +} + +impl NAOptionHandler for TM2XDecoder { + fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } + fn set_options(&mut self, _options: &[NAOption]) { } + fn query_option_value(&self, _name: &str) -> Option { None } } -pub fn get_decoder() -> Box { +pub fn get_decoder() -> Box { Box::new(TM2XDecoder::new()) } @@ -633,17 +709,25 @@ pub fn get_decoder() -> Box { 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; + use nihav_codec_support::test::dec_video::*; + use crate::duck_register_all_decoders; + use nihav_commonfmt::generic_register_all_demuxers; #[test] fn test_tm2x() { 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); + duck_register_all_decoders(&mut dec_reg); - test_file_decoding("avi", "assets/Duck/TM2x.avi", Some(16), true, false, None/*Some("tm2x")*/, &dmx_reg, &dec_reg); + test_decoding("avi", "truemotion2x", "assets/Duck/TM2x.avi", None, + &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ + [0x2854e7f3, 0x41e54fd3, 0xd9a16302, 0x580321b2], + [0x8e736f59, 0x57c58dc0, 0xe15bad3a, 0xf96e2c5b], + [0x12700e7c, 0xfa2d06e0, 0x05b758ba, 0xe79aabb6], + [0x29f935f2, 0x2ad0d6d1, 0x2fde19a2, 0x5aa3823b], + [0x7f1a787d, 0x77f3ab61, 0x0e584c66, 0x9d1842ea], + [0xb5607334, 0xdb149056, 0xe0e3ddb5, 0x19f8e254], + [0xb054e4d0, 0x1d241d4f, 0x75fdfe95, 0x9dde8024]])); } }