[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"]
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;
#[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 },
};
}
-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<u8>, 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);
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();
--- /dev/null
+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<VP56Header> {
+ 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<u8>, mc_buf: NAVideoBufferRef<u8>, src: NAVideoBufferRef<u8>, 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<NAFrameRef> {
+ 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<NADecoder> {
+ 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] ]
+ ]
+ ]
+];
--- /dev/null
+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<u8>;
+}
+
+impl<'a> ReadHuff for BitReader<'a> {
+ fn read_huff(&mut self, huff: &VP6Huff) -> DecoderResult<u8> {
+ 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<VP56Header>;
+ 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<u8>, mc_buf: NAVideoBufferRef<u8>, src: NAVideoBufferRef<u8>, 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<T: Copy> {
+ pub height: usize,
+ pub stride: usize,
+ pub xpos: usize,
+ pub data: Vec<T>,
+ pub default: T,
+}
+
+impl<T:Copy> GenericCache<T> {
+ 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<MBInfo>,
+ fstate: FrameState,
+ dc_y: GenericCache<i16>,
+ dc_u: GenericCache<i16>,
+ dc_v: GenericCache<i16>,
+ dc_a: GenericCache<i16>,
+ last_dc: [[i16; 4]; 3],
+ top_ctx: [Vec<u8>; 4],
+
+ mc_buf: NAVideoBufferRef<u8>,
+}
+
+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<VPMBType> {
+ 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<u8>, 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<u8>, 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<u8>, 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 ],
+ ]
+];
+
--- /dev/null
+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<VP56Header> {
+ 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<u8>, mut mc_buf: NAVideoBufferRef<u8>, src: NAVideoBufferRef<u8>, 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<usize> {
+ 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<usize> {
+ 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<u8>, 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<NAFrameRef> {
+ 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<NADecoder> {
+ Box::new(VP6Decoder::new(false))
+}
+
+pub fn get_decoder_vp6_alpha() -> Box<NADecoder> {
+ 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 ]
+ ]
+];
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 }
VPMBType::InterMV |
VPMBType::InterNearest |
VPMBType::InterNear |
- VPMBType::InterFourMV => 1,
- _ => 2,
+ VPMBType::InterFourMV => VP_REF_INTER,
+ _ => VP_REF_GOLDEN,
}
}
}
}
}
+#[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<Self> {
+ 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;
}
}
+pub fn vp_put_block_ilace(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame<u8>) {
+ 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<u8>) {
vp_idct_dc(coeffs);
let dc = (coeffs[0] + 128).min(255).max(0) as u8;
}
}
+pub fn vp_add_block_ilace(coeffs: &mut [i16; 64], bx: usize, by: usize, plane: usize, frm: &mut NASimpleVideoFrame<u8>) {
+ 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<u8>) {
vp_idct_dc(coeffs);
let dc = coeffs[0];
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 ];
+