X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-realmedia%2Fsrc%2Fcodecs%2Frv20.rs;h=0d24b28cc3dcaa1e588837c951d843f1a9ae94ea;hb=401b2b60a38e3eb19ae19aee9e652f7c8c0cf6f8;hp=44386f6967b4c0a90cc8e11d77920ea9ce8fc2eb;hpb=171860fcc4a4ba3ec28bc4b720b9f582377be4cf;p=nihav.git diff --git a/nihav-realmedia/src/codecs/rv20.rs b/nihav-realmedia/src/codecs/rv20.rs index 44386f6..0d24b28 100644 --- a/nihav-realmedia/src/codecs/rv20.rs +++ b/nihav-realmedia/src/codecs/rv20.rs @@ -3,10 +3,12 @@ use nihav_core::io::codebook::*; use nihav_core::formats; use nihav_core::frame::*; use nihav_core::codecs::*; -use nihav_core::codecs::h263::*; -use nihav_core::codecs::h263::code::H263BlockDSP; -use nihav_core::codecs::h263::decoder::*; -use nihav_core::codecs::h263::data::*; +use nihav_codec_support::codecs::{MV, ZIGZAG}; +use nihav_codec_support::codecs::blockdsp; +use nihav_codec_support::codecs::h263::*; +use nihav_codec_support::codecs::h263::code::{H263_INTERP_FUNCS, H263_INTERP_AVG_FUNCS, h263_filter_row}; +use nihav_codec_support::codecs::h263::decoder::*; +use nihav_codec_support::codecs::h263::data::*; #[allow(dead_code)] @@ -37,7 +39,10 @@ struct RealVideo20Decoder { h: usize, minor_ver: u8, rpr: RPRInfo, - bdsp: H263BlockDSP, + bdsp: Box, + base_ts: u64, + last_ts: u16, + next_ts: u16, } struct RealVideo20BR<'a> { @@ -53,6 +58,7 @@ struct RealVideo20BR<'a> { mb_pos_bits: u8, minor_ver: u8, rpr: RPRInfo, + pts: u16, } struct RV20SliceInfo { @@ -66,9 +72,125 @@ struct RV20SliceInfo { h: usize, } +#[derive(Default)] +struct RV20BlockDSP {} + impl RV20SliceInfo { fn new(ftype: Type, seq: u32, qscale: u8, mb_x: usize, mb_y: usize, mb_pos: usize, w: usize, h: usize) -> Self { - RV20SliceInfo { ftype: ftype, seq: seq, qscale: qscale, mb_x: mb_x, mb_y: mb_y, mb_pos: mb_pos, w: w, h: h } + RV20SliceInfo { ftype, seq, qscale, mb_x, mb_y, mb_pos, w, h } + } +} + +macro_rules! idct { + ($src: expr, $sstep: expr, $dst: expr, $dstep: expr, $bias: expr, $shift: expr, $dtype: tt) => { + let s0 = $src[0] as i32; + let s1 = $src[$sstep] as i32; + let s2 = $src[$sstep * 2] as i32; + let s3 = $src[$sstep * 3] as i32; + let s4 = $src[$sstep * 4] as i32; + let s5 = $src[$sstep * 5] as i32; + let s6 = $src[$sstep * 6] as i32; + let s7 = $src[$sstep * 7] as i32; + + let t0 = (s0 + s4).wrapping_mul(1448); + let t1 = (s0 - s4).wrapping_mul(1448); + let t2 = s2.wrapping_mul(1892) + s6.wrapping_mul(784); + let t3 = s2.wrapping_mul(784) - s6.wrapping_mul(1892); + let t4 = s1.wrapping_mul(2009) + s3.wrapping_mul(1703) + + s5.wrapping_mul(1138) + s7.wrapping_mul(400); + let t5 = s1.wrapping_mul(1703) - s3.wrapping_mul(400) + - s5.wrapping_mul(2009) - s7.wrapping_mul(1138); + let t6 = s1.wrapping_mul(1138) - s3.wrapping_mul(2009) + + s5.wrapping_mul(400) + s7.wrapping_mul(1703); + let t7 = s1.wrapping_mul(400) - s3.wrapping_mul(1138) + + s5.wrapping_mul(1703) - s7.wrapping_mul(2009); + + let t8 = t0 + t2; + let t9 = t0 - t2; + let ta = t1 + t3; + let tb = t1 - t3; + + $dst[0] = ((t8 + t4 + $bias) >> $shift) as $dtype; + $dst[$dstep] = ((ta + t5 + $bias) >> $shift) as $dtype; + $dst[$dstep * 2] = ((tb + t6 + $bias) >> $shift) as $dtype; + $dst[$dstep * 3] = ((t9 + t7 + $bias) >> $shift) as $dtype; + $dst[$dstep * 4] = ((t9 - t7 + $bias) >> $shift) as $dtype; + $dst[$dstep * 5] = ((tb - t6 + $bias) >> $shift) as $dtype; + $dst[$dstep * 6] = ((ta - t5 + $bias) >> $shift) as $dtype; + $dst[$dstep * 7] = ((t8 - t4 + $bias) >> $shift) as $dtype; + } +} + +impl BlockDSP for RV20BlockDSP { + fn idct(&self, blk: &mut [i16; 64]) { + let mut tmp = [0i32; 64]; + for (dst, src) in tmp.chunks_mut(8).zip(blk.chunks(8)) { + idct!(src, 1, dst, 1, 0, 4, i32); + } + for i in 0..8 { + idct!(&tmp[i..], 8, &mut blk[i..], 8, 1 << 19, 20, i16); + } + } + fn copy_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV) { + let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; + let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 }); + + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_FUNCS); + blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS); + blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS); + } + fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mvs: &[MV; 4]) { + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + for i in 0..4 { + let xadd = (i & 1) * 8; + let yadd = (i & 2) * 4; + let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize; + + blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS); + } + + let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize]; + let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize]; + let mode = ((cmx & 1) + (cmy & 1) * 2) as usize; + for plane in 1..3 { + blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS); + } + } + fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV) { + let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; + let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 }); + + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_AVG_FUNCS); + blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS); + blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS); + } + fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mvs: &[MV; 4]) { + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + for i in 0..4 { + let xadd = (i & 1) * 8; + let yadd = (i & 2) * 4; + let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize; + + blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS); + } + + let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize]; + let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize]; + let mode = ((cmx & 1) + (cmy & 1) * 2) as usize; + for plane in 1..3 { + blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS); + } + } + fn filter_row(&self, buf: &mut NAVideoBuffer, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) { + h263_filter_row(buf, mb_y, mb_w, cbpi) } } @@ -78,7 +200,7 @@ impl<'a> RealVideo20BR<'a> { let mut slice_offs = Vec::with_capacity(nslices); { let offs = &src[1..][..nslices * 8]; - let mut br = BitReader::new(offs, offs.len(), BitReaderMode::BE); + let mut br = BitReader::new(offs, BitReaderMode::BE); for _ in 0..nslices { br.skip(32).unwrap(); let off = br.read(32).unwrap(); @@ -97,18 +219,19 @@ impl<'a> RealVideo20BR<'a> { } } RealVideo20BR { - br: BitReader::new(&src[soff..], src.len() - soff, BitReaderMode::BE), - tables: tables, + br: BitReader::new(&src[soff..], BitReaderMode::BE), + tables, num_slices: nslices, slice_no: 0, slice_off: slice_offs, w: width, h: height, - mb_w: mb_w, - mb_h: mb_h, + mb_w, + mb_h, mb_pos_bits: mbpb, - minor_ver: minor_ver, - rpr: rpr, + minor_ver, + rpr, + pts: 0, } } @@ -126,12 +249,12 @@ impl<'a> RealVideo20BR<'a> { let scan = match acpred { ACPredMode::Hor => H263_SCAN_V, ACPredMode::Ver => H263_SCAN_H, - _ => H263_ZIGZAG, + _ => &ZIGZAG, }; let rl_cb = if sstate.is_iframe { &self.tables.aic_rl_cb } else { &self.tables.rl_cb }; - let q_add = if quant == 0 || sstate.is_iframe { 0i16 } else { ((quant - 1) | 1) as i16 }; - let q = if plane_no == 0 { (quant * 2) as i16 } else { H263_CHROMA_QUANT[quant as usize] as i16 }; + 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 || sstate.is_iframe { 0i16 } else { (((q >> 1) - 1) | 1) as i16 }; while idx < 64 { let code = br.read_cb(rl_cb)?; let run; @@ -142,7 +265,11 @@ impl<'a> RealVideo20BR<'a> { level = code.get_level(); last = code.is_last(); if br.read_bool()? { level = -level; } - level = (level * q) + q_add; + 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; @@ -152,7 +279,11 @@ impl<'a> RealVideo20BR<'a> { let top = br.read_s(6)? as i16; level = (top << 5) | low; } - level = (level * q) + q_add; + if level >= 0 { + level = (level * q) + q_add; + } else { + level = (level * q) - q_add; + } if level < -2048 { level = -2048; } if level > 2047 { level = 2047; } } @@ -381,6 +512,7 @@ impl<'a> RealVideo20BR<'a> { } else { br.read(13)? << 3 }; + self.pts = seq as u16; let w; let h; if self.rpr.present { @@ -432,32 +564,35 @@ impl RealVideo20Decoder { let mv_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); let tables = Tables { - intra_mcbpc_cb: intra_mcbpc_cb, - inter_mcbpc_cb: inter_mcbpc_cb, - mbtype_b_cb: mbtype_b_cb, - cbpy_cb: cbpy_cb, - cbpc_b_cb: cbpc_b_cb, - rl_cb: rl_cb, - aic_rl_cb: aic_rl_cb, - mv_cb: mv_cb, + intra_mcbpc_cb, + inter_mcbpc_cb, + mbtype_b_cb, + cbpy_cb, + cbpc_b_cb, + rl_cb, + aic_rl_cb, + mv_cb, }; RealVideo20Decoder{ info: NACodecInfoRef::default(), dec: H263BaseDecoder::new_b_frames(false), - tables: tables, + tables, w: 0, h: 0, minor_ver: 0, rpr: RPRInfo { present: false, bits: 0, widths: [0; 8], heights: [0; 8] }, - bdsp: H263BlockDSP::new(), + bdsp: Box::new(RV20BlockDSP::default()), + base_ts: 0, + last_ts: 0, + next_ts: 0, } } } impl NADecoder for RealVideo20Decoder { #[allow(unused_variables)] - fn init(&mut self, info: NACodecInfoRef) -> DecoderResult<()> { + 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(); @@ -491,18 +626,33 @@ impl NADecoder for RealVideo20Decoder { 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(); let mut ibr = RealVideo20BR::new(&src, &self.tables, self.w, self.h, self.minor_ver, self.rpr); - let bufinfo = self.dec.parse_frame(&mut ibr, &self.bdsp)?; + let bufinfo = self.dec.parse_frame(&mut ibr, self.bdsp.as_ref())?; let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + let ftype = self.dec.get_frame_type(); + let pts = ibr.pts; + if ftype != FrameType::B { + self.last_ts = self.next_ts; + self.next_ts = pts; + if self.last_ts > self.next_ts { + self.base_ts += 1 << 16; + } + } + let ts_diff = self.next_ts.wrapping_sub(pts); + let ts = self.base_ts + (self.next_ts as u64) - (ts_diff as u64); frm.set_keyframe(self.dec.is_intra()); - frm.set_frame_type(self.dec.get_frame_type()); + frm.set_frame_type(ftype); + frm.set_pts(Some(ts >> 3)); Ok(frm.into_ref()) } + fn flush(&mut self) { + self.dec.flush(); + } } struct MBB { blocks: usize, bits: u8 } @@ -516,7 +666,7 @@ const H263_MBB: &[MBB; 7] = &[ MBB{ blocks: 65536, bits: 14 }, ]; -pub fn get_decoder() -> Box { +pub fn get_decoder() -> Box { Box::new(RealVideo20Decoder::new()) } @@ -524,9 +674,9 @@ 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::realmedia_register_all_codecs; - use crate::demuxers::realmedia_register_all_demuxers; + use nihav_codec_support::test::dec_video::*; + use crate::realmedia_register_all_codecs; + use crate::realmedia_register_all_demuxers; #[test] fn test_rv20() { let mut dmx_reg = RegisteredDemuxers::new();