vp7: split out tables
[nihav.git] / nihav-duck / src / codecs / vp7.rs
index 3079fd079dd813d02d26f5ddff1b7b436e091069..2252e0d9d121f7c7c17480dad9affa0c3c0b536f 100644 (file)
@@ -1,82 +1,13 @@
 use nihav_core::codecs::*;
 use nihav_core::io::byteio::*;
-use nihav_core::data::GenericCache;
+use nihav_codec_support::codecs::{MV, ZERO_MV};
 use super::vpcommon::*;
+use super::vp78::*;
+use super::vp78data::*;
+use super::vp78dsp::*;
 use super::vp7data::*;
 use super::vp7dsp::*;
 
-enum VPTreeDef<T: Copy> {
-    Index(u8),
-    Value(T),
-}
-
-trait VPTreeReader {
-    fn read_tree<T:Copy>(&mut self, tree_def: &[VPTreeDef<T>], tree_prob: &[u8]) -> T;
-}
-
-impl<'a> VPTreeReader for BoolCoder<'a> {
-    fn read_tree<T:Copy>(&mut self, tree_def: &[VPTreeDef<T>], tree_prob: &[u8]) -> T {
-        let mut idx = 0;
-
-        loop {
-            let bit = self.read_prob(tree_prob[idx >> 1]);
-            match tree_def[idx + (bit as usize)] {
-                VPTreeDef::Value(v) => return v,
-                VPTreeDef::Index(ix) => { idx = ix as usize; },
-            };
-        }
-    }
-}
-
-#[repr(u8)]
-#[derive(Clone,Copy,PartialEq,Debug)]
-enum PredMode {
-    DCPred,
-    HPred,
-    VPred,
-    TMPred,
-    BPred,
-
-    //sub-block prediction modes
-    LDPred,
-    RDPred,
-    VRPred,
-    VLPred,
-    HDPred,
-    HUPred,
-
-    Inter,
-}
-
-impl Default for PredMode {
-    fn default() -> Self { PredMode::DCPred }
-}
-
-impl PredMode {
-    fn to_b_mode(self) -> Self {
-        if self == PredMode::DCPred {
-            self
-        } else {
-            PredMode::TMPred
-        }
-    }
-    fn to_b_index(self) -> usize {
-        match self {
-            PredMode::DCPred    => 0,
-            PredMode::TMPred    => 1,
-            PredMode::VPred     => 2,
-            PredMode::HPred     => 3,
-            PredMode::LDPred    => 4,
-            PredMode::RDPred    => 5,
-            PredMode::VRPred    => 6,
-            PredMode::VLPred    => 7,
-            PredMode::HDPred    => 8,
-            PredMode::HUPred    => 9,
-            _ => unreachable!(),
-        }
-    }
-}
-
 const PITCH_MODE_NORMAL: u8 = 0;
 const PITCH_MODE_FOUR:   u8 = 1;
 const PITCH_MODE_X2:     u8 = 2;
@@ -89,62 +20,13 @@ struct MBFeature {
     def_val:        [u8; 4],
 }
 
-#[derive(Clone,Copy,PartialEq)]
-enum DCTToken {
-    Zero,
-    One,
-    Two,
-    Three,
-    Four,
-    Cat1,
-    Cat2,
-    Cat3,
-    Cat4,
-    Cat5,
-    Cat6,
-    EOB,
-}
-
-fn expand_token(bc: &mut BoolCoder, token: DCTToken) -> i16 {
-    let cat;
-    match token {
-        DCTToken::Zero  => return 0,
-        DCTToken::One   => return if bc.read_bool() { -1 } else { 1 },
-        DCTToken::Two   => return if bc.read_bool() { -2 } else { 2 },
-        DCTToken::Three => return if bc.read_bool() { -3 } else { 3 },
-        DCTToken::Four  => return if bc.read_bool() { -4 } else { 4 },
-        DCTToken::Cat1  => cat = 0,
-        DCTToken::Cat2  => cat = 1,
-        DCTToken::Cat3  => cat = 2,
-        DCTToken::Cat4  => cat = 3,
-        DCTToken::Cat5  => cat = 4,
-        DCTToken::Cat6  => cat = 5,
-        _ => unreachable!(),
-    };
-    let mut add = 0i16;
-    let add_probs = &VP56_COEF_ADD_PROBS[cat];
-    for prob in add_probs.iter() {
-        if *prob == 128 { break; }
-        add                                 = (add << 1) | (bc.read_prob(*prob) as i16);
-    }
-    let sign                                = bc.read_bool();
-    let level = VP56_COEF_BASE[cat] + add;
-    if !sign {
-        level
-    } else {
-        -level
-    }
-}
-
 struct SBParams<'a> {
     coef_probs: &'a [[[[u8; 11]; 3]; 8]; 4],
     scan:       &'a [usize; 16],
     qmat:       &'a [i16; 16],
 }
 
