From 1b8522d6275f5a8e252b7c7283ed4d80a594db93 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Wed, 6 Feb 2019 12:29:15 +0100 Subject: [PATCH] crate for Duck decoders with TM RT decoder --- nihav-duck/Cargo.toml | 29 +++++++ nihav-duck/src/codecs/mod.rs | 59 ++++++++++++++ nihav-duck/src/codecs/truemotion1.rs | 6 ++ nihav-duck/src/codecs/truemotionrt.rs | 107 ++++++++++++++++++++++++++ nihav-duck/src/lib.rs | 6 ++ 5 files changed, 207 insertions(+) create mode 100644 nihav-duck/Cargo.toml create mode 100644 nihav-duck/src/codecs/mod.rs create mode 100644 nihav-duck/src/codecs/truemotion1.rs create mode 100644 nihav-duck/src/codecs/truemotionrt.rs create mode 100644 nihav-duck/src/lib.rs diff --git a/nihav-duck/Cargo.toml b/nihav-duck/Cargo.toml new file mode 100644 index 0000000..1fc1fab --- /dev/null +++ b/nihav-duck/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "nihav_duck" +version = "0.1.0" +authors = ["Kostya Shishkov "] +edition = "2018" + +[dependencies.nihav_core] +path = "../nihav-core" +features = ["fft", "dsp_window"] + +[dev-dependencies] +nihav_commonfmt = { path = "../nihav-commonfmt" } + +[features] +default = ["all_decoders"] + +all_decoders = ["decoder_truemotion1", "decoder_truemotionrt"]#, "decoder_truemotion2", "decoder_truemotion2x", "decoder_truemotion3", "decoder_truemotion4", "decoder_truemotion5", "decoder_truemotion6", "decoder_truemotion7", "decoder_on2avc"] +decoders = [] + +decoder_truemotion1 = ["decoders"] +decoder_truemotionrt = ["decoders"] +decoder_truemotion2 = ["decoders"] +decoder_truemotion2x = ["decoders"] +decoder_truemotion3 = ["decoders"] +decoder_truemotion4 = ["decoders"] +decoder_truemotion5 = ["decoders"] +decoder_truemotion6 = ["decoders"] +decoder_truemotion7 = ["decoders"] +decoder_on2avc = ["decoders"] diff --git a/nihav-duck/src/codecs/mod.rs b/nihav-duck/src/codecs/mod.rs new file mode 100644 index 0000000..f0a47dc --- /dev/null +++ b/nihav-duck/src/codecs/mod.rs @@ -0,0 +1,59 @@ +use nihav_core::codecs::*; + +macro_rules! validate { + ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DecoderError::InvalidData); } }; +} + +#[cfg(feature="decoder_truemotion1")] +mod truemotion1; +#[cfg(feature="decoder_truemotionrt")] +mod truemotionrt; +#[cfg(feature="decoder_truemotion2")] +mod truemotion2; +#[cfg(feature="decoder_truemotion2x")] +mod truemotion2x; +#[cfg(feature="decoder_truemotion3")] +mod truemotion3; +#[cfg(feature="decoder_truemotion4")] +mod truemotion4; +#[cfg(feature="decoder_truemotion5")] +mod truemotion5; +#[cfg(feature="decoder_truemotion6")] +mod truemotion6; +#[cfg(feature="decoder_truemotion7")] +mod truemotion7; + +#[cfg(feature="decoder_on2avc")] +mod on2avc; + +const DUCK_CODECS: &[DecoderInfo] = &[ +#[cfg(feature="decoder_truemotion1")] + DecoderInfo { name: "truemotion1", get_decoder: truemotion1::get_decoder }, +#[cfg(feature="decoder_truemotionrt")] + DecoderInfo { name: "truemotionrt", get_decoder: truemotionrt::get_decoder }, +#[cfg(feature="decoder_truemotion2")] + DecoderInfo { name: "truemotion2", get_decoder: truemotion2::get_decoder }, +#[cfg(feature="decoder_truemotion2x")] + DecoderInfo { name: "truemotion2x", get_decoder: truemotion2x::get_decoder }, +#[cfg(feature="decoder_truemotion3")] + DecoderInfo { name: "truemotion3", get_decoder: truemotion3::get_decoder }, +#[cfg(feature="decoder_truemotion4")] + DecoderInfo { name: "truemotion4", get_decoder: truemotion4::get_decoder }, +#[cfg(feature="decoder_truemotion5")] + DecoderInfo { name: "truemotion5", get_decoder: truemotion5::get_decoder }, +#[cfg(feature="decoder_truemotion6")] + DecoderInfo { name: "truemotion6", get_decoder: truemotion6::get_decoder }, +#[cfg(feature="decoder_truemotion7")] + DecoderInfo { name: "truemotion7", get_decoder: truemotion7::get_decoder }, + +#[cfg(feature="decoder_on2avc")] + DecoderInfo { name: "on2avc-500", get_decoder: on2avc::get_decoder_500 }, +#[cfg(feature="decoder_on2avc")] + DecoderInfo { name: "on2avc-501", get_decoder: on2avc::get_decoder_501 }, +]; + +pub fn duck_register_all_codecs(rd: &mut RegisteredDecoders) { + for decoder in DUCK_CODECS.into_iter() { + rd.add_decoder(decoder.clone()); + } +} diff --git a/nihav-duck/src/codecs/truemotion1.rs b/nihav-duck/src/codecs/truemotion1.rs new file mode 100644 index 0000000..df0bb5b --- /dev/null +++ b/nihav-duck/src/codecs/truemotion1.rs @@ -0,0 +1,6 @@ +use nihav_core::codecs::*; + +pub fn get_decoder() -> Box { +unimplemented!(); +} + diff --git a/nihav-duck/src/codecs/truemotionrt.rs b/nihav-duck/src/codecs/truemotionrt.rs new file mode 100644 index 0000000..3881ee7 --- /dev/null +++ b/nihav-duck/src/codecs/truemotionrt.rs @@ -0,0 +1,107 @@ +use nihav_core::codecs::*; +use nihav_core::io::bitreader::*; + +#[derive(Default)] +struct TMRTDecoder { + info: Rc, +} + +const TMRT_DELTA_TAB: [&[i16]; 3] = [ + &[ 5, -7, 36, -36 ], + &[ 2, -3, 8, -8, 18, -18, 36, -36 ], + &[ 1, -1, 2, -3, 8, -8, 18, -18, 36, -36, 54, -54, 96, -96, 144, -144 ] +]; + +impl TMRTDecoder { + fn new() -> Self { Self::default() } + fn decode_plane(&self, br: &mut BitReader, dst: &mut [u8], mut off: usize, stride: usize, w: usize, h: usize, hscale: bool, dbits: u8, is_chroma: bool) -> DecoderResult<()> { + let delta_tab = TMRT_DELTA_TAB[(dbits - 2) as usize]; + let step = if !hscale { 1 } else { 2 }; + for y in 0..h { + let mut diff = 0; + for x in (0..w).step_by(step) { + let delta = delta_tab[br.read(dbits)? as usize]; + diff += delta; + let pred = if y > 0 { dst[off + x - stride].into() } else if !is_chroma { 0 } else { 0x80 }; + dst[off + x] = (pred + diff).min(255).max(0) as u8; + if hscale { + dst[off + x + 1] = dst[off + x]; + } + } + off += stride; + } + Ok(()) + } +} + +impl NADecoder for TMRTDecoder { + 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 >= 10 && hdr_size < src.len() - 4); + let mut hdr: [u8; 127] = [0; 127]; + for i in 1..hdr_size { + hdr[i - 1] = src[i] ^ src[i + 1]; + } + let dbits = hdr[1]; + validate!(dbits >= 2 && dbits <= 4); + let hscale = hdr[3] != 0; + let width = (hdr[7] as usize) | ((hdr[8] as usize) << 8); + let height = (hdr[5] as usize) | ((hdr[6] as usize) << 8); + + let myinfo = NAVideoInfo::new(width, height, false, YUV410_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 mut br = BitReader::new(&src[hdr_size..], src.len() - hdr_size, BitReaderMode::LE); + let size = br.read(32)? as usize; + validate!(size <= src.len() - hdr_size); + for plane in 0..3 { + let (w, h) = buf.get_dimensions(plane); + let off = buf.get_offset(plane); + let stride = buf.get_stride(plane); + let mut data = buf.get_data_mut(); + let dst = data.as_mut_slice(); + self.decode_plane(&mut br, dst, off, stride, w, h, hscale, dbits, plane > 0)?; + } + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(true); + frm.set_frame_type(FrameType::I); + Ok(Rc::new(RefCell::new(frm))) + } +} + +pub fn get_decoder() -> Box { + Box::new(TMRTDecoder::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_tmrt() { + 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/tr20_low.avi", Some(10), true, false, None/*Some("tmrt")*/, &dmx_reg, &dec_reg); + } +} diff --git a/nihav-duck/src/lib.rs b/nihav-duck/src/lib.rs new file mode 100644 index 0000000..40b5f2b --- /dev/null +++ b/nihav-duck/src/lib.rs @@ -0,0 +1,6 @@ +extern crate nihav_core; + +pub mod codecs; + +#[cfg(test)] +extern crate nihav_commonfmt; -- 2.30.2