X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-vivo%2Fsrc%2Fcodecs%2Fvivo.rs;fp=nihav-vivo%2Fsrc%2Fcodecs%2Fvivo.rs;h=807814d1f1517430afd2587b6010bcebc39075ac;hb=31cf33aceca7798294e1ce5c01702ef5e6ef7adc;hp=0000000000000000000000000000000000000000;hpb=8989305f27376e92ec3f0a77cf7edf65a5255183;p=nihav.git diff --git a/nihav-vivo/src/codecs/vivo.rs b/nihav-vivo/src/codecs/vivo.rs new file mode 100644 index 0000000..807814d --- /dev/null +++ b/nihav-vivo/src/codecs/vivo.rs @@ -0,0 +1,513 @@ +use nihav_core::io::bitreader::*; +use nihav_core::io::codebook::*; +use nihav_core::formats; +use nihav_core::frame::*; +use nihav_core::codecs::*; +use nihav_codec_support::codecs::{MV, ZIGZAG}; +use nihav_codec_support::codecs::h263::*; +use nihav_codec_support::codecs::h263::code::H263BlockDSP; +use nihav_codec_support::codecs::h263::decoder::*; +use nihav_codec_support::codecs::h263::data::*; + +#[allow(dead_code)] +struct Tables { + intra_mcbpc_cb: Codebook, + inter_mcbpc_cb: Codebook, + cbpy_cb: Codebook, + rl_cb: Codebook, + aic_rl_cb: Codebook, + mv_cb: Codebook, +} + +struct VivoDecoder { + info: NACodecInfoRef, + dec: H263BaseDecoder, + tables: Tables, + bdsp: H263BlockDSP, + lastframe: Option, + lastpts: Option, + width: usize, + height: usize, +} + +struct VivoBR<'a> { + br: BitReader<'a>, + tables: &'a Tables, + gob_no: usize, + mb_w: usize, + is_pb: bool, + is_ipb: bool, + ref_w: usize, + ref_h: usize, + aic: bool, +} + +fn check_marker<'a>(br: &mut BitReader<'a>) -> DecoderResult<()> { + let mark = br.read(1)?; + validate!(mark == 1); + Ok(()) +} + +impl<'a> VivoBR<'a> { + fn new(src: &'a [u8], tables: &'a Tables, ref_w: usize, ref_h: usize) -> Self { + VivoBR { + br: BitReader::new(src, BitReaderMode::BE), + tables, + gob_no: 0, + mb_w: 0, + is_pb: false, + is_ipb: false, + ref_w, ref_h, + aic: false, + } + } + + fn decode_block(&mut self, quant: u8, intra: bool, coded: bool, blk: &mut [i16; 64], plane_no: usize, acpred: ACPredMode) -> DecoderResult<()> { + let br = &mut self.br; + let mut idx = 0; + if !self.aic && intra { + let mut dc = br.read(8)? as i16; + if dc == 255 { dc = 128; } + blk[0] = dc << 3; + idx = 1; + } + if !coded { return Ok(()); } + let scan = match acpred { + ACPredMode::Hor => H263_SCAN_V, + ACPredMode::Ver => H263_SCAN_H, + _ => &ZIGZAG, + }; + + let rl_cb = if self.aic && intra { &self.tables.aic_rl_cb } else { &self.tables.rl_cb }; + let q = if plane_no == 0 { (quant * 2) as i16 } else { (H263_CHROMA_QUANT[quant as usize] * 2) as i16 }; + let q_add = if q == 0 || self.aic { 0i16 } else { (((q >> 1) - 1) | 1) as i16 }; + while idx < 64 { + let code = br.read_cb(rl_cb)?; + let run; + let mut level; + let last; + if !code.is_escape() { + run = code.get_run(); + level = code.get_level(); + last = code.is_last(); + if br.read_bool()? { level = -level; } + if level >= 0 { + level = (level * q) + q_add; + } else { + level = (level * q) - q_add; + } + } else { + last = br.read_bool()?; + run = br.read(6)? as u8; + level = br.read_s(8)? as i16; + if level == -128 { + let low = br.read(5)? as i16; + let top = br.read_s(6)? as i16; + level = (top << 5) | low; + } + if level >= 0 { + level = (level * q) + q_add; + } else { + level = (level * q) - q_add; + } + if level < -2048 { level = -2048; } + if level > 2047 { level = 2047; } + } + idx += run; + validate!(idx < 64); + let oidx = scan[idx as usize]; + blk[oidx] = level; + idx += 1; + if last { break; } + } + Ok(()) + } +} + +fn decode_mv_component(br: &mut BitReader, mv_cb: &Codebook) -> DecoderResult { + let code = i16::from(br.read_cb(mv_cb)?); + if code == 0 { return Ok(0) } + if !br.read_bool()? { + Ok(code) + } else { + Ok(-code) + } +} + +fn decode_mv(br: &mut BitReader, mv_cb: &Codebook) -> DecoderResult { + let xval = decode_mv_component(br, mv_cb)?; + let yval = decode_mv_component(br, mv_cb)?; + Ok(MV::new(xval, yval)) +} + +fn decode_b_info(br: &mut BitReader, is_pb: bool, is_ipb: bool, is_intra: bool) -> DecoderResult { + if is_pb { // as improved pb + if is_ipb { + let pb_mv_add = if is_intra { 1 } else { 0 }; + if br.read_bool()?{ + if br.read_bool()? { + let pb_mv_count = 1 - (br.read(1)? as usize); + let cbpb = br.read(6)? as u8; + Ok(BBlockInfo::new(true, cbpb, pb_mv_count + pb_mv_add, pb_mv_count == 1)) + } else { + Ok(BBlockInfo::new(true, 0, 1 + pb_mv_add, true)) + } + } else { + Ok(BBlockInfo::new(true, 0, pb_mv_add, false)) + } + } else { + let mvdb = br.read_bool()?; + let cbpb = if mvdb && br.read_bool()? { br.read(6)? as u8 } else { 0 }; + Ok(BBlockInfo::new(true, cbpb, if mvdb { 1 } else { 0 }, false)) + } + } else { + Ok(BBlockInfo::new(false, 0, 0, false)) + } +} + +impl<'a> BlockDecoder for VivoBR<'a> { + +#[allow(unused_variables)] + fn decode_pichdr(&mut self) -> DecoderResult { + let br = &mut self.br; + let syncw = br.read(22)?; + validate!(syncw == 0x000020); + let tr = (br.read(8)? << 8) as u16; + check_marker(br)?; + let id = br.read(1)?; + validate!(id == 0); + br.read(1)?; // split screen indicator + br.read(1)?; // document camera indicator + br.read(1)?; // freeze picture release + let mut sfmt = br.read(3)?; + validate!(sfmt != 0b000); + let is_intra = !br.read_bool()?; + let umv = br.read_bool()?; + br.read(1)?; // syntax arithmetic coding + let apm = br.read_bool()?; + self.is_pb = br.read_bool()?; + let deblock; + let pbplus; + let aic; + if sfmt == 0b110 { + sfmt = br.read(3)?; + validate!(sfmt != 0b000 && sfmt != 0b110); + aic = br.read_bool()?; + br.read(1)?; // umv mode + deblock = br.read_bool()?; + br.read(3)?; // unknown flags + pbplus = br.read_bool()?; + br.read(4)?; // unknown flags + } else { + aic = false; + deblock = false; + pbplus = false; + } + self.is_ipb = pbplus; + let (w, h) = match sfmt { + 0b001 => ( 64, 48), + 0b011 => ( 88, 72), + 0b010 => (176, 144), + 0b100 => (352, 288), + 0b101 => (704, 576), + 0b111 => { + validate!((self.ref_w != 0) && (self.ref_h != 0)); + ((self.ref_w + 15) & !15, (self.ref_h + 15) & !15) + }, + _ => return Err(DecoderError::InvalidData), + }; + let quant = br.read(5)?; + let cpm = br.read_bool()?; + validate!(!cpm); + + let pbinfo; + if self.is_pb { + let trb = br.read(3)?; + let dbquant = br.read(2)?; + pbinfo = Some(PBInfo::new(trb as u8, dbquant as u8, pbplus)); + } else { + pbinfo = None; + } + while br.read_bool()? { // skip PEI + br.read(8)?; + } + self.gob_no = 0; + self.mb_w = (w + 15) >> 4; + self.aic = aic; + + let ftype = if is_intra { Type::I } else { Type::P }; + let plusinfo = Some(PlusInfo::new(aic, deblock, false, false)); + let mvmode = if umv { MVMode::UMV } else { MVMode::Old }; + let picinfo = PicInfo::new(w, h, ftype, mvmode, umv, apm, quant as u8, tr, pbinfo, plusinfo); + Ok(picinfo) + } + + #[allow(unused_variables)] + fn decode_slice_header(&mut self, info: &PicInfo) -> DecoderResult { + let br = &mut self.br; + let gbsc = br.read(17)?; + validate!(gbsc == 1); + let gn = br.read(5)?; + let gfid = br.read(2)?; + let gquant = br.read(5)?; + let ret = SliceInfo::new_gob(0, self.gob_no, gquant as u8); + self.gob_no += 1; + Ok(ret) + } + + #[allow(unused_variables)] + fn decode_block_header(&mut self, info: &PicInfo, slice: &SliceInfo, sstate: &SliceState) -> DecoderResult { + let br = &mut self.br; + let mut q = slice.get_quant(); + match info.get_mode() { + Type::I => { + let mut cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?; + while cbpc == 8 { cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?; } + let mut acpred = ACPredMode::None; + if let Some(ref pi) = info.plusinfo { + if pi.aic { + let acpp = br.read_bool()?; + acpred = ACPredMode::DC; + if acpp { + acpred = if !br.read_bool()? { ACPredMode::Hor } else { ACPredMode::Ver }; + } + } + } + let cbpy = br.read_cb(&self.tables.cbpy_cb)?; + let cbp = (cbpy << 2) | (cbpc & 3); + let dquant = (cbpc & 4) != 0; + if dquant { + let idx = br.read(2)? as usize; + q = (i16::from(q) + i16::from(H263_DQUANT_TAB[idx])) as u8; + } + let mut binfo = BlockInfo::new(Type::I, cbp, q); + binfo.set_acpred(acpred); + Ok(binfo) + }, + Type::P => { + if br.read_bool()? { return Ok(BlockInfo::new(Type::Skip, 0, info.get_quant())); } + let mut cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?; + while cbpc == 20 { cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?; } + let is_intra = (cbpc & 0x04) != 0; + let dquant = (cbpc & 0x08) != 0; + let is_4x4 = (cbpc & 0x10) != 0; + if is_intra { + let mut acpred = ACPredMode::None; + if let Some(ref pi) = info.plusinfo { + if pi.aic { + let acpp = br.read_bool()?; + acpred = ACPredMode::DC; + if acpp { + acpred = if !br.read_bool()? { ACPredMode::Hor } else { ACPredMode::Ver }; + } + } + } + let mut mvec: Vec = Vec::new(); + let bbinfo = decode_b_info(br, self.is_pb, self.is_ipb, true)?; + let cbpy = br.read_cb(&self.tables.cbpy_cb)?; + let cbp = (cbpy << 2) | (cbpc & 3); + if dquant { + let idx = br.read(2)? as usize; + q = (i16::from(q) + i16::from(H263_DQUANT_TAB[idx])) as u8; + } + let mut binfo = BlockInfo::new(Type::I, cbp, q); + binfo.set_bpart(bbinfo); + binfo.set_acpred(acpred); + if self.is_pb { + for _ in 0..bbinfo.get_num_mv() { + mvec.push(decode_mv(br, &self.tables.mv_cb)?); + } + binfo.set_b_mv(mvec.as_slice()); + } + return Ok(binfo); + } + + let bbinfo = decode_b_info(br, self.is_pb, self.is_ipb, false)?; + let mut cbpy = br.read_cb(&self.tables.cbpy_cb)?; +// if /* !aiv && */(cbpc & 3) != 3 { + cbpy ^= 0xF; +// } + let cbp = (cbpy << 2) | (cbpc & 3); + if dquant { + let idx = br.read(2)? as usize; + q = (i16::from(q) + i16::from(H263_DQUANT_TAB[idx])) as u8; + } + let mut binfo = BlockInfo::new(Type::P, cbp, q); + binfo.set_bpart(bbinfo); + if !is_4x4 { + let mvec: [MV; 1] = [decode_mv(br, &self.tables.mv_cb)?]; + binfo.set_mv(&mvec); + } else { + let mvec: [MV; 4] = [ + decode_mv(br, &self.tables.mv_cb)?, + decode_mv(br, &self.tables.mv_cb)?, + decode_mv(br, &self.tables.mv_cb)?, + decode_mv(br, &self.tables.mv_cb)? + ]; + binfo.set_mv(&mvec); + } + if self.is_pb { + let mut mvec: Vec = Vec::with_capacity(bbinfo.get_num_mv()); + for _ in 0..bbinfo.get_num_mv() { + let mv = decode_mv(br, &self.tables.mv_cb)?; + mvec.push(mv); + } + binfo.set_b_mv(mvec.as_slice()); + } + Ok(binfo) + }, + _ => Err(DecoderError::InvalidData), + } + } + + #[allow(unused_variables)] + fn decode_block_intra(&mut self, info: &BlockInfo, _sstate: &SliceState, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> { + self.decode_block(quant, true, coded, blk, if no < 4 { 0 } else { no - 3 }, info.get_acpred()) + } + + #[allow(unused_variables)] + fn decode_block_inter(&mut self, info: &BlockInfo, _sstate: &SliceState, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> { + self.decode_block(quant, false, coded, blk, if no < 4 { 0 } else { no - 3 }, ACPredMode::None) + } + + fn is_slice_end(&mut self) -> bool { self.br.peek(16) == 0 } +} + +impl VivoDecoder { + fn new() -> Self { + let mut coderead = H263ShortCodeReader::new(H263_INTRA_MCBPC); + let intra_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263ShortCodeReader::new(H263_INTER_MCBPC); + let inter_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263ShortCodeReader::new(H263_CBPY); + let cbpy_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263RLCodeReader::new(H263_RL_CODES); + let rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263RLCodeReader::new(H263_RL_CODES_AIC); + let aic_rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263ShortCodeReader::new(H263_MV); + let mv_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let tables = Tables { + intra_mcbpc_cb, + inter_mcbpc_cb, + cbpy_cb, + rl_cb, + aic_rl_cb, + mv_cb, + }; + + VivoDecoder{ + info: NACodecInfo::new_dummy(), + dec: H263BaseDecoder::new(true), + tables, + bdsp: H263BlockDSP::new(), + lastframe: None, + lastpts: None, + width: 0, + height: 0, + } + } +} + +impl NADecoder for VivoDecoder { + fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { + if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { + let w = vinfo.get_width(); + let h = vinfo.get_height(); + let fmt = formats::YUV420_FORMAT; + let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt)); + self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); + self.width = w; + self.height = h; + Ok(()) + } else { + Err(DecoderError::InvalidData) + } + } + fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult { + let src = pkt.get_buffer(); + + if src.len() == 0 { + let buftype; + let ftype; + if self.lastframe.is_none() { + buftype = NABufferType::None; + ftype = FrameType::Skip; + } else { + let mut buf = None; + std::mem::swap(&mut self.lastframe, &mut buf); + buftype = buf.unwrap(); + ftype = FrameType::B; + } + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype); + frm.set_keyframe(false); + frm.set_frame_type(ftype); + if self.lastpts.is_some() { + frm.set_pts(self.lastpts); + self.lastpts = None; + } + return Ok(frm.into_ref()); + } + let mut ibr = VivoBR::new(&src, &self.tables, self.width, self.height); + + let bufinfo = self.dec.parse_frame(&mut ibr, &self.bdsp)?; + + let mut cur_pts = pkt.get_pts(); + if !self.dec.is_intra() { + let bret = self.dec.get_bframe(&self.bdsp); + if let Ok(b_buf) = bret { + self.lastframe = Some(b_buf); + self.lastpts = pkt.get_pts(); + if let Some(pts) = pkt.get_pts() { + cur_pts = Some(pts + 1); + } + } + } + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(self.dec.is_intra()); + frm.set_frame_type(if self.dec.is_intra() { FrameType::I } else { FrameType::P }); + frm.set_pts(cur_pts); + Ok(frm.into_ref()) + } + fn flush(&mut self) { + self.dec.flush(); + } +} + + +pub fn get_decoder() -> Box { + Box::new(VivoDecoder::new()) +} + +#[cfg(test)] +mod test { + use nihav_core::codecs::RegisteredDecoders; + use nihav_core::demuxers::RegisteredDemuxers; + use nihav_codec_support::test::dec_video::*; + use crate::vivo_register_all_codecs; + use crate::vivo_register_all_demuxers; + #[test] + fn test_vivo1() { + let mut dmx_reg = RegisteredDemuxers::new(); + vivo_register_all_demuxers(&mut dmx_reg); + let mut dec_reg = RegisteredDecoders::new(); + vivo_register_all_codecs(&mut dec_reg); + +test_file_decoding("vivo", "assets/Misc/gr_al.viv", Some(16), true, false, Some("viv1"), &dmx_reg, &dec_reg); +// test_decoding("vivo", "vivo1", "assets/Misc/gr_al.viv", Some(16), +// &dmx_reg, &dec_reg, ExpectedTestResult::GenerateMD5Frames)); + } + #[test] + fn test_vivo2() { + let mut dmx_reg = RegisteredDemuxers::new(); + vivo_register_all_demuxers(&mut dmx_reg); + let mut dec_reg = RegisteredDecoders::new(); + vivo_register_all_codecs(&mut dec_reg); + +test_file_decoding("vivo", "assets/Misc/02-KimagureOrangeRoad.viv", Some(50), true, false, Some("viv2"), &dmx_reg, &dec_reg); +panic!("end"); +// test_decoding("vivo", "vivo2", "assets/Misc/greetings.viv", Some(16), +// &dmx_reg, &dec_reg, ExpectedTestResult::GenerateMD5Frames)); + } +}