-fn decode_subblock<'a>(bc: &mut BoolCoder, coeffs: &mut [i16; 16], ctype: usize, pctx: u8, sbparams: &SBParams) -> u8 {
-    const COEF_BANDS: [usize; 16] = [ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7 ];
-
+fn decode_subblock(bc: &mut BoolCoder, coeffs: &mut [i16; 16], ctype: usize, pctx: u8, sbparams: &SBParams) -> u8 {
     let mut has_nz = 0;
     let start = if ctype != 0 { 0 } else { 1 };
     *coeffs = [0; 16];
@@ -217,25 +99,7 @@ impl DecoderState {
     }
 }
 
-#[derive(Clone,Copy,Debug,PartialEq)]
-enum MVSplitMode {
-    TopBottom,
-    LeftRight,
-    Quarters,
-    Sixteenths,
-}
-
-#[derive(Clone,Copy,Debug,PartialEq)]
-enum SubMVRef {
-    Left,
-    Above,
-    New,
-    Zero,
-}
-
 fn decode_mv_component(bc: &mut BoolCoder, probs: &[u8; 17]) -> i16 {
-    const LONG_VECTOR_ORDER: [usize; 7] = [ 0, 1, 2, 7, 6, 5, 4 ];
-
     let val = if !bc.read_prob(probs[0]) {
                                      bc.read_tree(SMALL_MV_TREE, &probs[2..9])
         } else {
@@ -258,54 +122,6 @@ fn decode_mv_component(bc: &mut BoolCoder, probs: &[u8; 17]) -> i16 {
     }
 }
 
-struct PredCache {
-    y_pred:         GenericCache<u8>,
-    u_pred:         GenericCache<u8>,
-    v_pred:         GenericCache<u8>,
-    y2_pred:        GenericCache<u8>,
-    y_pred_left:    [u8; 4],
-    u_pred_left:    [u8; 2],
-    v_pred_left:    [u8; 2],
-    y2_pred_left:   u8,
-}
-
-impl PredCache {
-    fn new() -> Self {
-        Self {
-            y_pred:         GenericCache::new(1, 1, 0),
-            u_pred:         GenericCache::new(1, 1, 0),
-            v_pred:         GenericCache::new(1, 1, 0),
-            y2_pred:        GenericCache::new(1, 1, 0),
-            y_pred_left:    [0; 4],
-            u_pred_left:    [0; 2],
-            v_pred_left:    [0; 2],
-            y2_pred_left:   0,
-        }
-    }
-    fn resize(&mut self, mb_w: usize) {
-        self.y_pred     = GenericCache::new(4, mb_w * 4 + 1, 0);
-        self.u_pred     = GenericCache::new(2, mb_w * 2 + 1, 0);
-        self.v_pred     = GenericCache::new(2, mb_w * 2 + 1, 0);
-        self.y2_pred    = GenericCache::new(1, mb_w     + 1, 0);
-    }
-    fn reset(&mut self) {
-        self.y_pred.reset();
-        self.u_pred.reset();
-        self.v_pred.reset();
-        self.y2_pred.reset();
-        self.y_pred_left = [0; 4];
-        self.u_pred_left = [0; 2];
-        self.v_pred_left = [0; 2];
-        self.y2_pred_left = 0;
-    }
-    fn update_row(&mut self) {
-        self.y_pred.update_row();
-        self.u_pred.update_row();
-        self.v_pred.update_row();
-        self.y2_pred.update_row();
-    }
-}
-
 struct VP7Decoder {
     info:           NACodecInfoRef,
 
@@ -620,15 +436,6 @@ impl VP7Decoder {
         }
     }
     fn find_mv_pred(&self, mb_x: usize, mb_y: usize) -> ([u8; 4], MV, MV, MV) {
-        const CAND_POS: [(i8, i8, u8, u8); 12] = [
-            (-1,  0, 8, 12), ( 0, -1, 8,  3),
-            (-1, -1, 2, 15), (-1,  1, 2, 12),
-            (-2,  0, 2, 12), ( 0, -2, 2,  3),
-            (-1, -2, 1, 15), (-2, -1, 1, 15),
-            (-2,  1, 1, 12), (-1,  2, 1, 12),
-            (-2, -2, 1, 15), (-2,  2, 1, 12)
-        ];
-
         let mut nearest_mv = ZERO_MV;
         let mut near_mv = ZERO_MV;
 
@@ -1009,12 +816,12 @@ impl VP7Decoder {
 
             if pitch_smode == 0 {
                 mc_block8x8(dst, uoff, ustride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe.clone(), 1, &mut mc_buf);
-                mc_block8x8(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe.clone(), 2, &mut mc_buf);
+                mc_block8x8(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y, refframe,         2, &mut mc_buf);
             } else {
                 mc_block_special(dst, uoff, ustride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y,
                                  refframe.clone(), 1, &mut mc_buf, 8, pitch_smode);
                 mc_block_special(dst, voff, vstride, mb_x * 8, mb_y * 8, chroma_mv.x, chroma_mv.y,
-                                 refframe.clone(), 2, &mut mc_buf, 8, pitch_smode);
+                                 refframe,         2, &mut mc_buf, 8, pitch_smode);
             }
         } else {
             for y in 0..2 {
@@ -1057,30 +864,17 @@ impl VP7Decoder {
         self.add_residue(dframe, mb_x, mb_y, true, pitch_dmode);
     }
     fn loop_filter_mb(&mut self, dframe: &mut NASimpleVideoFrame<u8>, mb_x: usize, mb_y: usize, loop_str: u8) {
-        const HIGH_EDGE_VAR_THR: [[u8; 64]; 2] = [
-          [
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-            1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
-            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
-          ], [
-            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-            1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
-            2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
-          ]];
-
-        let edge_thr    = (loop_str as i16) + 2;
-        let luma_thr    = loop_str as i16;
-        let chroma_thr  = (loop_str as i16) * 2;
+        let edge_thr    = i16::from(loop_str) + 2;
+        let luma_thr    = i16::from(loop_str);
+        let chroma_thr  = i16::from(loop_str) * 2;
         let inner_thr   = if self.dstate.loop_sharpness == 0 {
-                loop_str as i16
+                i16::from(loop_str)
             } else {
-                let bound1 = (9 - self.dstate.loop_sharpness) as i16;
+                let bound1 = i16::from(9 - self.dstate.loop_sharpness);
                 let shift = (self.dstate.loop_sharpness + 3) >> 2;
-                ((loop_str as i16) >> shift).min(bound1)
+                (i16::from(loop_str) >> shift).min(bound1)
             };
-        let hev_thr     = HIGH_EDGE_VAR_THR[if self.dstate.is_intra { 1 } else { 0 }][loop_str as usize] as i16;
+        let hev_thr     = i16::from(HIGH_EDGE_VAR_THR[if self.dstate.is_intra { 1 } else { 0 }][loop_str as usize]);
 
         let ystride = dframe.stride[0];
         let ustride = dframe.stride[1];
@@ -1125,7 +919,7 @@ impl NADecoder for VP7Decoder {
         if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
             let fmt = YUV420_FORMAT;
             let myvinfo = NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, fmt);
-            let myinfo = NACodecTypeInfo::Video(myvinfo.clone());
+            let myinfo = NACodecTypeInfo::Video(myvinfo);
             self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
 
             supp.pool_u8.set_dec_bufs(4);
@@ -1136,6 +930,7 @@ impl NADecoder for VP7Decoder {
             Err(DecoderError::InvalidData)
         }
     }
+    #[allow(clippy::cognitive_complexity)]
     fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
         let src = pkt.get_buffer();
 
@@ -1422,7 +1217,13 @@ impl NADecoder for VP7Decoder {
     }
 }
 
-pub fn get_decoder() -> Box<NADecoder + Send> {
+impl NAOptionHandler for VP7Decoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
     Box::new(VP7Decoder::new())
 }
 
@@ -1430,112 +1231,32 @@ pub fn get_decoder() -> Box<NADecoder + Send> {
 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;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::duck_register_all_decoders;
+    use nihav_commonfmt::generic_register_all_demuxers;
 
     #[test]
     fn test_vp7() {
         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/potter-40.vp7";
-        //let file = "assets/Duck/potter-500.vp7";
-        //let file = "assets/Duck/starsky-700.vp7";
-        //let file = "assets/Duck/taking-700.vp7";
-        //let file = "assets/Duck/troy-700.vp7";
-        let file = "assets/Duck/interlaced_blit_pitch.avi";
-        //let file = "assets/Duck/vp7.avi";
-        test_file_decoding("avi", file, Some(12), true, false, None/*Some("vp7")*/, &dmx_reg, &dec_reg);
+        duck_register_all_decoders(&mut dec_reg);
+
+        // sample from https://trac.ffmpeg.org/ticket/5580
+        test_decoding("avi", "vp7", "assets/Duck/interlaced_blit_pitch.avi", Some(12), &dmx_reg,
+                      &dec_reg, ExpectedTestResult::MD5Frames(vec![
+                            [0xb79fb6f8, 0xed51ac9e, 0x9e423456, 0xc0918e7f],
+                            [0xbf8d1274, 0x83515e15, 0x8c0887de, 0xfbfd05d3],
+                            [0x8ad00466, 0x80b6cbfb, 0x54de408e, 0x9efbc05e],
+                            [0x144122c5, 0x6897b553, 0x93474d29, 0x1a1274ec],
+                            [0x06ff5d07, 0x55825d38, 0x072b0a78, 0xfcb5020f],
+                            [0xfd01591b, 0xc42113e7, 0xc5a5550f, 0xb30f3b02],
+                            [0x155e0d6e, 0x96d75e06, 0x9bd7ce87, 0xacf868e1],
+                            [0xfd79103a, 0x695d21d3, 0xfeacb5b4, 0x1d869d08],
+                            [0xf4bcfeac, 0x0d2c305c, 0x11416c96, 0x626a5ef6],
+                            [0x3579b66c, 0x0a7d7dc0, 0xe80b0395, 0xf6a70661],
+                            [0x5773768c, 0x813442e9, 0x4dd6f793, 0xb10fe55f],
+                            [0xcaaf0ddb, 0x65c2410e, 0x95da5bba, 0x3b90128e],
+                            [0x74773773, 0xe1dbadeb, 0x57aaf64b, 0x9c21e3c7]]));
     }
 }
-
-/*const DEFAULT_ZIGZAG: [usize; 16] = [
-    0,  1,  5,  6,
-    2,  4,  7, 12,
-    3,  8, 11, 13,
-    9, 10, 14, 15
-];*/
-const DEFAULT_SCAN_ORDER: [usize; 16] = [
-    0,  1,  4,  8,
-    5,  2,  3,  6,
-    9, 12, 13, 10,
-    7, 11, 14, 15
-];
-
-const Y_MODE_TREE: &[VPTreeDef<PredMode>] = &[
-    VPTreeDef::Value(PredMode::DCPred), VPTreeDef::Index(2),
-    VPTreeDef::Index(4),                VPTreeDef::Index(6),
-    VPTreeDef::Value(PredMode::VPred),  VPTreeDef::Value(PredMode::HPred),
-    VPTreeDef::Value(PredMode::TMPred), VPTreeDef::Value(PredMode::BPred),
-];
-const KF_Y_MODE_TREE: &[VPTreeDef<PredMode>] = &[
-    VPTreeDef::Value(PredMode::BPred),  VPTreeDef::Index(2),
-    VPTreeDef::Index(4),                VPTreeDef::Index(6),
-    VPTreeDef::Value(PredMode::DCPred), VPTreeDef::Value(PredMode::VPred),
-    VPTreeDef::Value(PredMode::HPred),  VPTreeDef::Value(PredMode::TMPred),
-];
-const UV_MODE_TREE: &[VPTreeDef<PredMode>] = &[
-    VPTreeDef::Value(PredMode::DCPred), VPTreeDef::Index(2),
-    VPTreeDef::Value(PredMode::VPred),  VPTreeDef::Index(4),
-    VPTreeDef::Value(PredMode::HPred),  VPTreeDef::Value(PredMode::TMPred)
-];
-const B_MODE_TREE: &[VPTreeDef<PredMode>] = &[
-    VPTreeDef::Value(PredMode::DCPred), VPTreeDef::Index(2),
-    VPTreeDef::Value(PredMode::TMPred), VPTreeDef::Index(4),
-    VPTreeDef::Value(PredMode::VPred),  VPTreeDef::Index(6),
-    VPTreeDef::Index(8),                VPTreeDef::Index(12),
-    VPTreeDef::Value(PredMode::HPred),  VPTreeDef::Index(10),
-    VPTreeDef::Value(PredMode::RDPred), VPTreeDef::Value(PredMode::VRPred),
-    VPTreeDef::Value(PredMode::LDPred), VPTreeDef::Index(14),
-    VPTreeDef::Value(PredMode::VLPred), VPTreeDef::Index(16),
-    VPTreeDef::Value(PredMode::HDPred), VPTreeDef::Value(PredMode::HUPred)
-];
-
-const FEATURE_TREE: &[VPTreeDef<usize>] = &[
-    VPTreeDef::Index(2), VPTreeDef::Index(4),
-    VPTreeDef::Value(0), VPTreeDef::Value(1),
-    VPTreeDef::Value(2), VPTreeDef::Value(3)
-];
-
-const COEF_TREE: &[VPTreeDef<DCTToken>] = &[
-    VPTreeDef::Value(DCTToken::EOB),    VPTreeDef::Index(2),
-    VPTreeDef::Value(DCTToken::Zero),   VPTreeDef::Index(4),
-    VPTreeDef::Value(DCTToken::One),    VPTreeDef::Index(6),
-    VPTreeDef::Index(8),                VPTreeDef::Index(12),
-    VPTreeDef::Value(DCTToken::Two),    VPTreeDef::Index(10),
-    VPTreeDef::Value(DCTToken::Three),  VPTreeDef::Value(DCTToken::Four),
-    VPTreeDef::Index(14),               VPTreeDef::Index(16),
-    VPTreeDef::Value(DCTToken::Cat1),   VPTreeDef::Value(DCTToken::Cat2),
-    VPTreeDef::Index(18),               VPTreeDef::Index(20),
-    VPTreeDef::Value(DCTToken::Cat3),   VPTreeDef::Value(DCTToken::Cat4),
-    VPTreeDef::Value(DCTToken::Cat5),   VPTreeDef::Value(DCTToken::Cat6)
-];
-
-const MV_REF_TREE: &[VPTreeDef<VPMBType>] = &[
-    VPTreeDef::Value(VPMBType::InterNoMV),      VPTreeDef::Index(2),
-    VPTreeDef::Value(VPMBType::InterNearest),   VPTreeDef::Index(4),
-    VPTreeDef::Value(VPMBType::InterNear),      VPTreeDef::Index(6),
-    VPTreeDef::Value(VPMBType::InterMV),        VPTreeDef::Value(VPMBType::InterFourMV)
-];
-const SMALL_MV_TREE: &[VPTreeDef<i16>] = &[
-    VPTreeDef::Index(2),    VPTreeDef::Index(8),
-    VPTreeDef::Index(4),    VPTreeDef::Index(6),
-    VPTreeDef::Value(0),    VPTreeDef::Value(1),
-    VPTreeDef::Value(2),    VPTreeDef::Value(3),
-    VPTreeDef::Index(10),   VPTreeDef::Index(12),
-    VPTreeDef::Value(4),    VPTreeDef::Value(5),
-    VPTreeDef::Value(6),    VPTreeDef::Value(7)
-];
-const MV_SPLIT_MODE_TREE: &[VPTreeDef<MVSplitMode>] = &[
-    VPTreeDef::Value(MVSplitMode::Sixteenths),  VPTreeDef::Index(2),
-    VPTreeDef::Value(MVSplitMode::Quarters),    VPTreeDef::Index(4),
-    VPTreeDef::Value(MVSplitMode::TopBottom),   VPTreeDef::Value(MVSplitMode::LeftRight)
-];
-const SUB_MV_REF_TREE: &[VPTreeDef<SubMVRef>] = &[
-    VPTreeDef::Value(SubMVRef::Left),   VPTreeDef::Index(2),
-    VPTreeDef::Value(SubMVRef::Above),  VPTreeDef::Index(4),
-    VPTreeDef::Value(SubMVRef::Zero),   VPTreeDef::Value(SubMVRef::New)
-];