From 3584b223ce417fe167dc90cb9a40e173f34823c0 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sun, 14 Jul 2019 18:35:04 +0200 Subject: [PATCH] semi-working VP5/6 decoder --- nihav-duck/Cargo.toml | 2 +- nihav-duck/src/codecs/mod.rs | 15 +- nihav-duck/src/codecs/vp3.rs | 51 -- nihav-duck/src/codecs/vp5.rs | 451 ++++++++++++ nihav-duck/src/codecs/vp56.rs | 1128 +++++++++++++++++++++++++++++ nihav-duck/src/codecs/vp6.rs | 967 +++++++++++++++++++++++++ nihav-duck/src/codecs/vpcommon.rs | 178 ++++- 7 files changed, 2734 insertions(+), 58 deletions(-) create mode 100644 nihav-duck/src/codecs/vp5.rs create mode 100644 nihav-duck/src/codecs/vp56.rs create mode 100644 nihav-duck/src/codecs/vp6.rs diff --git a/nihav-duck/Cargo.toml b/nihav-duck/Cargo.toml index cecf251..8817fa8 100644 --- a/nihav-duck/Cargo.toml +++ b/nihav-duck/Cargo.toml @@ -14,7 +14,7 @@ nihav_commonfmt = { path = "../nihav-commonfmt" } [features] default = ["all_decoders"] -all_decoders = ["decoder_truemotion1", "decoder_truemotionrt", "decoder_dk3_adpcm", "decoder_dk4_adpcm", "decoder_truemotion2", "decoder_truemotion2x", "decoder_vp3", "decoder_vp4"]#, "decoder_vp5", "decoder_vp6", "decoder_vp7", "decoder_on2avc"] +all_decoders = ["decoder_truemotion1", "decoder_truemotionrt", "decoder_dk3_adpcm", "decoder_dk4_adpcm", "decoder_truemotion2", "decoder_truemotion2x", "decoder_vp3", "decoder_vp4", "decoder_vp5", "decoder_vp6"]#, "decoder_vp7", "decoder_on2avc"] decoders = [] decoder_truemotion1 = ["decoders"] diff --git a/nihav-duck/src/codecs/mod.rs b/nihav-duck/src/codecs/mod.rs index 6a00e0f..2c934f1 100644 --- a/nihav-duck/src/codecs/mod.rs +++ b/nihav-duck/src/codecs/mod.rs @@ -12,14 +12,19 @@ mod truemotionrt; mod truemotion2; #[cfg(feature="decoder_truemotion2x")] mod truemotion2x; +#[cfg(any(feature="decoder_vp3", feature="decoder_vp4", feature="decoder_vp5", feature="decoder_vp6", feature="decoder_vp7"))] +#[macro_use] +mod vpcommon; #[cfg(any(feature="decoder_vp3", feature="decoder_vp4"))] mod vp3; #[cfg(any(feature="decoder_vp5", feature="decoder_vp6"))] mod vp56; +#[cfg(feature="decoder_vp5")] +mod vp5; +#[cfg(feature="decoder_vp6")] +mod vp6; #[cfg(feature="decoder_vp7")] mod vp7; -#[cfg(any(feature="decoder_vp3", feature="decoder_vp4", feature="decoder_vp5", feature="decoder_vp6", feature="decoder_vp7"))] -mod vpcommon; #[cfg(any(feature="decoder_dk3_adpcm", feature="decoder_dk4_adpcm"))] mod dkadpcm; @@ -40,9 +45,11 @@ const DUCK_CODECS: &[DecoderInfo] = &[ #[cfg(feature="decoder_vp4")] DecoderInfo { name: "vp4", get_decoder: vp3::get_decoder_vp4 }, #[cfg(feature="decoder_vp5")] - DecoderInfo { name: "vp5", get_decoder: vp56::get_decoder_vp5 }, + DecoderInfo { name: "vp5", get_decoder: vp5::get_decoder }, +#[cfg(feature="decoder_vp6")] + DecoderInfo { name: "vp6", get_decoder: vp6::get_decoder_vp6 }, #[cfg(feature="decoder_vp6")] - DecoderInfo { name: "vp6", get_decoder: vp56::get_decoder_vp6 }, + DecoderInfo { name: "vp6a", get_decoder: vp6::get_decoder_vp6_alpha }, #[cfg(feature="decoder_vp7")] DecoderInfo { name: "vp7", get_decoder: vp7::get_decoder }, diff --git a/nihav-duck/src/codecs/vp3.rs b/nihav-duck/src/codecs/vp3.rs index 487c671..d25d27f 100644 --- a/nihav-duck/src/codecs/vp3.rs +++ b/nihav-duck/src/codecs/vp3.rs @@ -542,55 +542,6 @@ macro_rules! fill_dc_pred { }; } -fn vp3_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) -{ - let mut didx = 0; - let mut sidx = 0; - for _ in 0..bh { - for x in 0..bw { dst[didx + x] = src[sidx + x]; } - didx += dstride; - sidx += sstride; - } -} - -fn vp3_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) -{ - let mut didx = 0; - let mut sidx = 0; - for _ in 0..bh { - for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + 1] as u16)) >> 1) as u8; } - didx += dstride; - sidx += sstride; - } -} - -fn vp3_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) -{ - let mut didx = 0; - let mut sidx = 0; - for _ in 0..bh { - for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16)) >> 1) as u8; } - didx += dstride; - sidx += sstride; - } -} - -fn vp3_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) -{ - let mut didx = 0; - let mut sidx = 0; - for _ in 0..bh { - for x in 0..bw { - dst[didx + x] = (((src[sidx + x] as u16) + - (src[sidx + x + 1] as u16) + - (src[sidx + x + sstride] as u16) + - (src[sidx + x + sstride + 1] as u16)) >> 2) as u8; - } - didx += dstride; - sidx += sstride; - } -} - fn vp31_loop_filter_v(frm: &mut NASimpleVideoFrame, x: usize, y: usize, plane: usize, loop_str: i16) { let off = frm.offset[plane] + x + y * frm.stride[plane]; vp31_loop_filter(frm.data, off, 1, frm.stride[plane], 8, loop_str); @@ -601,8 +552,6 @@ fn vp31_loop_filter_h(frm: &mut NASimpleVideoFrame, x: usize, y: usize, plan vp31_loop_filter(frm.data, off, frm.stride[plane], 1, 8, loop_str); } -pub const VP3_INTERP_FUNCS: &[blockdsp::BlkInterpFunc] = &[ vp3_interp00, vp3_interp01, vp3_interp10, vp3_interp11 ]; - impl VP34Decoder { fn new(version: u8) -> Self { let vt = alloc_video_buffer(NAVideoInfo::new(24, 24, false, YUV420_FORMAT), 4).unwrap(); diff --git a/nihav-duck/src/codecs/vp5.rs b/nihav-duck/src/codecs/vp5.rs new file mode 100644 index 0000000..abfd4d0 --- /dev/null +++ b/nihav-duck/src/codecs/vp5.rs @@ -0,0 +1,451 @@ +use nihav_core::codecs::*; +use nihav_core::io::bitreader::*; +use super::vpcommon::*; +use super::vp56::*; + +struct VP5BR {} + +impl VP5BR { + fn new() -> Self { + Self {} + } +} + +impl VP56Parser for VP5BR { + fn parse_header(&mut self, bc: &mut BoolCoder) -> DecoderResult { + let mut hdr = VP56Header::default(); + hdr.is_intra = !bc.read_bool(); + hdr.is_golden = hdr.is_intra; + bc.read_bool(); + hdr.quant = bc.read_bits(6) as u8; + if hdr.is_intra { + hdr.version = bc.read_bits(13) as u8; + validate!(hdr.version == 5); + hdr.profile = bc.read_bits(2) as u8; + hdr.interlaced = bc.read_bool(); + validate!(!hdr.interlaced); + hdr.mb_h = bc.read_bits(8) as u8; + hdr.mb_w = bc.read_bits(8) as u8; + hdr.disp_h = bc.read_bits(8) as u8; + hdr.disp_w = bc.read_bits(8) as u8; + validate!((hdr.mb_h > 0) && (hdr.mb_w > 0) && (hdr.disp_w > 0) && (hdr.disp_h > 0)); + validate!((hdr.disp_w <= hdr.mb_w) && (hdr.disp_h <= hdr.mb_h)); + hdr.scale = bc.read_bits(2) as u8; + } + + Ok(hdr) + } + fn decode_mv(&self, bc: &mut BoolCoder, model: &VP56MVModel) -> i16 { + if bc.read_prob(model.nz_prob) { + let sign = bc.read_prob(model.sign_prob); + let b0 = bc.read_prob(model.raw_probs[0]) as i16; + let b1 = bc.read_prob(model.raw_probs[1]) as i16; + let top: i16 = vp_tree!(bc, model.tree_probs[0], + vp_tree!(bc, model.tree_probs[1], + vp_tree!(bc, model.tree_probs[2], 0, 1), + vp_tree!(bc, model.tree_probs[3], 2, 3) + ), + vp_tree!(bc, model.tree_probs[4], + vp_tree!(bc, model.tree_probs[5], 4, 5), + vp_tree!(bc, model.tree_probs[6], 6, 7) + ) + ); + let val = (top << 2) | (b1 << 1) | b0; + if !sign { + val + } else { + -val + } + } else { + 0 + } + } + fn reset_models(&self, models: &mut VP56Models) { + for mdl in models.mv_models.iter_mut() { + mdl.nz_prob = 128; + mdl.sign_prob = 128; + mdl.raw_probs[0] = 85; + mdl.raw_probs[1] = 128; + mdl.tree_probs = [128; 7]; + } + } + fn decode_mv_models(&self, bc: &mut BoolCoder, models: &mut [VP56MVModel; 2]) -> DecoderResult<()> { + const HAS_NZ_PROB: [u8; 2] = [ 243, 235 ]; + const HAS_SIGN_PROB: [u8; 2] = [ 220, 211 ]; + const HAS_RAW0_PROB: [u8; 2] = [ 251, 246 ]; + const HAS_RAW1_PROB: [u8; 2] = [ 253, 249 ]; + const HAS_TREE_PROB: [[u8; 7]; 2] = [ + [ 237, 232, 241, 245, 247, 251, 253 ], + [ 234, 231, 248, 249, 252, 252, 254 ] + ]; + for comp in 0..2 { + if bc.read_prob(HAS_NZ_PROB[comp]) { + models[comp].nz_prob = bc.read_probability(); + } + if bc.read_prob(HAS_SIGN_PROB[comp]) { + models[comp].sign_prob = bc.read_probability(); + } + if bc.read_prob(HAS_RAW0_PROB[comp]) { + models[comp].raw_probs[0] = bc.read_probability(); + } + if bc.read_prob(HAS_RAW1_PROB[comp]) { + models[comp].raw_probs[1] = bc.read_probability(); + } + } + for comp in 0..2 { + for i in 0..7 { + if bc.read_prob(HAS_TREE_PROB[comp][i]) { + models[comp].tree_probs[i] = bc.read_probability(); + } + } + } + Ok(()) + } + fn decode_coeff_models(&self, bc: &mut BoolCoder, models: &mut VP56Models, is_intra: bool) -> DecoderResult<()> { + const COEF_PROBS: [[u8; 11]; 2] = [ + [ 146, 197, 181, 207, 232, 243, 238, 251, 244, 250, 249 ], + [ 179, 219, 214, 240, 250, 254, 244, 254, 254, 254, 254 ] + ]; + + let mut def_prob = [128u8; 11]; + for plane in 0..2 { + for i in 0..11 { + if bc.read_prob(COEF_PROBS[plane][i]) { + def_prob[i] = bc.read_probability(); + models.coeff_models[plane].dc_value_probs[i] = def_prob[i]; + } else if is_intra { + models.coeff_models[plane].dc_value_probs[i] = def_prob[i]; + } + } + } + for ctype in 0..3 { + for plane in 0..2 { + for group in 0..6 { + for i in 0..11 { + if bc.read_prob(VP5_AC_PROBS[ctype][plane][group][i]) { + def_prob[i] = bc.read_probability(); + models.coeff_models[plane].ac_val_probs[ctype][group][i] = def_prob[i]; + } else if is_intra { + models.coeff_models[plane].ac_val_probs[ctype][group][i] = def_prob[i]; + } + } + } + } + } + for plane in 0..2 { + let mdl = &mut models.coeff_models[plane]; + for i in 0..6 { + for j in 0..6 { + for k in 0..5 { + mdl.dc_token_probs[i][j][k] = rescale_prob(mdl.dc_value_probs[k], &VP5_DC_WEIGHTS[k][i][j], 254); + } + } + } + for ctype in 0..3 { + for group in 0..3 { + for i in 0..6 { + for j in 0..5 { + mdl.ac_type_probs[ctype][group][i][j] = rescale_prob(mdl.ac_val_probs[ctype][group][j], &VP5_AC_WEIGHTS[ctype][group][j][i], 254); + } + } + } + } + } + Ok(()) + } + fn decode_block(&self, bc: &mut BoolCoder, coeffs: &mut [i16; 64], model: &VP56CoeffModel, _vp6model: &VP6Models, fstate: &mut FrameState) -> DecoderResult<()> { + const COEF_GROUPS: [u8; 64] = [ + 0, 0, 1, 1, 2, 1, 1, 2, + 2, 1, 1, 2, 2, 2, 1, 2, + 2, 2, 2, 2, 1, 1, 2, 2, + 3, 3, 4, 3, 4, 4, 4, 3, + 3, 3, 3, 3, 4, 3, 3, 3, + 4, 4, 4, 4, 4, 3, 3, 4, + 4, 4, 3, 4, 4, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 5, 5 + ]; + + let mut ctype = 1; + let left_ctx = fstate.coeff_cat[fstate.ctx_idx][0] as usize; + let top_ctx = fstate.top_ctx as usize; + + let mut val_probs: &[u8; 11] = &model.dc_value_probs; + let mut tok_probs: &[u8] = &model.dc_token_probs[left_ctx][top_ctx]; + let mut idx = 0; + loop { + let token = vp_tree!(bc, tok_probs[0], + if ctype != 0 { vp_tree!(bc, tok_probs[1], break, 0) } else { 0 }, + vp_tree!(bc, tok_probs[2], + 1, + vp_tree!(bc, tok_probs[3], + vp_tree!(bc, tok_probs[4], 2, + vp_tree!(bc, val_probs[5], 3, 4)), + TOKEN_LARGE))); + let val = expand_token_bc(bc, val_probs, token, 5); + ctype = token.min(2) as usize; + if token < TOKEN_LARGE { + fstate.coeff_cat[fstate.ctx_idx][idx] = token.min(3); + } else { + fstate.coeff_cat[fstate.ctx_idx][idx] = 4; + } + coeffs[ZIGZAG[idx]] = val; + if idx > 0 { + coeffs[ZIGZAG[idx]] *= fstate.ac_quant; + } + + idx += 1; + if idx >= 64 { + break; + } + let group = COEF_GROUPS[idx] as usize; + val_probs = &model.ac_val_probs[ctype][group]; + tok_probs = if group > 2 { val_probs + } else { + let ctx = fstate.coeff_cat[fstate.ctx_idx][idx] as usize; + &model.ac_type_probs[ctype][group][ctx] + }; + } + let end = fstate.last_idx[fstate.ctx_idx].min(24); + fstate.last_idx[fstate.ctx_idx] = idx; + for i in idx..end { + fstate.coeff_cat[fstate.ctx_idx][i] = 5; + } + fstate.top_ctx = fstate.coeff_cat[fstate.ctx_idx][0]; + + Ok(()) + } + fn decode_block_huff(&self, _br: &mut BitReader, _coeffs: &mut [i16; 64], _vp6model: &VP6Models, _model: &VP6HuffModels, _fstate: &mut FrameState) -> DecoderResult<()> { + unreachable!(); + } + fn mc_block(&self, dst: &mut NASimpleVideoFrame, mc_buf: NAVideoBufferRef, src: NAVideoBufferRef, plane: usize, x: usize, y: usize, mv: MV, loop_str: i16) { + let (sx, sy, mx, my) = if (plane != 1) && (plane != 2) { + (mv.x / 2, mv.y / 2, mv.x & 1, mv.y & 1) + } else { + (mv.x / 4, mv.y / 4, (mv.x >> 1) & 1, (mv.y >> 1) & 1) + }; + let mode = (mx as usize) + (my as usize) * 2; + vp_copy_block(dst, src, plane, x, y, sx, sy, 0, 1, loop_str, + mode, VP3_INTERP_FUNCS, mc_buf); + } +} + +struct VP5Decoder { + dec: VP56Decoder, + info: NACodecInfoRef, + br: VP5BR, +} + +impl VP5Decoder { + fn new() -> Self { + Self { + dec: VP56Decoder::new(5, false, true), + info: NACodecInfoRef::default(), + br: VP5BR::new(), + } + } +} + +impl NADecoder for VP5Decoder { + fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { + if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { + let myvinfo = NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV420_FORMAT); + let myinfo = NACodecTypeInfo::Video(myvinfo.clone()); + self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); + self.dec.init(supp, myvinfo)?; + Ok(()) + } else { + Err(DecoderError::InvalidData) + } + } + fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult { + let src = pkt.get_buffer(); + + let (bufinfo, ftype) = self.dec.decode_frame(supp, src.as_slice(), &mut self.br)?; + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(ftype == FrameType::I); + frm.set_frame_type(ftype); + Ok(frm.into_ref()) + } +} + +pub fn get_decoder() -> Box { + Box::new(VP5Decoder::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_vp5() { + 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); + + let file = "assets/Duck/Cell-140.vp5"; + //let file = "assets/Duck/Chocolat-500.vp5"; + test_file_decoding("avi", file, Some(13), true, false, None/*Some("vp5")*/, &dmx_reg, &dec_reg); +//panic!("end"); + } +} + +const VP5_AC_PROBS: [[[[u8; 11]; 6]; 2]; 3] = [ + [ + [ + [ 227, 246, 230, 247, 244, 254, 254, 254, 254, 254, 254 ], + [ 202, 254, 209, 231, 231, 249, 249, 253, 254, 254, 254 ], + [ 206, 254, 225, 242, 241, 251, 253, 254, 254, 254, 254 ], + [ 235, 254, 241, 253, 252, 254, 254, 254, 254, 254, 254 ], + [ 234, 254, 248, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ] + ], [ + [ 240, 254, 248, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 238, 254, 240, 253, 254, 254, 254, 254, 254, 254, 254 ], + [ 244, 254, 251, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ] + ] + ], [ + [ + [ 206, 203, 227, 239, 247, 254, 253, 254, 254, 254, 254 ], + [ 207, 199, 220, 236, 243, 252, 252, 254, 254, 254, 254 ], + [ 212, 219, 230, 243, 244, 253, 252, 254, 254, 254, 254 ], + [ 236, 237, 247, 252, 253, 254, 254, 254, 254, 254, 254 ], + [ 240, 240, 248, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ] + ], [ + [ 230, 233, 249, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 238, 238, 250, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 248, 251, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ] + ] + ], [ + [ + [ 225, 239, 227, 231, 244, 253, 243, 254, 254, 253, 254 ], + [ 232, 234, 224, 228, 242, 249, 242, 252, 251, 251, 254 ], + [ 235, 249, 238, 240, 251, 254, 249, 254, 253, 253, 254 ], + [ 249, 253, 251, 250, 254, 254, 254, 254, 254, 254, 254 ], + [ 251, 250, 249, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ] + ], [ + [ 243, 244, 250, 250, 254, 254, 254, 254, 254, 254, 254 ], + [ 249, 248, 250, 253, 254, 254, 254, 254, 254, 254, 254 ], + [ 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ], + [ 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254 ] + ] + ] +]; + +const VP5_DC_WEIGHTS: [[[[i16; 2]; 6]; 6]; 5] = [ + [ + [ [154, 61], [141, 54], [ 90, 45], [ 54, 34], [ 54, 13], [128, 109] ], + [ [136, 54], [148, 45], [ 92, 41], [ 54, 33], [ 51, 15], [ 87, 113] ], + [ [ 87, 44], [ 97, 40], [ 67, 36], [ 46, 29], [ 41, 15], [ 64, 80] ], + [ [ 59, 33], [ 61, 31], [ 51, 28], [ 44, 22], [ 33, 12], [ 49, 63] ], + [ [ 69, 12], [ 59, 16], [ 46, 14], [ 31, 13], [ 26, 6], [ 92, 26] ], + [ [128, 108], [ 77, 119], [ 54, 84], [ 26, 71], [ 87, 19], [ 95, 155] ] + ], [ + [ [154, 4], [182, 0], [159, -8], [128, -5], [143, -5], [187, 55] ], + [ [182, 0], [228, -3], [187, -7], [174, -9], [189, -11], [169, 79] ], + [ [161, -9], [192, -8], [187, -9], [169, -10], [136, -9], [184, 40] ], + [ [164, -11], [179, -10], [174, -10], [161, -10], [115, -7], [197, 20] ], + [ [195, -11], [195, -11], [146, -10], [110, -6], [ 95, -4], [195, 39] ], + [ [182, 55], [172, 77], [177, 37], [169, 29], [172, 52], [ 92, 162] ] + ], [ + [ [174, 80], [164, 80], [ 95, 80], [ 46, 66], [ 56, 24], [ 36, 193] ], + [ [164, 80], [166, 77], [105, 76], [ 49, 68], [ 46, 31], [ 49, 186] ], + [ [ 97, 78], [110, 74], [ 72, 72], [ 44, 60], [ 33, 30], [ 69, 131] ], + [ [ 61, 61], [ 69, 63], [ 51, 57], [ 31, 48], [ 26, 27], [ 64, 89] ], + [ [ 67, 23], [ 51, 32], [ 36, 33], [ 26, 28], [ 20, 12], [ 44, 68] ], + [ [ 26, 197], [ 41, 189], [ 61, 129], [ 28, 103], [ 49, 52], [-12, 245] ] + ], [ + [ [102, 141], [ 79, 166], [ 72, 162], [ 97, 125], [179, 4], [307, 0] ], + [ [ 72, 168], [ 69, 175], [ 84, 160], [105, 127], [148, 34], [310, 0] ], + [ [ 84, 151], [ 82, 161], [ 87, 153], [ 87, 135], [115, 51], [317, 0] ], + [ [ 97, 125], [102, 131], [105, 125], [ 87, 122], [ 84, 64], [ 54, 184] ], + [ [166, 18], [146, 43], [125, 51], [ 90, 64], [ 95, 7], [ 38, 154] ], + [ [294, 0], [ 13, 225], [ 10, 225], [ 67, 168], [ 0, 167], [161, 94] ] + ], [ + [ [172, 76], [172, 75], [136, 80], [ 64, 98], [ 74, 67], [315, 0] ], + [ [169, 76], [207, 56], [164, 66], [ 97, 80], [ 67, 72], [328, 0] ], + [ [136, 80], [187, 53], [154, 62], [ 72, 85], [ -2, 105], [305, 0] ], + [ [ 74, 91], [128, 64], [113, 64], [ 61, 77], [ 41, 75], [259, 0] ], + [ [ 46, 84], [ 51, 81], [ 28, 89], [ 31, 78], [ 23, 77], [202, 0] ], + [ [323, 0], [323, 0], [300, 0], [236, 0], [195, 0], [328, 0] ] + ] +]; + +const VP5_AC_WEIGHTS: [[[[[i16; 2]; 6]; 5]; 3]; 3] = [ + [ + [ + [ [276, 0], [238, 0], [195, 0], [156, 0], [113, 0], [274, 0] ], + [ [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1] ], + [ [192, 59], [182, 50], [141, 48], [110, 40], [ 92, 19], [125,128] ], + [ [169, 87], [169, 83], [184, 62], [220, 16], [184, 0], [264, 0] ], + [ [212, 40], [212, 36], [169, 49], [174, 27], [ 8,120], [182, 71] ] + ], [ + [ [259, 10], [197, 19], [143, 22], [123, 16], [110, 8], [133, 88] ], + [ [ 0, 1], [256, 0], [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1] ], + [ [207, 46], [187, 50], [ 97, 83], [ 23,100], [ 41, 56], [ 56,188] ], + [ [166, 90], [146,108], [161, 88], [136, 95], [174, 0], [266, 0] ], + [ [264, 7], [243, 18], [184, 43], [-14,154], [ 20,112], [ 20,199] ] + ], [ + [ [230, 26], [197, 22], [159, 20], [146, 12], [136, 4], [ 54,162] ], + [ [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1], [ 0, 1] ], + [ [192, 59], [156, 72], [ 84,101], [ 49,101], [ 79, 47], [ 79,167] ], + [ [138,115], [136,116], [166, 80], [238, 0], [195, 0], [261, 0] ], + [ [225, 33], [205, 42], [159, 61], [ 79, 96], [ 92, 66], [ 28,195] ] + ] + ], [ + [ + [ [200, 37], [197, 18], [159, 13], [143, 7], [102, 5], [123,126] ], + [ [197, 3], [220, -9], [210,-12], [187, -6], [151, -2], [174, 80] ], + [ [200, 53], [187, 47], [159, 40], [118, 38], [100, 18], [141,111] ], + [ [179, 78], [166, 86], [197, 50], [207, 27], [187, 0], [115,139] ], + [ [218, 34], [220, 29], [174, 46], [128, 61], [ 54, 89], [187, 65] ] + ], [ + [ [238, 14], [197, 18], [125, 26], [ 90, 25], [ 82, 13], [161, 86] ], + [ [189, 1], [205, -2], [156, -4], [143, -4], [146, -4], [172, 72] ], + [ [230, 31], [192, 45], [102, 76], [ 38, 85], [ 56, 41], [ 64,173] ], + [ [166, 91], [141,111], [128,116], [118,109], [177, 0], [ 23,222] ], + [ [253, 14], [236, 21], [174, 49], [ 33,118], [ 44, 93], [ 23,187] ] + ], [ + [ [218, 28], [179, 28], [118, 35], [ 95, 30], [ 72, 24], [128,108] ], + [ [187, 1], [174, -1], [125, -1], [110, -1], [108, -1], [202, 52] ], + [ [197, 53], [146, 75], [ 46,118], [ 33,103], [ 64, 50], [118,126] ], + [ [138,114], [128,122], [161, 86], [243, -6], [195, 0], [ 38,210] ], + [ [215, 39], [179, 58], [ 97,101], [ 95, 85], [ 87, 70], [ 69,152] ] + ] + ], [ + [ + [ [236, 24], [205, 18], [172, 12], [154, 6], [125, 1], [169, 75] ], + [ [187, 4], [230, -2], [228, -4], [236, -4], [241, -2], [192, 66] ], + [ [200, 46], [187, 42], [159, 34], [136, 25], [105, 10], [179, 62] ], + [ [207, 55], [192, 63], [192, 54], [195, 36], [177, 1], [143, 98] ], + [ [225, 27], [207, 34], [200, 30], [131, 57], [ 97, 60], [197, 45] ] + ], [ + [ [271, 8], [218, 13], [133, 19], [ 90, 19], [ 72, 7], [182, 51] ], + [ [179, 1], [225, -1], [154, -2], [110, -1], [ 92, 0], [195, 41] ], + [ [241, 26], [189, 40], [ 82, 64], [ 33, 60], [ 67, 17], [120, 94] ], + [ [192, 68], [151, 94], [146, 90], [143, 72], [161, 0], [113,128] ], + [ [256, 12], [218, 29], [166, 48], [ 44, 99], [ 31, 87], [148, 78] ] + ], [ + [ [238, 20], [184, 22], [113, 27], [ 90, 22], [ 74, 9], [192, 37] ], + [ [184, 0], [215, -1], [141, -1], [ 97, 0], [ 49, 0], [264, 13] ], + [ [182, 51], [138, 61], [ 95, 63], [ 54, 59], [ 64, 25], [200, 45] ], + [ [179, 75], [156, 87], [174, 65], [177, 44], [174, 0], [164, 85] ], + [ [195, 45], [148, 65], [105, 79], [ 95, 72], [ 87, 60], [169, 63] ] + ] + ] +]; diff --git a/nihav-duck/src/codecs/vp56.rs b/nihav-duck/src/codecs/vp56.rs new file mode 100644 index 0000000..54c84a0 --- /dev/null +++ b/nihav-duck/src/codecs/vp56.rs @@ -0,0 +1,1128 @@ +use nihav_core::codecs::*; +use nihav_core::io::bitreader::*; +use super::vpcommon::*; + +pub const TOKEN_LARGE: u8 = 5; +pub const TOKEN_EOB: u8 = 42; + +#[derive(Clone,Copy,Debug,Default)] +#[allow(dead_code)] +pub struct VP56Header { + pub is_intra: bool, + pub is_golden: bool, + pub quant: u8, + pub multistream: bool, + pub use_huffman: bool, + pub version: u8, + pub profile: u8, + pub interlaced: bool, + pub offset: u16, + pub mb_w: u8, + pub mb_h: u8, + pub disp_w: u8, + pub disp_h: u8, + pub scale: u8, +} + +#[derive(Clone,Copy,Default)] +pub struct VP56MVModel { + pub nz_prob: u8, + pub sign_prob: u8, + pub raw_probs: [u8; 8], + pub tree_probs: [u8; 7], +} + +#[derive(Clone,Copy,Default)] +pub struct VP56MBTypeModel { + pub probs: [u8; 10], +} + +#[derive(Clone,Copy,Default)] +pub struct VP56CoeffModel { + pub dc_token_probs: [[[u8; 5]; 6]; 6], + pub dc_value_probs: [u8; 11], + pub ac_ctype_probs: [[[[u8; 5]; 5]; 6]; 3], + pub ac_type_probs: [[[[u8; 5]; 6]; 3]; 3], + pub ac_val_probs: [[[u8; 11]; 6]; 3], +} + +pub struct VP6Models { + pub scan_order: [usize; 64], + pub scan: [usize; 64], + pub zigzag: [usize; 64], + pub zero_run_probs: [[u8; 14]; 2], +} + +const MAX_HUFF_ELEMS: usize = 12; +#[derive(Clone,Copy,Default)] +pub struct VP6Huff { + pub codes: [u16; MAX_HUFF_ELEMS], + pub bits: [u8; MAX_HUFF_ELEMS], +} + +#[derive(Clone,Copy,Default)] +struct Node { + weight: u16, + sym: i8, + ch0: usize, + ch1: usize, +} + +fn prob2weight(a: u8, b: u8) -> u8 { + let w = (((a as u16) * (b as u16)) >> 8) as u8; + if w == 0 { + 1 + } else { + w + } +} + +impl VP6Huff { + fn build_codes(&mut self, probs: &[u8; 11]) { + let mut weights = [0u8; 12]; + + weights[11] = prob2weight( probs[0], probs[ 1]); + weights[ 0] = prob2weight( probs[0], !probs[ 1]); + weights[ 1] = prob2weight(!probs[0], probs[ 2]); + let lvroot = prob2weight(!probs[0], !probs[ 2]); + let tworoot = prob2weight( lvroot, probs[ 3]); + let hlroot = prob2weight( lvroot, !probs[ 3]); + weights[ 2] = prob2weight( tworoot, probs[ 4]); + let root34 = prob2weight( tworoot, !probs[ 4]); + weights[ 3] = prob2weight( root34, probs[ 5]); + weights[ 4] = prob2weight( root34, !probs[ 5]); + let c1root = prob2weight( hlroot, probs[ 6]); + let c34root = prob2weight( hlroot, !probs[ 6]); + weights[ 5] = prob2weight( c1root, probs[ 7]); + weights[ 6] = prob2weight( c1root, !probs[ 7]); + let c3root = prob2weight( c34root, probs[ 8]); + let c4root = prob2weight( c34root, !probs[ 8]); + weights[ 7] = prob2weight( c3root, probs[ 9]); + weights[ 8] = prob2weight( c3root, !probs[ 9]); + weights[ 9] = prob2weight( c4root, probs[10]); + weights[10] = prob2weight( c4root, !probs[10]); + + self.build(&weights); + } + fn build_codes_zero_run(&mut self, probs: &[u8; 14]) { + let mut weights = [0u8; 9]; + + let root = prob2weight( probs[0], probs[1]); + weights[0] = prob2weight( root, probs[2]); + weights[1] = prob2weight( root, !probs[2]); + + let root = prob2weight( probs[0], !probs[1]); + weights[2] = prob2weight( root, probs[3]); + weights[3] = prob2weight( root, !probs[3]); + + let root = prob2weight(!probs[0], probs[4]); + weights[8] = prob2weight(!probs[0], !probs[4]); + let root1 = prob2weight( root, probs[5]); + let root2 = prob2weight( root, !probs[5]); + weights[4] = prob2weight( root1, probs[6]); + weights[5] = prob2weight( root1, !probs[6]); + weights[6] = prob2weight( root2, probs[7]); + weights[7] = prob2weight( root2, !probs[7]); + + self.build(&weights); + } + fn build(&mut self, weights: &[u8]) { + let mut nodes = [Node::default(); MAX_HUFF_ELEMS * 2]; + let mut nlen = 0; + + for w in weights.iter().rev() { + let weight = *w as u16; + let mut pos = nlen; + for i in 0..nlen { + if nodes[i].weight > weight { + pos = i; + break; + } + } + for j in (pos..nlen).rev() { + nodes[j + 1] = nodes[j]; + } + nodes[pos].weight = weight; + nodes[pos].sym = (weights.len() - nlen - 1) as i8; + nlen += 1; + } + + let mut low = 0; + for _ in 0..nlen-1 { + let nnode = Node { + weight: nodes[low + 0].weight + nodes[low + 1].weight, + sym: -1, + ch0: low + 0, + ch1: low + 1, + }; + low += 2; + let mut pos = low; + while (pos < nlen) && (nodes[pos].weight < nnode.weight) { + pos += 1; + } + for j in (pos..nlen).rev() { + nodes[j + 1] = nodes[j]; + } + nodes[pos] = nnode; + nlen += 1; + } + self.get_codes(&nodes, nlen - 1, 0, 0); + for i in nlen..self.codes.len() { + self.codes[i] = self.codes[0]; + self.bits[i] = self.bits[0]; + } + } + fn get_codes(&mut self, nodes: &[Node], pos: usize, code: u16, len: u8) { + if nodes[pos].sym >= 0 { + self.codes[nodes[pos].sym as usize] = code; + self.bits [nodes[pos].sym as usize] = len; + } else { + self.get_codes(nodes, nodes[pos].ch0, (code << 1) | 0, len + 1); + self.get_codes(nodes, nodes[pos].ch1, (code << 1) | 1, len + 1); + } + } +} + +pub trait ReadHuff { + fn read_huff(&mut self, huff: &VP6Huff) -> DecoderResult; +} + +impl<'a> ReadHuff for BitReader<'a> { + fn read_huff(&mut self, huff: &VP6Huff) -> DecoderResult { + let peekval = self.peek(16); + for (i, (code, bit)) in huff.codes.iter().zip(huff.bits.iter()).enumerate() { + if (peekval >> (16 - *bit)) == (*code as u32) { + self.skip(*bit as u32)?; + return Ok(i as u8); + } + } + Err(DecoderError::InvalidData) + } +} + +#[derive(Clone,Copy,Default)] +pub struct VP6HuffModels { + pub dc_token_tree: [VP6Huff; 2], + pub ac_token_tree: [[[VP6Huff; 6]; 3]; 2], + pub zero_run_tree: [VP6Huff; 2], +} + +impl VP6Models { + fn new() -> Self { + Self { + scan_order: [0; 64], + scan: [0; 64], + zigzag: [0; 64], + zero_run_probs: [[0; 14]; 2], + } + } +} + +pub struct VP56Models { + pub mv_models: [VP56MVModel; 2], + pub mbtype_models: [[VP56MBTypeModel; 10]; 3], + pub coeff_models: [VP56CoeffModel; 2], + pub prob_xmitted: [[u8; 20]; 3], + pub vp6models: VP6Models, + pub vp6huff: VP6HuffModels, +} + +impl VP56Models { + fn new() -> Self { + Self { + mv_models: [VP56MVModel::default(); 2], + mbtype_models: [[VP56MBTypeModel::default(); 10]; 3], + coeff_models: [VP56CoeffModel::default(); 2], + prob_xmitted: [[0; 20]; 3], + vp6models: VP6Models::new(), + vp6huff: VP6HuffModels::default(), + } + } +} + +pub trait VP56Parser { + fn parse_header(&mut self, bc: &mut BoolCoder) -> DecoderResult; + fn reset_models(&self, models: &mut VP56Models); + fn decode_mv(&self, bc: &mut BoolCoder, model: &VP56MVModel) -> i16; + fn decode_mv_models(&self, bc: &mut BoolCoder, models: &mut [VP56MVModel; 2]) -> DecoderResult<()>; + fn decode_coeff_models(&self, bc: &mut BoolCoder, models: &mut VP56Models, is_intra: bool) -> DecoderResult<()>; + fn decode_block(&self, bc: &mut BoolCoder, coeffs: &mut [i16; 64], model: &VP56CoeffModel, vp6model: &VP6Models, fstate: &mut FrameState) -> DecoderResult<()>; + fn decode_block_huff(&self, br: &mut BitReader, coeffs: &mut [i16; 64], vp6model: &VP6Models, model: &VP6HuffModels, fstate: &mut FrameState) -> DecoderResult<()>; + fn mc_block(&self, dst: &mut NASimpleVideoFrame, mc_buf: NAVideoBufferRef, src: NAVideoBufferRef, plane: usize, x: usize, y: usize, mv: MV, loop_thr: i16); +} + +enum CoeffReader<'a> { + None, + Bool(BoolCoder<'a>), + Huff(BitReader<'a>), +} + +#[derive(Clone,Copy,Default)] +struct MBInfo { + mb_type: VPMBType, + mv: MV, +} + +pub struct FrameState { + pub mb_x: usize, + pub mb_y: usize, + pub plane: usize, + pub coeff_cat: [[u8; 64]; 4], + pub last_idx: [usize; 4], + pub top_ctx: u8, + pub ctx_idx: usize, + pub dc_quant: i16, + pub ac_quant: i16, + pub dc_zero_run: [usize; 2], + pub ac_zero_run: [usize; 2], +} + +impl FrameState { + fn new() -> Self { + Self { + mb_x: 0, + mb_y: 0, + plane: 0, + coeff_cat: [[0; 64]; 4], + last_idx: [0; 4], + top_ctx: 0, + ctx_idx: 0, + dc_quant: 0, + ac_quant: 0, + dc_zero_run: [0; 2], + ac_zero_run: [0; 2], + } + } +} + +pub struct GenericCache { + pub height: usize, + pub stride: usize, + pub xpos: usize, + pub data: Vec, + pub default: T, +} + +impl GenericCache { + fn new(height: usize, stride: usize, default: T) -> Self { + let mut ret = Self { + stride, + height, + xpos: 0, + data: Vec::with_capacity((height + 1) * stride), + default, + }; + ret.reset(); + ret + } + fn full_size(&self) -> usize { self.stride * (self.height + 1) } + fn reset(&mut self) { + self.data.truncate(0); + let size = self.full_size(); + self.data.resize(size, self.default); + self.xpos = self.stride + 1; + } + fn update_row(&mut self) { + for i in 0..self.stride { + self.data[i] = self.data[self.height * self.stride + i]; + } + self.data.truncate(self.stride); + let size = self.full_size(); + self.data.resize(size, self.default); + self.xpos = self.stride + 1; + } +} + +pub struct VP56Decoder { + version: u8, + has_alpha: bool, + flip: bool, + shuf: VPShuffler, + width: usize, + height: usize, + mb_w: usize, + mb_h: usize, + models: VP56Models, + coeffs: [[i16; 64]; 6], + last_mbt: VPMBType, + + loop_thr: i16, + ilace_prob: u8, + ilace_mb: bool, + + mb_info: Vec, + fstate: FrameState, + dc_y: GenericCache, + dc_u: GenericCache, + dc_v: GenericCache, + dc_a: GenericCache, + last_dc: [[i16; 4]; 3], + top_ctx: [Vec; 4], + + mc_buf: NAVideoBufferRef, +} + +fn rescale_mb_mode_prob(prob: u32, total: u32) -> u8 { + (255 * prob / (1 + total)) as u8 +} + +fn map_mb_type(mbtype: VPMBType) -> usize { + match mbtype { + VPMBType::InterNoMV => 0, + VPMBType::Intra => 1, + VPMBType::InterMV => 2, + VPMBType::InterNearest => 3, + VPMBType::InterNear => 4, + VPMBType::GoldenNoMV => 5, + VPMBType::GoldenMV => 6, + VPMBType::InterFourMV => 7, + VPMBType::GoldenNearest => 8, + VPMBType::GoldenNear => 9, + } +} + +pub const VP56_COEF_BASE: [i16; 6] = [ 5, 7, 11, 19, 35, 67 ]; +pub fn expand_token_bc(bc: &mut BoolCoder, val_probs: &[u8; 11], token: u8, version: u8) -> i16 { + const COEF_ADD_PROBS: [[u8; 12]; 6] = [ + [ 159, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 165, 145, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 173, 148, 140, 128, 0, 0, 0, 0, 0, 0, 0, 0 ], + [ 176, 155, 140, 135, 128, 0, 0, 0, 0, 0, 0, 0 ], + [ 180, 157, 141, 134, 130, 128, 0, 0, 0, 0, 0, 0 ], + [ 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 128 ], + ]; + + let mut sign = false; + let level; + if token < TOKEN_LARGE { + if token != 0 { + sign = bc.read_bool(); + } + level = token as i16; + } else { + let cat: usize = vp_tree!(bc, val_probs[6], + vp_tree!(bc, val_probs[7], 0, 1), + vp_tree!(bc, val_probs[8], + vp_tree!(bc, val_probs[9], 2, 3), + vp_tree!(bc, val_probs[10], 4, 5))); + if version == 5 { + sign = bc.read_bool(); + } + let mut add = 0i16; + let add_probs = &COEF_ADD_PROBS[cat]; + for prob in add_probs.iter() { + if *prob == 128 { break; } + add = (add << 1) | (bc.read_prob(*prob) as i16); + } + if version != 5 { + sign = bc.read_bool(); + } + level = VP56_COEF_BASE[cat] + add; + } + if !sign { + level + } else { + -level + } +} + +impl VP56Decoder { + pub fn new(version: u8, has_alpha: bool, flip: bool) -> Self { + let vt = alloc_video_buffer(NAVideoInfo::new(24, 24, false, YUV420_FORMAT), 4).unwrap(); + let mc_buf = vt.get_vbuf().unwrap(); + Self { + version, has_alpha, flip, + shuf: VPShuffler::new(), + width: 0, + height: 0, + mb_w: 0, + mb_h: 0, + models: VP56Models::new(), + coeffs: [[0; 64]; 6], + last_mbt: VPMBType::InterNoMV, + + loop_thr: 0, + ilace_prob: 0, + ilace_mb: false, + + mb_info: Vec::new(), + fstate: FrameState::new(), + dc_y: GenericCache::new(0, 0, 0), + dc_u: GenericCache::new(0, 0, 0), + dc_v: GenericCache::new(0, 0, 0), + dc_a: GenericCache::new(0, 0, 0), + last_dc: [[0; 4]; 3], + top_ctx: [Vec::new(), Vec::new(), Vec::new(), Vec::new()], + + mc_buf, + } + } + fn set_dimensions(&mut self, width: usize, height: usize) { + self.width = width; + self.height = height; + self.mb_w = (self.width + 15) >> 4; + self.mb_h = (self.height + 15) >> 4; + self.mb_info.resize(self.mb_w * self.mb_h, MBInfo::default()); + self.dc_y = GenericCache::new(2, 1 + self.mb_w * 2, 0); + self.dc_u = GenericCache::new(1, 1 + self.mb_w, 0); + self.dc_v = GenericCache::new(1, 1 + self.mb_w, 0); + self.dc_a = GenericCache::new(2, 1 + self.mb_w * 2, 0); + self.top_ctx = [vec![0; self.mb_w * 2], vec![0; self.mb_w], vec![0; self.mb_w], vec![0; self.mb_w * 2]]; + } + pub fn init(&mut self, supp: &mut NADecoderSupport, vinfo: NAVideoInfo) -> DecoderResult<()> { + supp.pool_u8.set_dec_bufs(3); + supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, vinfo.get_format()), 4)?; + self.set_dimensions(vinfo.get_width(), vinfo.get_height()); + Ok(()) + } + pub fn decode_frame(&mut self, supp: &mut NADecoderSupport, src: &[u8], br: &mut dyn VP56Parser) -> DecoderResult<(NABufferType, FrameType)> { + let aoffset; + let mut bc; + if self.has_alpha { + validate!(src.len() >= 7); + aoffset = ((src[0] as usize) << 16) | ((src[1] as usize) << 8) | (src[2] as usize); + validate!((aoffset > 0) && (aoffset < src.len() - 3)); + bc = BoolCoder::new(&src[3..])?; + } else { + validate!(src.len() >= 4); + aoffset = src.len(); + bc = BoolCoder::new(src)?; + } + let hdr = br.parse_header(&mut bc)?; + validate!((hdr.offset as usize) < aoffset); //XXX: take alpha 3 byte offset into account? + + if hdr.mb_w != 0 { + self.set_dimensions((hdr.mb_w as usize) * 16, (hdr.mb_h as usize) * 16); + } + let vinfo = NAVideoInfo::new(self.width, self.height, self.flip, YUV420_FORMAT); + let ret = supp.pool_u8.get_free(); + if ret.is_none() { + return Err(DecoderError::AllocError); + } + let mut buf = ret.unwrap(); + if buf.get_info() != vinfo { + self.shuf.clear(); + supp.pool_u8.reset(); + supp.pool_u8.prealloc_video(vinfo, 4)?; + let ret = supp.pool_u8.get_free(); + if ret.is_none() { + return Err(DecoderError::AllocError); + } + buf = ret.unwrap(); + } + let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap(); + + if hdr.is_intra { + self.shuf.clear(); + } + + let mut cr; + if hdr.multistream { + let off = (if self.has_alpha { 3 } else { 0 }) + (hdr.offset as usize); + if !hdr.use_huffman { + let bc2 = BoolCoder::new(&src[off..])?; + cr = CoeffReader::Bool(bc2); + } else { + let br = BitReader::new(&src[off..], aoffset - off, BitReaderMode::BE); + cr = CoeffReader::Huff(br); + } + } else { + cr = CoeffReader::None; + } + + if hdr.is_intra { + br.reset_models(&mut self.models); + self.reset_mbtype_models(); + } else { + self.decode_mode_prob_models(&mut bc)?; + br.decode_mv_models(&mut bc, &mut self.models.mv_models)?; + } + br.decode_coeff_models(&mut bc, &mut self.models, hdr.is_intra)?; + if hdr.use_huffman { + for i in 0..2 { + self.models.vp6huff.dc_token_tree[i].build_codes(&self.models.coeff_models[i].dc_value_probs); + } + for i in 0..2 { + for mode in 0..3 { + for band in 0..6 { + self.models.vp6huff.ac_token_tree[i][mode][band].build_codes(&self.models.coeff_models[i].ac_val_probs[mode][band]); + } + } + } + for i in 0..2 { + self.models.vp6huff.zero_run_tree[i].build_codes_zero_run(&self.models.vp6models.zero_run_probs[i]); + } + } + + if hdr.interlaced { + self.ilace_prob = bc.read_bits(8) as u8; + } + + self.fstate = FrameState::new(); + self.fstate.dc_quant = VP56_DC_QUANTS[hdr.quant as usize] * 4; + self.fstate.ac_quant = VP56_AC_QUANTS[hdr.quant as usize] * 4; + self.loop_thr = VP56_FILTER_LIMITS[hdr.quant as usize] as i16; + + self.last_mbt = VPMBType::InterNoMV; + self.dc_y.reset(); + self.dc_u.reset(); + self.dc_v.reset(); + self.dc_a.reset(); + for vec in self.top_ctx.iter_mut() { + for el in vec.iter_mut() { + *el = 0; + } + } + self.last_dc = [[0; 4]; 3]; + self.last_dc[0][1] = 0x80; + self.last_dc[0][2] = 0x80; + + self.ilace_mb = false; + for mb_y in 0..self.mb_h { + self.fstate.mb_y = mb_y; + self.fstate.coeff_cat = [[0; 64]; 4]; + self.fstate.last_idx = [24; 4]; + for mb_x in 0..self.mb_w { + self.fstate.mb_x = mb_x; + self.decode_mb(&mut dframe, &mut bc, &mut cr, br, &hdr, false)?; + } + self.dc_y.update_row(); + self.dc_u.update_row(); + self.dc_v.update_row(); + self.dc_a.update_row(); + } + + if self.has_alpha { + let asrc = &src[aoffset + 3..]; + let mut bc = BoolCoder::new(asrc)?; + let ahdr = br.parse_header(&mut bc)?; + validate!(ahdr.mb_w == hdr.mb_w && ahdr.mb_h == hdr.mb_h); + } + + if hdr.is_golden { + self.shuf.add_golden_frame(buf.clone()); + } + self.shuf.add_frame(buf.clone()); + + Ok((NABufferType::Video(buf), if hdr.is_intra { FrameType::I } else { FrameType::P })) + } + fn reset_mbtype_models(&mut self) { + const DEFAULT_XMITTED_PROBS: [[u8; 20]; 3] = [ + [ 42, 69, 2, 1, 7, 1, 42, 44, 22, 6, 3, 1, 2, 0, 5, 1, 1, 0, 0, 0 ], + [ 8, 229, 1, 1, 8, 0, 0, 0, 0, 0, 2, 1, 1, 0, 0, 0, 1, 1, 0, 0 ], + [ 35, 122, 1, 1, 6, 1, 34, 46, 0, 0, 2, 1, 1, 0, 1, 0, 1, 1, 0, 0 ] + ]; + self.models.prob_xmitted.copy_from_slice(&DEFAULT_XMITTED_PROBS); + } + fn decode_mode_prob_models(&mut self, bc: &mut BoolCoder) -> DecoderResult<()> { + for ctx in 0..3 { + if bc.read_prob(174) { + let idx = bc.read_bits(4) as usize; + for i in 0..20 { + self.models.prob_xmitted[ctx][i ^ 1] = VP56_MODE_VQ[ctx][idx][i]; + } + } + if bc.read_prob(254) { + for set in 0..20 { + if bc.read_prob(205) { + let sign = bc.read_bool(); + let diff = vp_tree!(bc, 171, + vp_tree!(bc, 83, 2, 1), + vp_tree!(bc, 199, + vp_tree!(bc, 140, + vp_tree!(bc, 125, + vp_tree!(bc, 104, 6, 5), + 4 + ), + 3 + ), + bc.read_bits(7) + )) * 4; + validate!(diff < 256); + let diff = diff as u8; + if !sign { + validate!(self.models.prob_xmitted[ctx][set ^ 1] <= 255 - diff); + self.models.prob_xmitted[ctx][set ^ 1] += diff; + } else { + validate!(self.models.prob_xmitted[ctx][set ^ 1] >= diff); + self.models.prob_xmitted[ctx][set ^ 1] -= diff; + } + } + } + } + } + for ctx in 0..3 { + let prob_xmitted = &self.models.prob_xmitted[ctx]; + for mode in 0..10 { + let mdl = &mut self.models.mbtype_models[ctx][mode]; + let mut cnt = [0u32; 10]; + let mut total = 0; + for i in 0..10 { + if i == mode { continue; } + cnt[i] = 100 * (prob_xmitted[i * 2] as u32); + total += cnt[i]; + } + let sum = (prob_xmitted[mode * 2] as u32) + (prob_xmitted[mode * 2 + 1] as u32); + mdl.probs[9] = 255 - rescale_mb_mode_prob(prob_xmitted[mode * 2 + 1] as u32, sum); + + let inter_mv0_weight = (cnt[0] as u32) + (cnt[2] as u32); + let inter_mv1_weight = (cnt[3] as u32) + (cnt[4] as u32); + let gold_mv0_weight = (cnt[5] as u32) + (cnt[6] as u32); + let gold_mv1_weight = (cnt[8] as u32) + (cnt[9] as u32); + let mix_weight = (cnt[1] as u32) + (cnt[7] as u32); + mdl.probs[0] = 1 + rescale_mb_mode_prob(inter_mv0_weight + inter_mv1_weight, total); + mdl.probs[1] = 1 + rescale_mb_mode_prob(inter_mv0_weight, inter_mv0_weight + inter_mv1_weight); + mdl.probs[2] = 1 + rescale_mb_mode_prob(mix_weight, mix_weight + gold_mv0_weight + gold_mv1_weight); + mdl.probs[3] = 1 + rescale_mb_mode_prob(cnt[0] as u32, inter_mv0_weight); + mdl.probs[4] = 1 + rescale_mb_mode_prob(cnt[3] as u32, inter_mv1_weight); + mdl.probs[5] = 1 + rescale_mb_mode_prob(cnt[1], mix_weight); + mdl.probs[6] = 1 + rescale_mb_mode_prob(gold_mv0_weight, gold_mv0_weight + gold_mv1_weight); + mdl.probs[7] = 1 + rescale_mb_mode_prob(cnt[5], gold_mv0_weight); + mdl.probs[8] = 1 + rescale_mb_mode_prob(cnt[8], gold_mv1_weight); + } + } + Ok(()) + } + fn find_mv_pred(&self, ref_id: u8) -> (usize, MV, MV, MV) { + const CAND_POS: [(i8, i8); 12] = [ + (-1, 0), ( 0, -1), + (-1, -1), (-1, 1), + (-2, 0), ( 0, -2), + (-1, -2), (-2, -1), + (-2, 1), (-1, 2), + (-2, -2), (-2, 2) + ]; + + let mut nearest_mv = ZERO_MV; + let mut near_mv = ZERO_MV; + let mut pred_mv = ZERO_MV; + let mut num_mv: usize = 0; + + for (i, (yoff, xoff)) in CAND_POS.iter().enumerate() { + let cx = (self.fstate.mb_x as isize) + (*xoff as isize); + let cy = (self.fstate.mb_y as isize) + (*yoff as isize); + if (cx < 0) || (cy < 0) { + continue; + } + let cx = cx as usize; + let cy = cy as usize; + if (cx >= self.mb_w) || (cy >= self.mb_h) { + continue; + } + let mb_pos = cx + cy * self.mb_w; + let mv = self.mb_info[mb_pos].mv; + if (self.mb_info[mb_pos].mb_type.get_ref_id() != ref_id) || (mv == ZERO_MV) { + continue; + } + if num_mv == 0 { + nearest_mv = mv; + num_mv += 1; + if (self.version > 5) && (i < 2) { + pred_mv = mv; + } + } else if mv != nearest_mv { + near_mv = mv; + num_mv += 1; + break; + } + } + + (num_mv, nearest_mv, near_mv, pred_mv) + } + fn decode_mv(&self, bc: &mut BoolCoder, br: &mut dyn VP56Parser) -> MV { + let x = br.decode_mv(bc, &self.models.mv_models[0]); + let y = br.decode_mv(bc, &self.models.mv_models[1]); + MV{ x, y } + } + fn decode_mb_type(&mut self, bc: &mut BoolCoder, ctx: usize) -> DecoderResult { + let probs = &self.models.mbtype_models[ctx][map_mb_type(self.last_mbt)].probs; + if !bc.read_prob(probs[9]) { + self.last_mbt = vp_tree!( + bc, probs[0], + vp_tree!(bc, probs[1], + vp_tree!(bc, probs[3], VPMBType::InterNoMV, VPMBType::InterMV), + vp_tree!(bc, probs[4], VPMBType::InterNearest, VPMBType::InterNear) + ), + vp_tree!(bc, probs[2], + vp_tree!(bc, probs[5], VPMBType::Intra, VPMBType::InterFourMV), + vp_tree!(bc, probs[6], + vp_tree!(bc, probs[7], VPMBType::GoldenNoMV, VPMBType::GoldenMV), + vp_tree!(bc, probs[8], VPMBType::InterNearest, VPMBType::InterNear) + ) + ) + ); + } + Ok(self.last_mbt) + } + fn decode_mb(&mut self, frm: &mut NASimpleVideoFrame, bc: &mut BoolCoder, cr: &mut CoeffReader, br: &mut dyn VP56Parser, hdr: &VP56Header, alpha: bool) -> DecoderResult<()> { + const FOURMV_SUB_TYPE: [VPMBType; 4] = [ VPMBType::InterNoMV, VPMBType::InterMV, VPMBType::InterNearest, VPMBType::InterNear ]; + + let mb_x = self.fstate.mb_x; + let mb_y = self.fstate.mb_y; + self.coeffs = [[0; 64]; 6]; + let mb_pos = mb_x + mb_y * self.mb_w; + let mut four_mv = [ZERO_MV; 4]; + let mut four_mbt = [VPMBType::Intra; 4]; + + if hdr.interlaced { + let iprob = self.ilace_prob; + let prob = if mb_x == 0 { + iprob + } else if !self.ilace_mb { + iprob + (((256 - (iprob as u16)) >> 1) as u8) + } else { + iprob - (iprob >> 1) + }; + self.ilace_mb = bc.read_prob(prob); + } + + let (num_mv, nearest_mv, near_mv, pred_mv) = if hdr.is_intra { + (0, ZERO_MV, ZERO_MV, ZERO_MV) + } else { self.find_mv_pred(VP_REF_INTER) }; + let mb_type = if hdr.is_intra { + VPMBType::Intra + } else { + self.decode_mb_type(bc, (num_mv + 1) % 3)? + }; + self.mb_info[mb_pos].mb_type = mb_type; + if mb_type.get_ref_id() != VP_REF_GOLDEN { + match mb_type { + VPMBType::Intra | + VPMBType::InterNoMV => { + self.mb_info[mb_pos].mv = ZERO_MV; + }, + VPMBType::InterMV => { + let diff_mv = self.decode_mv(bc, br); + self.mb_info[mb_pos].mv = pred_mv + diff_mv; + }, + VPMBType::InterNearest => { + self.mb_info[mb_pos].mv = nearest_mv; + }, + VPMBType::InterNear => { + self.mb_info[mb_pos].mv = near_mv; + }, + VPMBType::InterFourMV => { + for i in 0..4 { + four_mbt[i] = FOURMV_SUB_TYPE[bc.read_bits(2) as usize]; + } + for i in 0..4 { + match four_mbt[i] { + VPMBType::InterNoMV => {}, + VPMBType::InterMV => { + let diff_mv = self.decode_mv(bc, br); + four_mv[i] = pred_mv + diff_mv; + }, + VPMBType::InterNearest => { + four_mv[i] = nearest_mv; + }, + VPMBType::InterNear => { + four_mv[i] = near_mv; + }, + _ => unreachable!(), + }; + } + self.mb_info[mb_pos].mv = four_mv[3]; + }, + _ => unreachable!(), + }; + } else { + let (_num_mv, nearest_mv, near_mv, pred_mv) = self.find_mv_pred(VP_REF_GOLDEN); + match mb_type { + VPMBType::GoldenNoMV => { + self.mb_info[mb_pos].mv = ZERO_MV; + }, + VPMBType::GoldenMV => { + let diff_mv = self.decode_mv(bc, br); + self.mb_info[mb_pos].mv = pred_mv + diff_mv; + }, + VPMBType::GoldenNearest => { + self.mb_info[mb_pos].mv = nearest_mv; + }, + VPMBType::GoldenNear => { + self.mb_info[mb_pos].mv = near_mv; + }, + _ => unreachable!(), + }; + } + if !mb_type.is_intra() && (mb_type != VPMBType::InterFourMV) { + self.do_mc(br, frm, mb_type, self.mb_info[mb_pos].mv, alpha); + } else if mb_type == VPMBType::InterFourMV { + self.do_fourmv(br, frm, &four_mv, alpha); + } + + for blk_no in 0..4 { + self.fstate.plane = if !alpha { 0 } else { 3 }; + self.fstate.ctx_idx = blk_no >> 1; + self.fstate.top_ctx = self.top_ctx[self.fstate.plane][mb_x * 2 + (blk_no & 1)]; + match cr { + CoeffReader::None => { + br.decode_block(bc, &mut self.coeffs[blk_no], &self.models.coeff_models[0], &self.models.vp6models, &mut self.fstate)?; + }, + CoeffReader::Bool(ref mut bcc) => { + br.decode_block(bcc, &mut self.coeffs[blk_no], &self.models.coeff_models[0], &self.models.vp6models, &mut self.fstate)?; + }, + CoeffReader::Huff(ref mut brc) => { + br.decode_block_huff(brc, &mut self.coeffs[blk_no], &self.models.vp6models, &self.models.vp6huff, &mut self.fstate)?; + }, + }; + self.top_ctx[self.fstate.plane][mb_x * 2 + (blk_no & 1)] = self.fstate.top_ctx; + self.predict_dc(mb_type, mb_pos, blk_no, alpha); + + let bx = mb_x * 2 + (blk_no & 1); + let by = mb_y * 2 + (blk_no >> 1); + let has_ac = self.fstate.last_idx[self.fstate.ctx_idx] > 0; + if mb_type.is_intra() { + if !self.ilace_mb { + if has_ac { + vp_put_block(&mut self.coeffs[blk_no], bx, by, self.fstate.plane, frm); + } else { + vp_put_block_dc(&mut self.coeffs[blk_no], bx, by, self.fstate.plane, frm); + } + } else { + vp_put_block_ilace(&mut self.coeffs[blk_no], bx, by, self.fstate.plane, frm); + } + } else { + if !self.ilace_mb { + if has_ac { + vp_add_block(&mut self.coeffs[blk_no], bx, by, self.fstate.plane, frm); + } else { + vp_add_block_dc(&mut self.coeffs[blk_no], bx, by, self.fstate.plane, frm); + } + } else { + vp_add_block_ilace(&mut self.coeffs[blk_no], bx, by, self.fstate.plane, frm); + } + } + } + if !alpha { + for blk_no in 4..6 { + self.fstate.plane = blk_no - 3; + self.fstate.ctx_idx = blk_no - 2; + self.fstate.top_ctx = self.top_ctx[self.fstate.plane][mb_x]; + match cr { + CoeffReader::None => { + br.decode_block(bc, &mut self.coeffs[blk_no], &self.models.coeff_models[1], &self.models.vp6models, &mut self.fstate)?; + }, + CoeffReader::Bool(ref mut bcc) => { + br.decode_block(bcc, &mut self.coeffs[blk_no], &self.models.coeff_models[1], &self.models.vp6models, &mut self.fstate)?; + }, + CoeffReader::Huff(ref mut brc) => { + br.decode_block_huff(brc, &mut self.coeffs[blk_no], &self.models.vp6models, &self.models.vp6huff, &mut self.fstate)?; + }, + }; + self.top_ctx[self.fstate.plane][mb_x] = self.fstate.top_ctx; + self.predict_dc(mb_type, mb_pos, blk_no, alpha); + + let has_ac = self.fstate.last_idx[self.fstate.ctx_idx] > 0; + if mb_type.is_intra() { + if has_ac { + vp_put_block(&mut self.coeffs[blk_no], mb_x, mb_y, self.fstate.plane, frm); + } else { + vp_put_block_dc(&mut self.coeffs[blk_no], mb_x, mb_y, self.fstate.plane, frm); + } + } else { + if has_ac { + vp_add_block(&mut self.coeffs[blk_no], mb_x, mb_y, self.fstate.plane, frm); + } else { + vp_add_block_dc(&mut self.coeffs[blk_no], mb_x, mb_y, self.fstate.plane, frm); + } + } + } + } + Ok(()) + } + fn do_mc(&mut self, br: &dyn VP56Parser, frm: &mut NASimpleVideoFrame, mb_type: VPMBType, mv: MV, alpha: bool) { + let x = self.fstate.mb_x * 16; + let y = self.fstate.mb_y * 16; + let plane = if !alpha { 0 } else { 3 }; + let src = if mb_type.get_ref_id() == VP_REF_INTER { + self.shuf.get_last().unwrap() + } else { + self.shuf.get_golden().unwrap() + }; + + br.mc_block(frm, self.mc_buf.clone(), src.clone(), plane, x + 0, y + 0, mv, self.loop_thr); + br.mc_block(frm, self.mc_buf.clone(), src.clone(), plane, x + 8, y + 0, mv, self.loop_thr); + br.mc_block(frm, self.mc_buf.clone(), src.clone(), plane, x + 0, y + 8, mv, self.loop_thr); + br.mc_block(frm, self.mc_buf.clone(), src.clone(), plane, x + 8, y + 8, mv, self.loop_thr); + if !alpha { + let x = self.fstate.mb_x * 8; + let y = self.fstate.mb_y * 8; + br.mc_block(frm, self.mc_buf.clone(), src.clone(), 1, x, y, mv, self.loop_thr); + br.mc_block(frm, self.mc_buf.clone(), src.clone(), 2, x, y, mv, self.loop_thr); + } + } + fn do_fourmv(&mut self, br: &dyn VP56Parser, frm: &mut NASimpleVideoFrame, mvs: &[MV; 4], alpha: bool) { + let x = self.fstate.mb_x * 16; + let y = self.fstate.mb_y * 16; + let plane = if !alpha { 0 } else { 3 }; + let src = self.shuf.get_last().unwrap(); + for blk_no in 0..4 { + br.mc_block(frm, self.mc_buf.clone(), src.clone(), + plane, x + (blk_no & 1) * 8, y + (blk_no & 2) * 4, + mvs[blk_no], self.loop_thr); + } + if !alpha { + let x = self.fstate.mb_x * 8; + let y = self.fstate.mb_y * 8; + let sum = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let mv = MV { x: sum.x / 4, y: sum.y / 4 }; + br.mc_block(frm, self.mc_buf.clone(), src.clone(), 1, x, y, mv, self.loop_thr); + br.mc_block(frm, self.mc_buf.clone(), src.clone(), 2, x, y, mv, self.loop_thr); + } + } + fn predict_dc(&mut self, mb_type: VPMBType, mb_pos: usize, blk_no: usize, alpha: bool) { + let mb_x = self.fstate.mb_x; + let is_luma = blk_no < 4; + let (plane, dcs) = if alpha { (0, &mut self.dc_a) } else { + match blk_no { + 4 => (1, &mut self.dc_u), + 5 => (2, &mut self.dc_v), + _ => (0, &mut self.dc_y), + } + }; + let dc_pos = if is_luma { + dcs.xpos + mb_x * 2 + (blk_no & 1) + (blk_no >> 1) * dcs.stride + } else { + dcs.xpos + mb_x + }; + let ref_id = mb_type.get_ref_id(); + let has_left_blk = is_luma && ((blk_no & 1) != 0); + let has_top_blk = is_luma && ((blk_no & 2) != 0); + let mut dc_pred = 0; + let mut count = 0; + if has_left_blk || ((mb_x > 0) && (self.mb_info[mb_pos - 1].mb_type.get_ref_id() == ref_id)) { + dc_pred += dcs.data[dc_pos - 1]; + count += 1; + } + if has_top_blk || ((mb_pos >= self.mb_w) && (self.mb_info[mb_pos - self.mb_w].mb_type.get_ref_id() == ref_id)) { + dc_pred += dcs.data[dc_pos - dcs.stride]; + count += 1; + } + if self.version == 5 { + if (count < 2) && has_left_blk { + dc_pred += dc_pred; + count += 1; + } + if (count < 2) && !has_left_blk && has_top_blk && (mb_x > 0) && (self.mb_info[mb_pos - 1].mb_type.get_ref_id() == ref_id) { + dc_pred += dc_pred; + count += 1; + } + if (count < 2) && mb_pos == 0 && !is_luma { + count += 1; + } + if (count < 2) && !has_left_blk && !has_top_blk && is_luma && (mb_x > 0) && (self.mb_info[mb_pos - 1].mb_type.get_ref_id() == ref_id) { + dc_pred += dcs.data[dc_pos + dcs.stride - 1]; + count += 1; + } + if (count < 2) && blk_no == 2 { + dc_pred += dcs.data[dc_pos - dcs.stride + 1]; + count += 1; + } + if (count < 2) && !has_left_blk && (mb_pos >= self.mb_w) && (self.mb_info[mb_pos - self.mb_w].mb_type.get_ref_id() == ref_id) { + dc_pred += dcs.data[dc_pos - dcs.stride + 1]; + count += 1; + } + if (count < 2) && has_left_blk && (mb_pos > self.mb_w) && (mb_x < self.mb_w - 1) && (self.mb_info[mb_pos - self.mb_w + 1].mb_type.get_ref_id() == ref_id) { + dc_pred += dcs.data[dc_pos - dcs.stride + 1]; + count += 1; + } + } + if count == 0 { + dc_pred = self.last_dc[ref_id as usize][plane]; + } else if count == 2 { + dc_pred /= 2; + } + self.coeffs[blk_no][0] += dc_pred; + self.last_dc[ref_id as usize][plane] = self.coeffs[blk_no][0]; + dcs.data[dc_pos] = self.coeffs[blk_no][0]; + self.coeffs[blk_no][0] = self.coeffs[blk_no][0].wrapping_mul(self.fstate.dc_quant); + } +} + +const VP56_DC_QUANTS: [i16; 64] = [ + 47, 47, 47, 47, 45, 43, 43, 43, + 43, 43, 42, 41, 41, 40, 40, 40, + 40, 35, 35, 35, 35, 33, 33, 33, + 33, 32, 32, 32, 27, 27, 26, 26, + 25, 25, 24, 24, 23, 23, 19, 19, + 19, 19, 18, 18, 17, 16, 16, 16, + 16, 16, 15, 11, 11, 11, 10, 10, + 9, 8, 7, 5, 3, 3, 2, 2 +]; +const VP56_AC_QUANTS: [i16; 64] = [ + 94, 92, 90, 88, 86, 82, 78, 74, + 70, 66, 62, 58, 54, 53, 52, 51, + 50, 49, 48, 47, 46, 45, 44, 43, + 42, 40, 39, 37, 36, 35, 34, 33, + 32, 31, 30, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1 +]; + +const VP56_FILTER_LIMITS: [u8; 64] = [ + 14, 14, 13, 13, 12, 12, 10, 10, + 10, 10, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, + 7, 7, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 4, 4, 4, 4, + 4, 4, 4, 3, 3, 3, 3, 2 +]; + +const VP56_MODE_VQ: [[[u8; 20]; 16]; 3] = [ + [ + [ 9, 15, 32, 25, 7, 19, 9, 21, 1, 12, 14, 12, 3, 18, 14, 23, 3, 10, 0, 4 ], + [ 48, 39, 1, 2, 11, 27, 29, 44, 7, 27, 1, 4, 0, 3, 1, 6, 1, 2, 0, 0 ], + [ 21, 32, 1, 2, 4, 10, 32, 43, 6, 23, 2, 3, 1, 19, 1, 6, 12, 21, 0, 7 ], + [ 69, 83, 0, 0, 0, 2, 10, 29, 3, 12, 0, 1, 0, 3, 0, 3, 2, 2, 0, 0 ], + [ 11, 20, 1, 4, 18, 36, 43, 48, 13, 35, 0, 2, 0, 5, 3, 12, 1, 2, 0, 0 ], + [ 70, 44, 0, 1, 2, 10, 37, 46, 8, 26, 0, 2, 0, 2, 0, 2, 0, 1, 0, 0 ], + [ 8, 15, 0, 1, 8, 21, 74, 53, 22, 42, 0, 1, 0, 2, 0, 3, 1, 2, 0, 0 ], + [ 141, 42, 0, 0, 1, 4, 11, 24, 1, 11, 0, 1, 0, 1, 0, 2, 0, 0, 0, 0 ], + [ 8, 19, 4, 10, 24, 45, 21, 37, 9, 29, 0, 3, 1, 7, 11, 25, 0, 2, 0, 1 ], + [ 46, 42, 0, 1, 2, 10, 54, 51, 10, 30, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0 ], + [ 28, 32, 0, 0, 3, 10, 75, 51, 14, 33, 0, 1, 0, 2, 0, 1, 1, 2, 0, 0 ], + [ 100, 46, 0, 1, 3, 9, 21, 37, 5, 20, 0, 1, 0, 2, 1, 2, 0, 1, 0, 0 ], + [ 27, 29, 0, 1, 9, 25, 53, 51, 12, 34, 0, 1, 0, 3, 1, 5, 0, 2, 0, 0 ], + [ 80, 38, 0, 0, 1, 4, 69, 33, 5, 16, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 ], + [ 16, 20, 0, 0, 2, 8, 104, 49, 15, 33, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0 ], + [ 194, 16, 0, 0, 1, 1, 1, 9, 1, 3, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0 ], + ], [ + [ 41, 22, 1, 0, 1, 31, 0, 0, 0, 0, 0, 1, 1, 7, 0, 1, 98, 25, 4, 10 ], + [ 123, 37, 6, 4, 1, 27, 0, 0, 0, 0, 5, 8, 1, 7, 0, 1, 12, 10, 0, 2 ], + [ 26, 14, 14, 12, 0, 24, 0, 0, 0, 0, 55, 17, 1, 9, 0, 36, 5, 7, 1, 3 ], + [ 209, 5, 0, 0, 0, 27, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 ], + [ 2, 5, 4, 5, 0, 121, 0, 0, 0, 0, 0, 3, 2, 4, 1, 4, 2, 2, 0, 1 ], + [ 175, 5, 0, 1, 0, 48, 0, 0, 0, 0, 0, 2, 0, 1, 0, 2, 0, 1, 0, 0 ], + [ 83, 5, 2, 3, 0, 102, 0, 0, 0, 0, 1, 3, 0, 2, 0, 1, 0, 0, 0, 0 ], + [ 233, 6, 0, 0, 0, 8, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 ], + [ 34, 16, 112, 21, 1, 28, 0, 0, 0, 0, 6, 8, 1, 7, 0, 3, 2, 5, 0, 2 ], + [ 159, 35, 2, 2, 0, 25, 0, 0, 0, 0, 3, 6, 0, 5, 0, 1, 4, 4, 0, 1 ], + [ 75, 39, 5, 7, 2, 48, 0, 0, 0, 0, 3, 11, 2, 16, 1, 4, 7, 10, 0, 2 ], + [ 212, 21, 0, 1, 0, 9, 0, 0, 0, 0, 1, 2, 0, 2, 0, 0, 2, 2, 0, 0 ], + [ 4, 2, 0, 0, 0, 172, 0, 0, 0, 0, 0, 1, 0, 2, 0, 0, 2, 0, 0, 0 ], + [ 187, 22, 1, 1, 0, 17, 0, 0, 0, 0, 3, 6, 0, 4, 0, 1, 4, 4, 0, 1 ], + [ 133, 6, 1, 2, 1, 70, 0, 0, 0, 0, 0, 2, 0, 4, 0, 3, 1, 1, 0, 0 ], + [ 251, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], + ], [ + [ 2, 3, 2, 3, 0, 2, 0, 2, 0, 0, 11, 4, 1, 4, 0, 2, 3, 2, 0, 4 ], + [ 49, 46, 3, 4, 7, 31, 42, 41, 0, 0, 2, 6, 1, 7, 1, 4, 2, 4, 0, 1 ], + [ 26, 25, 1, 1, 2, 10, 67, 39, 0, 0, 1, 1, 0, 14, 0, 2, 31, 26, 1, 6 ], + [ 103, 46, 1, 2, 2, 10, 33, 42, 0, 0, 1, 4, 0, 3, 0, 1, 1, 3, 0, 0 ], + [ 14, 31, 9, 13, 14, 54, 22, 29, 0, 0, 2, 6, 4, 18, 6, 13, 1, 5, 0, 1 ], + [ 85, 39, 0, 0, 1, 9, 69, 40, 0, 0, 0, 1, 0, 3, 0, 1, 2, 3, 0, 0 ], + [ 31, 28, 0, 0, 3, 14, 130, 34, 0, 0, 0, 1, 0, 3, 0, 1, 3, 3, 0, 1 ], + [ 171, 25, 0, 0, 1, 5, 25, 21, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 ], + [ 17, 21, 68, 29, 6, 15, 13, 22, 0, 0, 6, 12, 3, 14, 4, 10, 1, 7, 0, 3 ], + [ 51, 39, 0, 1, 2, 12, 91, 44, 0, 0, 0, 2, 0, 3, 0, 1, 2, 3, 0, 1 ], + [ 81, 25, 0, 0, 2, 9, 106, 26, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0 ], + [ 140, 37, 0, 1, 1, 8, 24, 33, 0, 0, 1, 2, 0, 2, 0, 1, 1, 2, 0, 0 ], + [ 14, 23, 1, 3, 11, 53, 90, 31, 0, 0, 0, 3, 1, 5, 2, 6, 1, 2, 0, 0 ], + [ 123, 29, 0, 0, 1, 7, 57, 30, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0 ], + [ 13, 14, 0, 0, 4, 20, 175, 20, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0 ], + [ 202, 23, 0, 0, 1, 3, 2, 9, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 ], + ] +]; + diff --git a/nihav-duck/src/codecs/vp6.rs b/nihav-duck/src/codecs/vp6.rs new file mode 100644 index 0000000..1cf6a78 --- /dev/null +++ b/nihav-duck/src/codecs/vp6.rs @@ -0,0 +1,967 @@ +use nihav_core::codecs::*; +use nihav_core::io::bitreader::*; +use nihav_core::codecs::blockdsp::edge_emu; +use super::vpcommon::*; +use super::vp56::*; + +const VERSION_VP60: u8 = 6; +//const VERSION_VP61: u8 = 7; +const VERSION_VP62: u8 = 8; + +const VP6_SIMPLE_PROFILE: u8 = 0; +const VP6_ADVANCED_PROFILE: u8 = 3; + +#[derive(Default)] +struct VP6BR { + vpversion: u8, + profile: u8, + interlaced: bool, + do_pm: bool, + loop_mode: u8, + autosel_pm: bool, + var_thresh: u16, + mv_thresh: u8, + bicubic: bool, + filter_alpha: usize, +} + +impl VP6BR { + fn new() -> Self { + Self::default() + } +} + +impl VP56Parser for VP6BR { + fn parse_header(&mut self, bc: &mut BoolCoder) -> DecoderResult { + let mut hdr = VP56Header::default(); +// horrible hack to match VP6 header parsing + let src = bc.src; + let mut br = BitReader::new(src, src.len(), BitReaderMode::BE); + + hdr.is_intra = !br.read_bool()?; + hdr.is_golden = hdr.is_intra; + hdr.quant = br.read(6)? as u8; + hdr.multistream = br.read_bool()?; + if hdr.is_intra { + hdr.version = br.read(5)? as u8; + validate!((hdr.version >= VERSION_VP60) && (hdr.version <= VERSION_VP62)); + hdr.profile = br.read(2)? as u8; + validate!((hdr.profile == VP6_SIMPLE_PROFILE) || (hdr.profile == VP6_ADVANCED_PROFILE)); + hdr.interlaced = br.read_bool()?; + } else { + hdr.version = self.vpversion; + hdr.profile = self.profile; + } + if hdr.multistream || (hdr.profile == VP6_SIMPLE_PROFILE) { + hdr.offset = br.read(16)? as u16; + validate!(hdr.offset > if hdr.is_intra { 6 } else { 2 }); + } + let bytes = br.tell() >> 3; + std::mem::drop(br); + bc.skip_bytes(bytes); + self.loop_mode = 0; + if hdr.is_intra { + hdr.mb_h = bc.read_bits(8) as u8; + hdr.mb_w = bc.read_bits(8) as u8; + hdr.disp_h = bc.read_bits(8) as u8; + hdr.disp_w = bc.read_bits(8) as u8; + validate!((hdr.mb_h > 0) && (hdr.mb_w > 0) && (hdr.disp_w > 0) && (hdr.disp_h > 0)); + validate!((hdr.disp_w <= hdr.mb_w) && (hdr.disp_h <= hdr.mb_h)); + hdr.scale = bc.read_bits(2) as u8; + } else { + hdr.is_golden = bc.read_bool(); + if hdr.profile == VP6_ADVANCED_PROFILE { + self.loop_mode = bc.read_bool() as u8; + if self.loop_mode != 0 { + self.loop_mode += bc.read_bool() as u8; + validate!(self.loop_mode <= 1); + } + if hdr.version == VERSION_VP62 { + self.do_pm = bc.read_bool(); + } + } + } + + if (hdr.profile == VP6_ADVANCED_PROFILE) && (hdr.is_intra || self.do_pm) { + self.autosel_pm = bc.read_bool(); + if self.autosel_pm { + self.var_thresh = bc.read_bits(5) as u16; + if hdr.version != VERSION_VP62 { + self.var_thresh <<= 5; + } + self.mv_thresh = bc.read_bits(3) as u8; + } else { + self.bicubic = bc.read_bool(); + } + if hdr.version == VERSION_VP62 { + self.filter_alpha = bc.read_bits(4) as usize; + } else { + self.filter_alpha = 16; + } + } + + hdr.use_huffman = bc.read_bool(); + + self.vpversion = hdr.version; + self.profile = hdr.profile; + self.interlaced = hdr.interlaced; + Ok(hdr) + } + fn decode_mv(&self, bc: &mut BoolCoder, model: &VP56MVModel) -> i16 { + const LONG_VECTOR_ORDER: [usize; 7] = [ 0, 1, 2, 7, 6, 5, 4 ]; + + let val = if !bc.read_prob(model.nz_prob) { // short vector + vp_tree!(bc, model.tree_probs[0], + vp_tree!(bc, model.tree_probs[1], + vp_tree!(bc, model.tree_probs[2], 0, 1), + vp_tree!(bc, model.tree_probs[3], 2, 3)), + vp_tree!(bc, model.tree_probs[4], + vp_tree!(bc, model.tree_probs[5], 4, 5), + vp_tree!(bc, model.tree_probs[6], 6, 7))) + } else { + let mut raw = 0; + for ord in LONG_VECTOR_ORDER.iter() { + raw |= (bc.read_prob(model.raw_probs[*ord]) as i16) << *ord; + } + if (raw & 0xF0) != 0 { + raw |= (bc.read_prob(model.raw_probs[3]) as i16) << 3; + } else { + raw |= 1 << 3; + } + raw + }; + if (val != 0) && bc.read_prob(model.sign_prob) { + -val + } else { + val + } + } + fn reset_models(&self, models: &mut VP56Models) { + const NZ_PROBS: [u8; 2] = [ 162, 164 ]; + const RAW_PROBS: [[u8; 8]; 2] = [ + [ 247, 210, 135, 68, 138, 220, 239, 246 ], + [ 244, 184, 201, 44, 173, 221, 239, 253 ] + ]; + const TREE_PROBS: [[u8; 7]; 2] = [ + [ 225, 146, 172, 147, 214, 39, 156 ], + [ 204, 170, 119, 235, 140, 230, 228 ] + ]; + const ZERO_RUN_PROBS: [[u8; 14]; 2] = [ + [ 198, 197, 196, 146, 198, 204, 169, 142, 130, 136, 149, 149, 191, 249 ], + [ 135, 201, 181, 154, 98, 117, 132, 126, 146, 169, 184, 240, 246, 254 ] + ]; + + for (i, mdl) in models.mv_models.iter_mut().enumerate() { + mdl.nz_prob = NZ_PROBS[i]; + mdl.sign_prob = 128; + mdl.raw_probs.copy_from_slice(&RAW_PROBS[i]); + mdl.tree_probs.copy_from_slice(&TREE_PROBS[i]); + } + models.vp6models.zero_run_probs.copy_from_slice(&ZERO_RUN_PROBS); + reset_scan(&mut models.vp6models, self.interlaced); + } + fn decode_mv_models(&self, bc: &mut BoolCoder, models: &mut [VP56MVModel; 2]) -> DecoderResult<()> { + const HAS_NZ_PROB: [u8; 2] = [ 237, 231 ]; + const HAS_SIGN_PROB: [u8; 2] = [ 246, 243 ]; + const HAS_TREE_PROB: [[u8; 7]; 2] = [ + [ 253, 253, 254, 254, 254, 254, 254 ], + [ 245, 253, 254, 254, 254, 254, 254 ] + ]; + const HAS_RAW_PROB: [[u8; 8]; 2] = [ + [ 254, 254, 254, 254, 254, 250, 250, 252 ], + [ 254, 254, 254, 254, 254, 251, 251, 254 ] + ]; + + for comp in 0..2 { + if bc.read_prob(HAS_NZ_PROB[comp]) { + models[comp].nz_prob = bc.read_probability(); + } + if bc.read_prob(HAS_SIGN_PROB[comp]) { + models[comp].sign_prob = bc.read_probability(); + } + } + for comp in 0..2 { + for (i, prob) in HAS_TREE_PROB[comp].iter().enumerate() { + if bc.read_prob(*prob) { + models[comp].tree_probs[i] = bc.read_probability(); + } + } + } + for comp in 0..2 { + for (i, prob) in HAS_RAW_PROB[comp].iter().enumerate() { + if bc.read_prob(*prob) { + models[comp].raw_probs[i] = bc.read_probability(); + } + } + } + Ok(()) + } + fn decode_coeff_models(&self, bc: &mut BoolCoder, models: &mut VP56Models, is_intra: bool) -> DecoderResult<()> { + const COEF_PROBS: [[u8; 11]; 2] = [ + [ 146, 255, 181, 207, 232, 243, 238, 251, 244, 250, 249 ], + [ 179, 255, 214, 240, 250, 255, 244, 255, 255, 255, 255 ] + ]; + const SCAN_UPD_PROBS: [u8; 64] = [ + 0, 132, 132, 159, 153, 151, 161, 170, + 164, 162, 136, 110, 103, 114, 129, 118, + 124, 125, 132, 136, 114, 110, 142, 135, + 134, 123, 143, 126, 153, 183, 166, 161, + 171, 180, 179, 164, 203, 218, 225, 217, + 215, 206, 203, 217, 229, 241, 248, 243, + 253, 255, 253, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 + ]; + const ZERO_RUN_PROBS: [[u8; 14]; 2] = [ + [ 219, 246, 238, 249, 232, 239, 249, 255, 248, 253, 239, 244, 241, 248 ], + [ 198, 232, 251, 253, 219, 241, 253, 255, 248, 249, 244, 238, 251, 255 ] + ]; + + let mut def_prob = [128u8; 11]; + for plane in 0..2 { + for i in 0..11 { + if bc.read_prob(COEF_PROBS[plane][i]) { + def_prob[i] = bc.read_probability(); + models.coeff_models[plane].dc_value_probs[i] = def_prob[i]; + } else if is_intra { + models.coeff_models[plane].dc_value_probs[i] = def_prob[i]; + } + } + } + + if bc.read_bool() { + for i in 1..64 { + if bc.read_prob(SCAN_UPD_PROBS[i]) { + models.vp6models.scan_order[i] = bc.read_bits(4) as usize; + } + } + update_scan(&mut models.vp6models); + } else { + reset_scan(&mut models.vp6models, self.interlaced); + } + + for comp in 0..2 { + for i in 0..14 { + if bc.read_prob(ZERO_RUN_PROBS[comp][i]) { + models.vp6models.zero_run_probs[comp][i] = bc.read_probability(); + } + } + } + + for ctype in 0..3 { + for plane in 0..2 { + for group in 0..6 { + for i in 0..11 { + if bc.read_prob(VP6_AC_PROBS[ctype][plane][group][i]) { + def_prob[i] = bc.read_probability(); + models.coeff_models[plane].ac_val_probs[ctype][group][i] = def_prob[i]; + } else if is_intra { + models.coeff_models[plane].ac_val_probs[ctype][group][i] = def_prob[i]; + } + } + } + } + } + for plane in 0..2 { + let mdl = &mut models.coeff_models[plane]; + for i in 0..3 { + for k in 0..5 { + mdl.dc_token_probs[0][i][k] = rescale_prob(mdl.dc_value_probs[k], &VP6_DC_WEIGHTS[k][i], 255); + } + } + } + Ok(()) + } + fn decode_block(&self, bc: &mut BoolCoder, coeffs: &mut [i16; 64], model: &VP56CoeffModel, vp6model: &VP6Models, fstate: &mut FrameState) -> DecoderResult<()> { + let left_ctx = fstate.coeff_cat[fstate.ctx_idx][0] as usize; + let top_ctx = fstate.top_ctx as usize; + let dc_mode = top_ctx + left_ctx; + let token = decode_token_bc(bc, &model.dc_token_probs[0][dc_mode], model.dc_value_probs[5], true, true); + let val = expand_token_bc(bc, &model.dc_value_probs, token, 6); + coeffs[0] = val; + fstate.last_idx[fstate.ctx_idx] = 0; + + let mut idx = 1; + let mut last_val = val; + while idx < 64 { + let ac_band = VP6_IDX_TO_AC_BAND[idx]; + let ac_mode = last_val.abs().min(2) as usize; + let has_nnz = (idx == 1) || (last_val != 0); + let token = decode_token_bc(bc, &model.ac_val_probs[ac_mode][ac_band], model.ac_val_probs[ac_mode][ac_band][5], false, has_nnz); + if token == 42 { break; } + let val = expand_token_bc(bc, &model.ac_val_probs[ac_mode][ac_band], token, 6); + coeffs[vp6model.zigzag[idx]] = val.wrapping_mul(fstate.ac_quant); + idx += 1; + last_val = val; + if val == 0 { + idx += decode_zero_run_bc(bc, &vp6model.zero_run_probs[if idx >= 7 { 1 } else { 0 }]); + validate!(idx <= 64); + } + } + fstate.coeff_cat[fstate.ctx_idx][0] = if coeffs[0] != 0 { 1 } else { 0 }; + fstate.top_ctx = fstate.coeff_cat[fstate.ctx_idx][0]; + fstate.last_idx[fstate.ctx_idx] = idx; + Ok(()) + } + fn decode_block_huff(&self, br: &mut BitReader, coeffs: &mut [i16; 64], vp6model: &VP6Models, model: &VP6HuffModels, fstate: &mut FrameState) -> DecoderResult<()> { + let plane = if (fstate.plane == 0) || (fstate.plane == 3) { 0 } else { 1 }; + let mut last_val; + + if fstate.dc_zero_run[plane] == 0 { + let (val, eob) = decode_token_huff(br, &model.dc_token_tree[plane])?; + if eob { + return Ok(()); + } + last_val = val; + coeffs[0] = val; + if val == 0 { + fstate.dc_zero_run[plane] = decode_eob_run_huff(br)?; + } + } else { + last_val = 0; + fstate.dc_zero_run[plane] -= 1; + } + + if fstate.ac_zero_run[plane] > 0 { + fstate.ac_zero_run[plane] -= 1; + fstate.last_idx[fstate.ctx_idx] = 0; + return Ok(()); + } + + let mut idx = 1; + while idx < 64 { + let ac_band = VP6_IDX_TO_AC_BAND[idx].min(3); + let ac_mode = last_val.abs().min(2) as usize; + let (val, eob) = decode_token_huff(br, &model.ac_token_tree[plane][ac_mode][ac_band])?; + if eob { + if idx == 1 { + fstate.ac_zero_run[plane] = decode_eob_run_huff(br)?; + } + break; + } + coeffs[vp6model.zigzag[idx]] = val.wrapping_mul(fstate.ac_quant); + idx += 1; + last_val = val; + if val == 0 { + idx += decode_zero_run_huff(br, &model.zero_run_tree[if idx >= 7 { 1 } else { 0 }])?; + validate!(idx <= 64); + } + } + + fstate.last_idx[fstate.ctx_idx] = idx; + + Ok(()) + } + fn mc_block(&self, dst: &mut NASimpleVideoFrame, mut mc_buf: NAVideoBufferRef, src: NAVideoBufferRef, plane: usize, x: usize, y: usize, mv: MV, _loop_str: i16) { + let is_luma = (plane != 1) && (plane != 2); + let (sx, sy, mx, my) = if is_luma { + (mv.x / 4, mv.y / 4, mv.x & 3, mv.y & 3) + } else { + (mv.x / 8, mv.y / 8, mv.x & 7, mv.y & 7) + }; + let tmp_blk = mc_buf.get_data_mut().unwrap(); + get_block(tmp_blk, 16, src.clone(), plane, x, y, sx, sy); + // todo filtering + let mut bicubic = self.bicubic; + if is_luma && (self.profile == VP6_ADVANCED_PROFILE) { + if !self.autosel_pm { + bicubic = true; + } else { + let mv_limit = 1 << (self.mv_thresh + 1); + if (mv.x.abs() <= mv_limit) && (mv.y.abs() <= mv_limit) { + let var = calc_variance(&tmp_blk[16 * 2 + 2..], 16); + if var > self.var_thresh { + bicubic = false; + } + } + } + } + let dstride = dst.stride[plane]; + let dbuf = &mut dst.data[dst.offset[plane] + x + y * dstride..]; + if mx == 0 && my == 0 { + let src = &tmp_blk[2 * 16 + 2..]; + for (dline, sline) in dbuf.chunks_mut(dst.stride[plane]).zip(src.chunks(16)).take(8) { + for i in 0..8 { dline[i] = sline[i]; } + } + } else if is_luma && bicubic { + let coeff_h = &VP6_BICUBIC_COEFFS[self.filter_alpha][mx as usize]; + let coeff_v = &VP6_BICUBIC_COEFFS[self.filter_alpha][my as usize]; + mc_bicubic(dbuf, dstride, tmp_blk, 16 * 2 + 2, 16, coeff_h, coeff_v); + } else { + mc_bilinear(dbuf, dstride, tmp_blk, 16 * 2 + 2, 16, mx as u16, my as u16); + } + } +} + +fn update_scan(model: &mut VP6Models) { + let mut idx = 1; + for band in 0..16 { + for i in 1..64 { + if model.scan_order[i] == band { + model.scan[idx] = i; + idx += 1; + } + } + } + for i in 1..64 { + model.zigzag[i] = ZIGZAG[model.scan[i]]; + } +} + +fn reset_scan(model: &mut VP6Models, interlaced: bool) { + const VP6_DEFAULT_SCAN_ORDER: [usize; 64] = [ + 0, 0, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 3, 3, 4, 4, 4, + 5, 5, 5, 5, 6, 6, 7, 7, + 7, 7, 7, 8, 8, 9, 9, 9, + 9, 9, 9, 10, 10, 11, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15 + ]; + const VP6_INTERLACED_SCAN_ORDER: [usize; 64] = [ + 0, 1, 0, 1, 1, 2, 5, 3, + 2, 2, 2, 2, 4, 7, 8, 10, + 9, 7, 5, 4, 2, 3, 5, 6, + 8, 9, 11, 12, 13, 12, 11, 10, + 9, 7, 5, 4, 6, 7, 9, 11, + 12, 12, 13, 13, 14, 12, 11, 9, + 7, 9, 11, 12, 14, 14, 14, 15, + 13, 11, 13, 15, 15, 15, 15, 15 + ]; + + if !interlaced { + model.scan_order.copy_from_slice(&VP6_DEFAULT_SCAN_ORDER); + } else { + model.scan_order.copy_from_slice(&VP6_INTERLACED_SCAN_ORDER); + } + for i in 0..64 { model.scan[i] = i; } + model.zigzag.copy_from_slice(&ZIGZAG); +} + +fn decode_token_bc(bc: &mut BoolCoder, probs: &[u8], prob34: u8, is_dc: bool, has_nnz: bool) -> u8 { + if has_nnz && !bc.read_prob(probs[0]) { + if is_dc || bc.read_prob(probs[1]) { + 0 + } else { + TOKEN_EOB + } + } else { + vp_tree!(bc, probs[2], + 1, + vp_tree!(bc, probs[3], + vp_tree!(bc, probs[4], + 2, + vp_tree!(bc, prob34, 3, 4)), + TOKEN_LARGE)) + } +} + +fn decode_zero_run_bc(bc: &mut BoolCoder, probs: &[u8; 14]) -> usize { + let val = vp_tree!(bc, probs[0], + vp_tree!(bc, probs[1], + vp_tree!(bc, probs[2], 0, 1), + vp_tree!(bc, probs[3], 2, 3)), + vp_tree!(bc, probs[4], + vp_tree!(bc, probs[5], + vp_tree!(bc, probs[6], 4, 5), + vp_tree!(bc, probs[7], 6, 7)), + 42)); + if val != 42 { + val + } else { + let mut nval = 8; + for i in 0..6 { + nval += (bc.read_prob(probs[i + 8]) as usize) << i; + } + nval + } +} + +fn decode_token_huff(br: &mut BitReader, huff: &VP6Huff) -> DecoderResult<(i16, bool)> { + const COEF_ADD_BITS: [u8; 6] = [ 1, 2, 3, 4, 5, 11 ]; + let tok = br.read_huff(huff)?; + match tok { + 0 => Ok((0, false)), + 1 | 2 | 3 | 4 => { + if !br.read_bool()? { + Ok((tok as i16, false)) + } else { + Ok((-(tok as i16), false)) + } + }, + 5 | 6 | 7 | 8 | 9 | 10 => { + let base = (tok - 5) as usize; + let add_bits = br.read(COEF_ADD_BITS[base])? as i16; + let val = VP56_COEF_BASE[base] + add_bits; + if !br.read_bool()? { + Ok((val, false)) + } else { + Ok((-val, false)) + } + }, + _ => Ok((0, true)), + } +} + +fn decode_eob_run_huff(br: &mut BitReader) -> DecoderResult { + let val = br.read(2)?; + match val { + 0 => Ok(0), + 1 => Ok(1), + 2 => { + let val = br.read(2)?; + Ok((val as usize) + 2) + }, + _ => { + if br.read_bool()? { + Ok((br.read(6)? as usize) + 10) + } else { + Ok((br.read(2)? as usize) + 6) + } + }, + } +} + +fn decode_zero_run_huff(br: &mut BitReader, huff: &VP6Huff) -> DecoderResult { + let val = br.read_huff(huff)?; + if val < 8 { + Ok(val as usize) + } else { + Ok((br.read(6)? as usize) + 8) + } +} + + +fn get_block(dst: &mut [u8], dstride: usize, src: NAVideoBufferRef, comp: usize, + dx: usize, dy: usize, mv_x: i16, mv_y: i16) +{ + let (w, h) = src.get_dimensions(comp); + let sx = (dx as isize) + (mv_x as isize); + let sy = (dy as isize) + (mv_y as isize); + + if (sx - 2 < 0) || (sx + 8 + 2 > (w as isize)) || + (sy - 2 < 0) || (sy + 8 + 2 > (h as isize)) { + edge_emu(&src, sx - 2, sy - 2, 8 + 2 + 2, 8 + 2 + 2, + dst, dstride, comp); + } else { + let sstride = src.get_stride(comp); + let soff = src.get_offset(comp); + let sdta = src.get_data(); + let sbuf: &[u8] = sdta.as_slice(); + let saddr = soff + ((sx - 2) as usize) + ((sy - 2) as usize) * sstride; + let src = &sbuf[saddr..]; + for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(12) { + for i in 0..12 { + dline[i] = sline[i]; + } + } + } +} + +fn calc_variance(src: &[u8], stride: usize) -> u16 { + let mut sum = 0; + let mut ssum = 0; + for line in src.chunks(stride * 2).take(8) { + for el in line.iter().take(8).step_by(2) { + let pix = *el as u32; + sum += pix; + ssum += pix * pix; + } + } + ((ssum * 16 - sum * sum) >> 8) as u16 +} + +macro_rules! mc_filter { + (bilinear; $a: expr, $b: expr, $c: expr) => { + ((($a as u16) * (8 - $c) + ($b as u16) * $c + 3) >> 3) as u8 + }; + (bicubic; $src: expr, $off: expr, $step: expr, $coeffs: expr) => { + ((($src[$off - $step] as i32) * ($coeffs[0] as i32) + + ($src[$off] as i32) * ($coeffs[1] as i32) + + ($src[$off + $step] as i32) * ($coeffs[2] as i32) + + ($src[$off + $step * 2] as i32) * ($coeffs[3] as i32) + 64) >> 7).min(255).max(0) as u8 + } +} + +//#[allow(snake_case)] +fn mc_bilinear(dst: &mut [u8], dstride: usize, src: &[u8], mut soff: usize, sstride: usize, mx: u16, my: u16) { + if my == 0 { + for dline in dst.chunks_mut(dstride).take(8) { + for i in 0..8 { + dline[i] = mc_filter!(bilinear; src[soff + i], src[soff + i + 1], mx); + } + soff += sstride; + } + } else if mx == 0 { + for dline in dst.chunks_mut(dstride).take(8) { + for i in 0..8 { + dline[i] = mc_filter!(bilinear; src[soff + i], src[soff + i + sstride], my); + } + soff += sstride; + } + } else { + let mut tmp = [0u8; 8]; + for i in 0..8 { + tmp[i] = mc_filter!(bilinear; src[soff + i], src[soff + i + 1], mx); + } + soff += sstride; + for dline in dst.chunks_mut(dstride).take(8) { + for i in 0..8 { + let cur = mc_filter!(bilinear; src[soff + i], src[soff + i + 1], mx); + dline[i] = mc_filter!(bilinear; tmp[i], cur, my); + tmp[i] = cur; + } + soff += sstride; + } + } +} + +fn mc_bicubic(dst: &mut [u8], dstride: usize, src: &[u8], mut soff: usize, sstride: usize, coeffs_w: &[i16; 4], coeffs_h: &[i16; 4]) { + if coeffs_h[1] == 128 { + for dline in dst.chunks_mut(dstride).take(8) { + for i in 0..8 { + dline[i] = mc_filter!(bicubic; src, soff + i, 1, coeffs_w); + } + soff += sstride; + } + } else if coeffs_w[1] == 128 { // horizontal-only interpolation + for dline in dst.chunks_mut(dstride).take(8) { + for i in 0..8 { + dline[i] = mc_filter!(bicubic; src, soff + i, sstride, coeffs_h); + } + soff += sstride; + } + } else { + let mut buf = [0u8; 16 * 11]; + soff -= sstride; + for dline in buf.chunks_mut(16) { + for i in 0..8 { + dline[i] = mc_filter!(bicubic; src, soff + i, 1, coeffs_w); + } + soff += sstride; + } + let mut soff = 16; + for dline in dst.chunks_mut(dstride).take(8) { + for i in 0..8 { + dline[i] = mc_filter!(bicubic; buf, soff + i, 16, coeffs_h); + } + soff += 16; + } + } +} + +struct VP6Decoder { + dec: VP56Decoder, + info: NACodecInfoRef, + br: VP6BR, + has_alpha: bool, +} + +impl VP6Decoder { + fn new(has_alpha: bool) -> Self { + Self { + dec: VP56Decoder::new(6, has_alpha, true), + info: NACodecInfoRef::default(), + br: VP6BR::new(), + has_alpha, + } + } +} + +impl NADecoder for VP6Decoder { + fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { + if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { + let fmt = if !self.has_alpha { + YUV420_FORMAT + } else { + NAPixelFormaton::new(ColorModel::YUV(YUVSubmodel::YUVJ), + Some(NAPixelChromaton::new(0, 0, false, 8, 0, 0, 1)), + Some(NAPixelChromaton::new(1, 1, false, 8, 0, 1, 1)), + Some(NAPixelChromaton::new(1, 1, false, 8, 0, 2, 1)), + Some(NAPixelChromaton::new(0, 0, false, 8, 0, 3, 1)), + None, + 0, 4) + }; + let myvinfo = NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt); + let myinfo = NACodecTypeInfo::Video(myvinfo.clone()); + self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); + self.dec.init(supp, myvinfo)?; + Ok(()) + } else { + Err(DecoderError::InvalidData) + } + } + fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult { + let src = pkt.get_buffer(); + + let (bufinfo, ftype) = self.dec.decode_frame(supp, src.as_slice(), &mut self.br)?; + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(ftype == FrameType::I); + frm.set_frame_type(ftype); + Ok(frm.into_ref()) + } +} + +pub fn get_decoder_vp6() -> Box { + Box::new(VP6Decoder::new(false)) +} + +pub fn get_decoder_vp6_alpha() -> Box { + Box::new(VP6Decoder::new(true)) +} + +#[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_vp6() { + 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); + + //let file = "assets/Duck/predator2_vp60.avi"; + //let file = "assets/Duck/predator2_vp61.avi"; + //let file = "assets/Duck/vp6_crash.avi"; + let file = "assets/Duck/vp6_interlaced.avi"; + //let file = "assets/Duck/vp6_vid.avi"; + //let file = "assets/Duck/selection_720x576_300kBit_vp60i.avi"; + //let file = "assets/Duck/selection_720x576_300kBit_flipped_vp60i.avi"; + test_file_decoding("avi", file, Some(17), true, false, None/*Some("vp6")*/, &dmx_reg, &dec_reg); +//panic!("end"); + } +} + +const VP6_AC_PROBS: [[[[u8; 11]; 6]; 2]; 3] = [ + [ + [ + [ 227, 246, 230, 247, 244, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 209, 231, 231, 249, 249, 253, 255, 255, 255 ], + [ 255, 255, 225, 242, 241, 251, 253, 255, 255, 255, 255 ], + [ 255, 255, 241, 253, 252, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 248, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ] + ], [ + [ 240, 255, 248, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 240, 253, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ] + ] + ], [ + [ + [ 206, 203, 227, 239, 247, 255, 253, 255, 255, 255, 255 ], + [ 207, 199, 220, 236, 243, 252, 252, 255, 255, 255, 255 ], + [ 212, 219, 230, 243, 244, 253, 252, 255, 255, 255, 255 ], + [ 236, 237, 247, 252, 253, 255, 255, 255, 255, 255, 255 ], + [ 240, 240, 248, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ] + ], [ + [ 230, 233, 249, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 238, 238, 250, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 248, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ] + ] + ], [ + [ + [ 225, 239, 227, 231, 244, 253, 243, 255, 255, 253, 255 ], + [ 232, 234, 224, 228, 242, 249, 242, 252, 251, 251, 255 ], + [ 235, 249, 238, 240, 251, 255, 249, 255, 253, 253, 255 ], + [ 249, 253, 251, 250, 255, 255, 255, 255, 255, 255, 255 ], + [ 251, 250, 249, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ] + ], [ + [ 243, 244, 250, 250, 255, 255, 255, 255, 255, 255, 255 ], + [ 249, 248, 250, 253, 255, 255, 255, 255, 255, 255, 255 ], + [ 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ], + [ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 ] + ] + ] +]; + +const VP6_DC_WEIGHTS: [[[i16; 2]; 3]; 5] = [ + [ [ 122, 133 ], [ 133, 51 ], [ 142, -16 ] ], + [ [ 0, 1 ], [ 0, 1 ], [ 0, 1 ] ], + [ [ 78, 171 ], [ 169, 71 ], [ 221, -30 ] ], + [ [ 139, 117 ], [ 214, 44 ], [ 246, -3 ] ], + [ [ 168, 79 ], [ 210, 38 ], [ 203, 17 ] ] +]; + +const VP6_IDX_TO_AC_BAND: [usize; 64] = [ + 0, 0, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5 +]; + +const VP6_BICUBIC_COEFFS: [[[i16; 4]; 8]; 17] = [ + [ + [ 0, 128, 0, 0 ], + [ -3, 122, 9, 0 ], + [ -4, 109, 24, -1 ], + [ -5, 91, 45, -3 ], + [ -4, 68, 68, -4 ], + [ -3, 45, 91, -5 ], + [ -1, 24, 109, -4 ], + [ 0, 9, 122, -3 ] + ], [ + [ 0, 128, 0, 0 ], + [ -4, 124, 9, -1 ], + [ -5, 110, 25, -2 ], + [ -6, 91, 46, -3 ], + [ -5, 69, 69, -5 ], + [ -3, 46, 91, -6 ], + [ -2, 25, 110, -5 ], + [ -1, 9, 124, -4 ] + ], [ + [ 0, 128, 0, 0 ], + [ -4, 123, 10, -1 ], + [ -6, 110, 26, -2 ], + [ -7, 92, 47, -4 ], + [ -6, 70, 70, -6 ], + [ -4, 47, 92, -7 ], + [ -2, 26, 110, -6 ], + [ -1, 10, 123, -4 ] + ], [ + [ 0, 128, 0, 0 ], + [ -5, 124, 10, -1 ], + [ -7, 110, 27, -2 ], + [ -7, 91, 48, -4 ], + [ -6, 70, 70, -6 ], + [ -4, 48, 92, -8 ], + [ -2, 27, 110, -7 ], + [ -1, 10, 124, -5 ] + ], [ + [ 0, 128, 0, 0 ], + [ -6, 124, 11, -1 ], + [ -8, 111, 28, -3 ], + [ -8, 92, 49, -5 ], + [ -7, 71, 71, -7 ], + [ -5, 49, 92, -8 ], + [ -3, 28, 111, -8 ], + [ -1, 11, 124, -6 ] + ], [ + [ 0, 128, 0, 0 ], + [ -6, 123, 12, -1 ], + [ -9, 111, 29, -3 ], + [ -9, 93, 50, -6 ], + [ -8, 72, 72, -8 ], + [ -6, 50, 93, -9 ], + [ -3, 29, 111, -9 ], + [ -1, 12, 123, -6 ] + ], [ + [ 0, 128, 0, 0 ], + [ -7, 124, 12, -1 ], + [ -10, 111, 30, -3 ], + [ -10, 93, 51, -6 ], + [ -9, 73, 73, -9 ], + [ -6, 51, 93, -10 ], + [ -3, 30, 111, -10 ], + [ -1, 12, 124, -7 ] + ], [ + [ 0, 128, 0, 0 ], + [ -7, 123, 13, -1 ], + [ -11, 112, 31, -4 ], + [ -11, 94, 52, -7 ], + [ -10, 74, 74, -10 ], + [ -7, 52, 94, -11 ], + [ -4, 31, 112, -11 ], + [ -1, 13, 123, -7 ] + ], [ + [ 0, 128, 0, 0 ], + [ -8, 124, 13, -1 ], + [ -12, 112, 32, -4 ], + [ -12, 94, 53, -7 ], + [ -10, 74, 74, -10 ], + [ -7, 53, 94, -12 ], + [ -4, 32, 112, -12 ], + [ -1, 13, 124, -8 ] + ], [ + [ 0, 128, 0, 0 ], + [ -9, 124, 14, -1 ], + [ -13, 112, 33, -4 ], + [ -13, 95, 54, -8 ], + [ -11, 75, 75, -11 ], + [ -8, 54, 95, -13 ], + [ -4, 33, 112, -13 ], + [ -1, 14, 124, -9 ] + ], [ + [ 0, 128, 0, 0 ], + [ -9, 123, 15, -1 ], + [ -14, 113, 34, -5 ], + [ -14, 95, 55, -8 ], + [ -12, 76, 76, -12 ], + [ -8, 55, 95, -14 ], + [ -5, 34, 112, -13 ], + [ -1, 15, 123, -9 ] + ], [ + [ 0, 128, 0, 0 ], + [ -10, 124, 15, -1 ], + [ -14, 113, 34, -5 ], + [ -15, 96, 56, -9 ], + [ -13, 77, 77, -13 ], + [ -9, 56, 96, -15 ], + [ -5, 34, 113, -14 ], + [ -1, 15, 124, -10 ] + ], [ + [ 0, 128, 0, 0 ], + [ -10, 123, 16, -1 ], + [ -15, 113, 35, -5 ], + [ -16, 98, 56, -10 ], + [ -14, 78, 78, -14 ], + [ -10, 56, 98, -16 ], + [ -5, 35, 113, -15 ], + [ -1, 16, 123, -10 ] + ], [ + [ 0, 128, 0, 0 ], + [ -11, 124, 17, -2 ], + [ -16, 113, 36, -5 ], + [ -17, 98, 57, -10 ], + [ -14, 78, 78, -14 ], + [ -10, 57, 98, -17 ], + [ -5, 36, 113, -16 ], + [ -2, 17, 124, -11 ] + ], [ + [ 0, 128, 0, 0 ], + [ -12, 125, 17, -2 ], + [ -17, 114, 37, -6 ], + [ -18, 99, 58, -11 ], + [ -15, 79, 79, -15 ], + [ -11, 58, 99, -18 ], + [ -6, 37, 114, -17 ], + [ -2, 17, 125, -12 ] + ], [ + [ 0, 128, 0, 0 ], + [ -12, 124, 18, -2 ], + [ -18, 114, 38, -6 ], + [ -19, 99, 59, -11 ], + [ -16, 80, 80, -16 ], + [ -11, 59, 99, -19 ], + [ -6, 38, 114, -18 ], + [ -2, 18, 124, -12 ] + ], [ + [ 0, 128, 0, 0 ], + [ -4, 118, 16, -2 ], + [ -7, 106, 34, -5 ], + [ -8, 90, 53, -7 ], + [ -8, 72, 72, -8 ], + [ -7, 53, 90, -8 ], + [ -5, 34, 106, -7 ], + [ -2, 16, 118, -4 ] + ] +]; diff --git a/nihav-duck/src/codecs/vpcommon.rs b/nihav-duck/src/codecs/vpcommon.rs index 05b07d1..0392a38 100644 --- a/nihav-duck/src/codecs/vpcommon.rs +++ b/nihav-duck/src/codecs/vpcommon.rs @@ -16,6 +16,9 @@ pub enum VPMBType { GoldenNear, } +pub const VP_REF_INTER: u8 = 1; +pub const VP_REF_GOLDEN: u8 = 2; + #[allow(dead_code)] impl VPMBType { pub fn is_intra(self) -> bool { self == VPMBType::Intra } @@ -26,8 +29,8 @@ impl VPMBType { VPMBType::InterMV | VPMBType::InterNearest | VPMBType::InterNear | - VPMBType::InterFourMV => 1, - _ => 2, + VPMBType::InterFourMV => VP_REF_INTER, + _ => VP_REF_GOLDEN, } } } @@ -67,6 +70,103 @@ impl VPShuffler { } } +#[allow(dead_code)] +pub struct BoolCoder<'a> { + pub src: &'a [u8], + pos: usize, + value: u32, + range: u32, + bits: i32, +} + +#[allow(dead_code)] +impl<'a> BoolCoder<'a> { + pub fn new(src: &'a [u8]) -> DecoderResult { + if src.len() < 3 { return Err(DecoderError::ShortData); } + let value = ((src[0] as u32) << 24) | ((src[1] as u32) << 16) | ((src[2] as u32) << 8) | (src[3] as u32); + Ok(Self { src, pos: 4, value, range: 255, bits: 8 }) + } + pub fn read_bool(&mut self) -> bool { + self.read_prob(128) + } + pub fn read_prob(&mut self, prob: u8) -> bool { + self.renorm(); + let split = 1 + (((self.range - 1) * (prob as u32)) >> 8); + let bit; + if self.value < (split << 24) { + self.range = split; + bit = false; + } else { + self.range -= split; + self.value -= split << 24; + bit = true; + } + bit + } + pub fn read_bits(&mut self, bits: u8) -> u32 { + let mut val = 0u32; + for _ in 0..bits { + val = (val << 1) | (self.read_prob(128) as u32); + } + val + } + pub fn read_probability(&mut self) -> u8 { + let val = self.read_bits(7) as u8; + if val == 0 { + 1 + } else { + val << 1 + } + } + fn renorm(&mut self) { + let shift = self.range.leading_zeros() & 7; + self.range <<= shift; + self.value <<= shift; + self.bits -= shift as i32; + if (self.bits <= 0) && (self.pos < self.src.len()) { + self.value |= (self.src[self.pos] as u32) << (-self.bits as u8); + self.pos += 1; + self.bits += 8; + } +/* while self.range < 0x80 { + self.range <<= 1; + self.value <<= 1; + self.bits -= 1; + if (self.bits <= 0) && (self.pos < self.src.len()) { + self.value |= self.src[self.pos] as u32; + self.pos += 1; + self.bits = 8; + } + }*/ + } + pub fn skip_bytes(&mut self, nbytes: usize) { + for _ in 0..nbytes { + self.value <<= 8; + if self.pos < self.src.len() { + self.value |= self.src[self.pos] as u32; + self.pos += 1; + } + } + } +} + +#[allow(dead_code)] +pub fn rescale_prob(prob: u8, weights: &[i16; 2], maxval: i32) -> u8 { + ((((prob as i32) * (weights[0] as i32) + 128) >> 8) + (weights[1] as i32)).min(maxval).max(1) as u8 +} + +#[macro_export] +macro_rules! vp_tree { + ($bc: expr, $prob: expr, $node1: expr, $node2: expr) => { + if !$bc.read_prob($prob) { + $node1 + } else { + $node2 + } + }; + ($leaf: expr) => { $leaf } +} + const C1S7: i32 = 64277; const C2S6: i32 = 60547; const C3S5: i32 = 54491; @@ -153,6 +253,17 @@ pub fn vp_put_block(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, } } +pub fn vp_put_block_ilace(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame) { + vp_idct(coeffs); + let mut off = frm.offset[plane] + bx * 8 + ((by & !1) * 8 + (by & 1)) * frm.stride[plane]; + for y in 0..8 { + for x in 0..8 { + frm.data[off + x] = (coeffs[x + y * 8] + 128).min(255).max(0) as u8; + } + off += frm.stride[plane] * 2; + } +} + pub fn vp_put_block_dc(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame) { vp_idct_dc(coeffs); let dc = (coeffs[0] + 128).min(255).max(0) as u8; @@ -176,6 +287,17 @@ pub fn vp_add_block(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, } } +pub fn vp_add_block_ilace(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame) { + vp_idct(coeffs); + let mut off = frm.offset[plane] + bx * 8 + ((by & !1) * 8 + (by & 1)) * frm.stride[plane]; + for y in 0..8 { + for x in 0..8 { + frm.data[off + x] = (coeffs[x + y * 8] + (frm.data[off + x] as i16)).min(255).max(0) as u8; + } + off += frm.stride[plane] * 2; + } +} + pub fn vp_add_block_dc(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame) { vp_idct_dc(coeffs); let dc = coeffs[0]; @@ -249,3 +371,55 @@ pub fn vp_copy_block(dst: &mut NASimpleVideoFrame, src: NAVideoBufferRef let dyoff = (pre as i16) - (dy as i16); copy_block(dst, mc_buf, comp, dx, dy, dxoff, dyoff, 8, 8, preborder, postborder, 0/* mode*/, interp); } + +fn vp3_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { dst[didx + x] = src[sidx + x]; } + didx += dstride; + sidx += sstride; + } +} + +fn vp3_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + 1] as u16)) >> 1) as u8; } + didx += dstride; + sidx += sstride; + } +} + +fn vp3_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16)) >> 1) as u8; } + didx += dstride; + sidx += sstride; + } +} + +fn vp3_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { + dst[didx + x] = (((src[sidx + x] as u16) + + (src[sidx + x + 1] as u16) + + (src[sidx + x + sstride] as u16) + + (src[sidx + x + sstride + 1] as u16)) >> 2) as u8; + } + didx += dstride; + sidx += sstride; + } +} + +pub const VP3_INTERP_FUNCS: &[blockdsp::BlkInterpFunc] = &[ vp3_interp00, vp3_interp01, vp3_interp10, vp3_interp11 ]; + -- 2.30.2