X-Git-Url: https://git.nihav.org/?p=nihav.git;a=blobdiff_plain;f=nihav-realmedia%2Fsrc%2Fcodecs%2Frv40enc%2Fbitstream.rs;fp=nihav-realmedia%2Fsrc%2Fcodecs%2Frv40enc%2Fbitstream.rs;h=bd0bacc926d3d214c72e012960751e619668f009;hp=0000000000000000000000000000000000000000;hb=4965a5e560c5e194c5b5163c591fcade5f56c3f0;hpb=6bd5b458d9889f092abe9b582bd531ed08a8dc51 diff --git a/nihav-realmedia/src/codecs/rv40enc/bitstream.rs b/nihav-realmedia/src/codecs/rv40enc/bitstream.rs new file mode 100644 index 0000000..bd0bacc --- /dev/null +++ b/nihav-realmedia/src/codecs/rv40enc/bitstream.rs @@ -0,0 +1,534 @@ +use nihav_core::frame::FrameType; +use nihav_core::io::bitwriter::*; +use nihav_core::io::intcode::*; +use nihav_codec_support::codecs::MV; +use super::types::*; +use super::super::rv34codes::*; +use super::super::rv40data::*; + +pub fn write_slice_header(bw: &mut BitWriter, ftype: FrameType, q: usize, set_idx: usize, deblock: bool, pts: u32) { + bw.write0(); + match ftype { + FrameType::I => bw.write(0, 2), + FrameType::P => bw.write(2, 2), + FrameType::B => bw.write(3, 2), + _ => unreachable!(), + }; + bw.write(q as u32, 5); + bw.write(0, 2); // unknown + bw.write(set_idx as u32, 2); + bw.write(!deblock as u32, 1); + bw.write(pts, 13); +} + +pub fn write_slice_dimensions(bw: &mut BitWriter, width: usize, height: usize) { + let wcode = match width { + 160 => 0, + 176 => 1, + 240 => 2, + 320 => 3, + 352 => 4, + 640 => 5, + 704 => 6, + _ => 7, + }; + bw.write(wcode, 3); + if wcode == 7 { + let mut w = width >> 2; + while w >= 255 { + bw.write(255, 8); + w -= 255; + } + bw.write(w as u32, 8); + } + + let hcode = match height { + 120 => 0, + 132 => 1, + 144 => 2, + 240 => 3, + 288 => 4, + 480 => 5, + 180 => 6, + 360 => 7, + 576 => 8, + _ => 9, + }; + if hcode < 6 { + bw.write(hcode, 3); + } else { + bw.write(hcode + 6, 4); + if hcode == 9 { + let mut h = height >> 2; + while h >= 255 { + bw.write(255, 8); + h -= 255; + } + bw.write(h as u32, 8); + } + } +} + +pub fn write_slice_mb_idx(bw: &mut BitWriter, mb_idx: usize, num_mbs: usize) { + let mba_bits = match num_mbs - 1 { + 0..= 47 => 6, + 48..= 98 => 7, + 99..= 395 => 9, + 396..=1583 => 11, + 1584..=6335 => 13, + 6336..=9215 => 14, + _ => unreachable!(), + }; + bw.write(mb_idx as u32, mba_bits); +} + +pub fn write_skip_count(bw: &mut BitWriter, skip_count: u32) { + bw.write_code(UintCodeType::Gamma, skip_count); +} + +fn write_mv(bw: &mut BitWriter, mv: MV) { + let xcode = if mv.x > 0 { (mv.x - 1) * 2 + 1 } else { -mv.x * 2 } as u32; + let ycode = if mv.y > 0 { (mv.y - 1) * 2 + 1 } else { -mv.y * 2 } as u32; + + bw.write_code(UintCodeType::Gamma, xcode); + bw.write_code(UintCodeType::Gamma, ycode); +} + +pub fn write_mb_header(bw: &mut BitWriter, ftype: FrameType, sstate: &SliceState, mbstate: &MBState) { + let mb_idx = mbstate.get_mb_idx(sstate.mb_x, sstate.mb_y); + let pred_mbt = mbstate.get_pred_mbtype(sstate, ftype == FrameType::B); + + let set_id = pred_mbt.to_code(); + + if ftype != FrameType::I { + let (codes, lens) = if ftype == FrameType::P { + (&RV40_PTYPE_CODES[set_id][..], &RV40_PTYPE_BITS[set_id][..]) + } else { + (&RV40_BTYPE_CODES[set_id][..], &RV40_BTYPE_BITS[set_id][..]) + }; + let idx = mbstate.mb_type[mb_idx].to_code(); + bw.write(codes[idx].into(), lens[idx]); + } + match mbstate.mb_type[mb_idx] { + MBType::Intra16 => { + if ftype == FrameType::I { + bw.write1(); + } + bw.write(mbstate.ipred[mbstate.get_blk4_idx(sstate.mb_x, sstate.mb_y)] as u32, 2); + }, + MBType::Intra => { + if ftype == FrameType::I { + bw.write0(); + bw.write1(); //dquant + } + let ystart = if sstate.has_t { 0 } else { 1 }; + let mut blk4_idx = mbstate.get_blk4_idx(sstate.mb_x, sstate.mb_y); + + if !sstate.has_t { + let mut code = 0; + for &el in mbstate.ipred[blk4_idx..][..4].iter() { + code = code * 2 + if el == 0 { 0 } else { 1 }; + } + bw.write(RV40_AIC_TOP_CODES[code].into(), RV40_AIC_TOP_BITS[code]); + blk4_idx += mbstate.blk4_stride; + } + for y in ystart..4 { + let mut x = 0; + while x < 4 { + let (lctx, tctx, trctx) = mbstate.get_ipred4x4_ctx(sstate.mb_x, sstate.mb_y, x, y); + let mode = mbstate.ipred[blk4_idx + x]; + let ctx_word = if x < 3 { + ((trctx & 0xF) as u16) + (((tctx & 0xF) as u16) << 4) + (((lctx & 0xF) as u16) << 8) + } else { 0xFFF }; + if let Some(idx) = RV40_AIC_PATTERNS.iter().position(|&x| x == ctx_word) { + let mode1 = mbstate.ipred[blk4_idx + x + 1]; + let code = mode * 9 + mode1; + bw.write(RV40_AIC_MODE2_CODES[idx][code as usize].into(), + RV40_AIC_MODE2_BITS[idx][code as usize]); + x += 2; + } else if tctx != -1 && lctx != -1 { + let idx = (tctx + lctx * 10) as usize; + let code = mode as usize; + bw.write(RV40_AIC_MODE1_CODES[idx][code].into(), + RV40_AIC_MODE1_BITS[idx][code]); + x += 1; + } else { + match lctx { + -1 if tctx < 2 => { + if mode == 0 { + bw.write1(); + } else { +assert_eq!(mode, 1); + bw.write0(); + } + }, + 0 | 2 => { + if mode == 0 { + bw.write1(); + } else { +assert_eq!(mode, 2); + bw.write0(); + } + }, + _ => { +assert_eq!(mode, 0); + }, + }; + x += 1; + } + } + blk4_idx += mbstate.blk4_stride; + } + }, + MBType::P16x16 | MBType::P16x16Mix => { + let diff_mv = mbstate.get_diff_mv(sstate, true, 0, 0); + write_mv(bw, diff_mv); + }, + MBType::P16x8 => { + let diff_mv = mbstate.get_diff_mv(sstate, true, 0, 0); + write_mv(bw, diff_mv); + let diff_mv = mbstate.get_diff_mv(sstate, true, 0, 1); + write_mv(bw, diff_mv); + }, + MBType::P8x16 => { + let diff_mv = mbstate.get_diff_mv(sstate, false, 0, 0); + write_mv(bw, diff_mv); + let diff_mv = mbstate.get_diff_mv(sstate, false, 1, 0); + write_mv(bw, diff_mv); + }, + MBType::P8x8 => { + for i in 0..4 { + let diff_mv = mbstate.get_diff_mv(sstate, false, i & 1, i >> 1); + write_mv(bw, diff_mv); + } + }, + MBType::Forward => { + let fwd_diff = mbstate.get_diff_mv_b(sstate, true); + write_mv(bw, fwd_diff); + }, + MBType::Backward => { + let bwd_diff = mbstate.get_diff_mv_b(sstate, false); + write_mv(bw, bwd_diff); + }, + MBType::Bidir => { + let fwd_diff = mbstate.get_diff_mv_b(sstate, true); + let bwd_diff = mbstate.get_diff_mv_b(sstate, false); + write_mv(bw, fwd_diff); + write_mv(bw, bwd_diff); + }, + MBType::Invalid => unreachable!(), + _ => unimplemented!(), + }; +} + +trait CodeWriter { + fn write(&self, bw: &mut BitWriter, code: u16); +} + +impl CodeWriter for RV34CodeReader { + fn write(&self, bw: &mut BitWriter, to_write: u16) { + for (&sym, (&code, &bits)) in self.syms.iter().zip(self.codes.iter().zip(self.lengths.iter())) { + if sym == to_write { + bw.write(code, bits); + return; + } + } +unreachable!(); + } +} + +impl CodeWriter for RV34CBPCodeReader { + fn write(&self, bw: &mut BitWriter, to_write: u16) { + for (&sym, (&code, &bits)) in self.syms.iter().zip(self.codes.iter().zip(self.lengths.iter())) { + if u16::from(sym) == to_write { + bw.write(code, bits); + return; + } + } +unreachable!(); + } +} + +struct CBPSet { + cbp_pattern: RV34CodeReader, + cbp: [RV34CBPCodeReader; 4] +} + +impl CBPSet { + fn new(intra: bool, set: usize, subset: usize) -> Self { + if intra { + let cbp_pat = RV34CodeReader::new(&RV34_INTRA_CBPPAT[set][subset]); + let cbp0 = RV34CBPCodeReader::new(&RV34_INTRA_CBP[set][subset]); + let cbp1 = RV34CBPCodeReader::new(&RV34_INTRA_CBP[set][subset + 1*2]); + let cbp2 = RV34CBPCodeReader::new(&RV34_INTRA_CBP[set][subset + 2*2]); + let cbp3 = RV34CBPCodeReader::new(&RV34_INTRA_CBP[set][subset + 3*2]); + CBPSet { cbp_pattern: cbp_pat, cbp: [cbp0, cbp1, cbp2, cbp3] } + } else { + let cbp_pat = RV34CodeReader::new(&RV34_INTER_CBPPAT[set]); + let cbp0 = RV34CBPCodeReader::new(&RV34_INTER_CBP[set][0]); + let cbp1 = RV34CBPCodeReader::new(&RV34_INTER_CBP[set][1]); + let cbp2 = RV34CBPCodeReader::new(&RV34_INTER_CBP[set][2]); + let cbp3 = RV34CBPCodeReader::new(&RV34_INTER_CBP[set][3]); + CBPSet { cbp_pattern: cbp_pat, cbp: [cbp0, cbp1, cbp2, cbp3] } + } + } +} + +struct CoefSet { + pat0: Vec, + pat1: Vec, + pat2: Vec, +} + +impl CoefSet { + fn new(intra: bool, set: usize) -> Self { + if intra { + let first0 = RV34CodeReader::new(&RV34_INTRA_FIRSTPAT[set][0]); + let first1 = RV34CodeReader::new(&RV34_INTRA_FIRSTPAT[set][1]); + let first2 = RV34CodeReader::new(&RV34_INTRA_FIRSTPAT[set][2]); + let first3 = RV34CodeReader::new(&RV34_INTRA_FIRSTPAT[set][3]); + let firsts = vec![first0, first1, first2, first3]; + + let second0 = RV34CodeReader::new(&RV34_INTRA_SECONDPAT[set][0]); + let second1 = RV34CodeReader::new(&RV34_INTRA_SECONDPAT[set][1]); + let seconds = vec![second0, second1]; + + let third0 = RV34CodeReader::new(&RV34_INTRA_THIRDPAT[set][0]); + let third1 = RV34CodeReader::new(&RV34_INTRA_THIRDPAT[set][1]); + let thirds = vec![third0, third1]; + + CoefSet { pat0: firsts, pat1: seconds, pat2: thirds } + } else { + let first0 = RV34CodeReader::new(&RV34_INTER_FIRSTPAT[set][0]); + let first1 = RV34CodeReader::new(&RV34_INTER_FIRSTPAT[set][1]); + let firsts = vec![first0, first1]; + + let second0 = RV34CodeReader::new(&RV34_INTER_SECONDPAT[set][0]); + let second1 = RV34CodeReader::new(&RV34_INTER_SECONDPAT[set][1]); + let seconds = vec![second0, second1]; + + let third0 = RV34CodeReader::new(&RV34_INTER_THIRDPAT[set][0]); + let third1 = RV34CodeReader::new(&RV34_INTER_THIRDPAT[set][1]); + let thirds = vec![third0, third1]; + + CoefSet { pat0: firsts, pat1: seconds, pat2: thirds } + } + } +} + +struct FullSet { + cbp: Vec, + cset: CoefSet, + coeffs: RV34CodeReader, +} + +impl FullSet { + fn new(intra: bool, set: usize) -> Self { + if intra { + let cbp0 = CBPSet::new(intra, set, 0); + let cbp1 = CBPSet::new(intra, set, 1); + let cbp: Vec = vec![cbp0, cbp1]; + let cset = CoefSet::new(intra, set); + let coeffs = RV34CodeReader::new(&RV34_INTRA_COEFFS[set]); + FullSet { cbp, cset, coeffs } + } else { + let cbp0 = CBPSet::new(intra, set, 0); + let cbp: Vec = vec![cbp0]; + let cset = CoefSet::new(intra, set); + let coeffs = RV34CodeReader::new(&RV34_INTER_COEFFS[set]); + FullSet { cbp, cset, coeffs } + } + } + fn write_block(&self, bw: &mut BitWriter, blk: &Block, subset_idx: usize, luma: bool) { + let sblk0 = [blk.coeffs[0], blk.coeffs[1], blk.coeffs[4], blk.coeffs[5]]; + let sblk1 = [blk.coeffs[2], blk.coeffs[3], blk.coeffs[6], blk.coeffs[7]]; + let sblk2 = [blk.coeffs[8], blk.coeffs[12], blk.coeffs[9], blk.coeffs[13]]; // sub-block 2 has different order + let sblk3 = [blk.coeffs[10], blk.coeffs[11], blk.coeffs[14], blk.coeffs[15]]; + + let idx0 = get_subblock_index(&sblk0); + let idx1 = get_subblock_index(&sblk1); + let idx2 = get_subblock_index(&sblk2); + let idx3 = get_subblock_index(&sblk3); + + let mut cflags = idx0; + cflags = (cflags << 1) | ((idx1 != 0) as u16); + cflags = (cflags << 1) | ((idx2 != 0) as u16); + cflags = (cflags << 1) | ((idx3 != 0) as u16); + + self.cset.pat0[subset_idx].write(bw, cflags); + + if matches!(idx0, 0 | 27 | 54 | 81) { // only first coefficient is set + write_single_coeff(bw, &self.coeffs, sblk0[0], 3); + } else { + write_coeffs(bw, &self.coeffs, &sblk0); + } + if idx1 != 0 { + self.cset.pat1[!luma as usize].write(bw, idx1); + write_coeffs(bw, &self.coeffs, &sblk1); + } + if idx2 != 0 { + self.cset.pat1[!luma as usize].write(bw, idx2); + write_coeffs(bw, &self.coeffs, &sblk2); + } + if idx3 != 0 { + self.cset.pat2[!luma as usize].write(bw, idx3); + write_coeffs(bw, &self.coeffs, &sblk3); + } + } +} + +fn write_coeffs(bw: &mut BitWriter, coeffs: &RV34CodeReader, blk: &[i16; 4]) { + for (&val, &limit) in blk.iter().zip([3i16, 2, 2, 2].iter()) { + write_single_coeff(bw, coeffs, val, limit); + } +} + +fn write_single_coeff(bw: &mut BitWriter, coeffs: &RV34CodeReader, val: i16, limit: i16) { + if val != 0 { + if val.abs() >= limit { + let mut val = (val.abs() - limit) as u16; + if val > 23 { + val -= 22; + let bits = (15 - val.leading_zeros()) as u16; + coeffs.write(bw, bits + 23); + bw.write(u32::from(val - (1 << bits)), bits as u8); + } else { + coeffs.write(bw, val); + } + } + if val > 0 { + bw.write0(); + } else { + bw.write1(); + } + } +} + +pub struct CodeSets { + super_idx: usize, + set_idx: usize, + intra: bool, + is16: bool, + is_p16: bool, + + iset: Vec, + pset: Vec, +} + +impl CodeSets { + pub fn new() -> Self { + let mut iset: Vec = Vec::with_capacity(5); + for set in 0..5 { iset.push(FullSet::new(true, set)); } + let mut pset: Vec = Vec::with_capacity(7); + for set in 0..7 { pset.push(FullSet::new(false, set)); } + + Self { + iset, pset, + super_idx: 0, + set_idx: 0, + intra: false, + is16: false, + is_p16: false, + } + } + pub fn init(&mut self, quant: usize, subset: usize) { + let mut idx = quant as usize; + if (subset == 2) && (idx < 19) { + idx += 10; + } else if (subset != 0) && (idx < 26) { + idx += 5; + } + if idx > 30 { + idx = 30; + } + self.super_idx = idx; + } + pub fn set_params(&mut self, mbtype: &MacroblockType) { + self.is_p16 = matches!(*mbtype, MacroblockType::InterMix(_)); + self.intra = mbtype.is_intra() || self.is_p16; + self.is16 = mbtype.is_16(); + self.set_idx = if self.intra { + RV34_SET_IDX_INTRA[self.super_idx] + } else { + RV34_SET_IDX_INTER[self.super_idx] + }; + } + fn write_cbp(&self, bw: &mut BitWriter, coded_pat: [bool; 24], cbp_code: &CBPSet) { + let mut cbp_pat = 0u16; + for i in 16..20 { + cbp_pat = cbp_pat * 3 + (coded_pat[i] as u16) + (coded_pat[i + 4] as u16); + } + let mut nnz = 0usize; + for blk4 in coded_pat[..16].chunks(4) { + let cur_nz = blk4.contains(&true); + if cur_nz { + nnz += 1; + } + cbp_pat = cbp_pat * 2 + (cur_nz as u16); + } + nnz = nnz.saturating_sub(1); + + cbp_code.cbp_pattern.write(bw, cbp_pat); + for blk4 in coded_pat[..16].chunks(4) { + let pat = (blk4[3] as u16) * 32 + (blk4[2] as u16) * 16 + (blk4[1] as u16) * 2 + (blk4[0] as u16); + if pat != 0 { + cbp_code.cbp[nnz].write(bw, pat); + } + } + for i in 16..20 { + if coded_pat[i] ^ coded_pat[i + 4] { + if coded_pat[i] { + bw.write1(); + } else { + bw.write0(); + } + } + } + } + pub fn write_coeffs(&mut self, bw: &mut BitWriter, coeffs: &[Block; 25]) { + let mut fset = if self.intra { &self.iset[self.set_idx] } else { &self.pset[self.set_idx] }; + + const CODED_ORDER: [usize; 24] = [0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]; + let cbp_code = &fset.cbp[if self.is16 { 1 } else { 0 }]; + let mut coded_blk = [false; 24]; + let mut coded_pat = [false; 24]; + for (i, ((cpat, cblk), &seq)) in coded_pat.iter_mut().zip(coded_blk.iter_mut()) + .zip(CODED_ORDER.iter()).enumerate() { + *cpat = !coeffs[seq].is_empty(); + *cblk = !coeffs[i].is_empty(); + } + self.write_cbp(bw, coded_pat, cbp_code); + + if self.is16 { + fset.write_block(bw, &coeffs[24], 3, true); + } + let (luma_set, chroma_set) = if self.intra { + (if self.is16 { 2 } else { 1 }, if !self.is_p16 { 0 } else { 1 }) + } else { + (0, 1) + }; + let mut citer = coded_blk.iter(); + for blk in coeffs[..16].iter() { + if let Some(true) = citer.next() { + fset.write_block(bw, blk, luma_set, true); + } + } + if self.is_p16 { + self.set_idx = RV34_SET_IDX_INTER[self.super_idx]; + fset = &self.pset[self.set_idx]; + } + for blk in coeffs[16..24].iter() { + if let Some(true) = citer.next() { + fset.write_block(bw, blk, chroma_set, false); + } + } + } +} + +fn get_subblock_index(blk: &[i16; 4]) -> u16 { + let mut idx = blk[0].abs().min(3) as u16; + idx = idx * 3 + (blk[1].abs().min(2) as u16); + idx = idx * 3 + (blk[2].abs().min(2) as u16); + idx = idx * 3 + (blk[3].abs().min(2) as u16); + idx +}