add nihav_qt crate with some QuickTime codecs
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 4 Jul 2020 16:30:01 +0000 (18:30 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Mon, 6 Jul 2020 11:30:44 +0000 (13:30 +0200)
19 files changed:
nihav-allstuff/Cargo.toml
nihav-allstuff/src/lib.rs
nihav-qt/Cargo.toml [new file with mode: 0644]
nihav-qt/src/codecs/imaadpcm.rs [new file with mode: 0644]
nihav-qt/src/codecs/mace.rs [new file with mode: 0644]
nihav-qt/src/codecs/mod.rs [new file with mode: 0644]
nihav-qt/src/codecs/qdm2.rs [new file with mode: 0644]
nihav-qt/src/codecs/qdm2fft.rs [new file with mode: 0644]
nihav-qt/src/codecs/qdm2qmf.rs [new file with mode: 0644]
nihav-qt/src/codecs/qdmc.rs [new file with mode: 0644]
nihav-qt/src/codecs/qdmcommon.rs [new file with mode: 0644]
nihav-qt/src/codecs/rle.rs [new file with mode: 0644]
nihav-qt/src/codecs/rpza.rs [new file with mode: 0644]
nihav-qt/src/codecs/smc.rs [new file with mode: 0644]
nihav-qt/src/codecs/svq1.rs [new file with mode: 0644]
nihav-qt/src/codecs/svq1data.rs [new file with mode: 0644]
nihav-qt/src/codecs/svq3.rs [new file with mode: 0644]
nihav-qt/src/codecs/svq3dsp.rs [new file with mode: 0644]
nihav-qt/src/lib.rs [new file with mode: 0644]

index 49aeaae28ce918335773b0b42a8b322449d6a295..6c5de36f500c0d2e355d41ba0c6dc7e45af412c4 100644 (file)
@@ -11,6 +11,7 @@ nihav_duck = { path = "../nihav-duck" }
 nihav_game = { path = "../nihav-game" }
 nihav_indeo = { path = "../nihav-indeo" }
 nihav_ms = { path = "../nihav-ms" }
+nihav_qt = { path = "../nihav-qt" }
 nihav_rad = { path = "../nihav-rad" }
 nihav_realmedia = { path = "../nihav-realmedia" }
 
index 0b85b89953648e33799325a81cebc646e7368b8c..88435c549e03ab3f5ca19420c92025fd090a2fb0 100644 (file)
@@ -28,6 +28,8 @@ use nihav_indeo::indeo_register_all_codecs;
 use nihav_ms::ms_register_all_codecs;
 use nihav_ms::ms_register_all_encoders;
 
+use nihav_qt::qt_register_all_codecs;
+
 use nihav_rad::rad_register_all_codecs;
 use nihav_rad::rad_register_all_demuxers;
 
@@ -41,6 +43,7 @@ pub fn nihav_register_all_codecs(rd: &mut RegisteredDecoders) {
     game_register_all_codecs(rd);
     indeo_register_all_codecs(rd);
     ms_register_all_codecs(rd);
+    qt_register_all_codecs(rd);
     rad_register_all_codecs(rd);
     realmedia_register_all_codecs(rd);
 }
diff --git a/nihav-qt/Cargo.toml b/nihav-qt/Cargo.toml
new file mode 100644 (file)
index 0000000..3e4b653
--- /dev/null
@@ -0,0 +1,34 @@
+[package]
+name = "nihav_qt"
+version = "0.1.0"
+authors = ["Kostya Shishkov <kostya.shishkov@gmail.com>"]
+edition = "2018"
+
+[dependencies.nihav_core]
+path = "../nihav-core"
+features = []
+
+[dependencies.nihav_codec_support]
+path = "../nihav-codec-support"
+features = ["blockdsp", "fft", "qmf"]
+
+[dev-dependencies]
+nihav_commonfmt = { path = "../nihav-commonfmt" }
+
+[features]
+default = ["all_decoders"]
+all_decoders = ["all_video_decoders", "all_audio_decoders"]
+decoders = []
+
+all_video_decoders = ["decoder_rle", "decoder_smc", "decoder_rpza", "decoder_svq1", "decoder_svq3", "decoder_qdm", "decoder_qdm2"]
+decoder_rle = ["decoders"]
+decoder_smc = ["decoders"]
+decoder_rpza = ["decoders"]
+decoder_svq1 = ["decoders"]
+decoder_svq3 = ["decoders"]
+decoder_qdm = ["decoders"]
+decoder_qdm2 = ["decoders"]
+
+all_audio_decoders = ["decoder_ima_adpcm_qt", "decoder_mace"]
+decoder_ima_adpcm_qt = ["decoders"]
+decoder_mace = ["decoders"]
diff --git a/nihav-qt/src/codecs/imaadpcm.rs b/nihav-qt/src/codecs/imaadpcm.rs
new file mode 100644 (file)
index 0000000..1d1a647
--- /dev/null
@@ -0,0 +1,109 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_codec_support::codecs::imaadpcm::*;
+use std::str::FromStr;
+
+const PACKET_LEN: usize = 34;
+const PACKET_SAMPLES: usize = 64;
+
+struct IMAADPCMDecoder {
+    ainfo:      NAAudioInfo,
+    chmap:      NAChannelMap,
+    ch_state:   [IMAState; 2],
+}
+
+impl IMAADPCMDecoder {
+    fn new() -> Self {
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_S16P_FORMAT, PACKET_SAMPLES),
+            chmap:      NAChannelMap::new(),
+            ch_state:   [IMAState::new(), IMAState::new()],
+        }
+    }
+}
+
+impl NADecoder for IMAADPCMDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+            let channels = ainfo.get_channels() as usize;
+            validate!(channels == 2 || channels == 1);
+            self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_S16P_FORMAT, PACKET_SAMPLES);
+            self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            let channels = self.chmap.num_channels();
+            validate!(pktbuf.len() % (PACKET_LEN * channels) == 0);
+            let nblocks = pktbuf.len() / channels / PACKET_LEN;
+            let nsamples = nblocks * PACKET_SAMPLES;
+            let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?;
+            let mut adata = abuf.get_abuf_i16().unwrap();
+            let mut off = [adata.get_offset(0), adata.get_offset(1)];
+            let dst = adata.get_data_mut().unwrap();
+
+            for data in pktbuf.chunks(PACKET_LEN * channels) {
+                for ch in 0..channels {
+                    let mut mr = MemoryReader::new_read(&data[PACKET_LEN * ch..][..PACKET_LEN]);
+                    let mut br = ByteReader::new(&mut mr);
+
+                    let init                    = br.read_u16be()?;
+                    let pred = (init as i16) & !0x7F;
+                    let step = (init & 0x7F) as u8;
+                    validate!(step <= IMA_MAX_STEP);
+                    self.ch_state[ch].reset(pred, step);
+
+                    for i in (0..PACKET_SAMPLES).step_by(2) {
+                        let byte                = br.read_byte()?;
+                        dst[off[ch] + i]     = self.ch_state[ch].expand_sample(byte & 0xF);
+                        dst[off[ch] + i + 1] = self.ch_state[ch].expand_sample(byte >> 4);
+                    }
+                    off[ch] += PACKET_SAMPLES;
+                }
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
+            frm.set_duration(Some(nsamples as u64));
+            frm.set_keyframe(false);
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for IMAADPCMDecoder {
+    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(IMAADPCMDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_ima_adpcm_qt() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "ima-adpcm-qt", "assets/QT/shuffle-ima41.mov", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xba2ad472, 0xd6aee026, 0xb915dd7d, 0xac51314c]));
+    }
+}
diff --git a/nihav-qt/src/codecs/mace.rs b/nihav-qt/src/codecs/mace.rs
new file mode 100644 (file)
index 0000000..d3fc953
--- /dev/null
@@ -0,0 +1,309 @@
+use nihav_core::codecs::*;
+use std::str::FromStr;
+
+const SND_U8P_FORMAT: NASoniton = NASoniton { bits: 8, be: false, packed: false, planar: true, float: false, signed: false };
+
+#[derive(Clone,Copy,Default)]
+struct ChannelPredictor {
+    index:      usize,
+    prev:       i16,
+    pprev:      i16,
+    scale:      i16,
+    level:      i16,
+}
+
+fn clip(val: i32) -> i16 {
+    if val > 0x7FFF { 0x7FFF }
+    else if val < -0x8000 { -0x7FFF }
+    else { val as i16 }
+}
+
+fn to_sample(val: i32) -> u8 {
+    ((val >> 8) + 128).max(0).min(255) as u8
+}
+
+impl ChannelPredictor {
+    fn get_quant(&mut self, idx: usize, middle: bool) -> i16 {
+        let pred;
+        let tab_idx = (self.index >> 4) & 0x7F;
+        if !middle {
+            if idx < 4 {
+                pred = QUANT_TAB0[tab_idx][idx];
+            } else {
+                pred = -1 - QUANT_TAB0[tab_idx][8 - 1 - idx];
+            }
+            self.index -= self.index >> 5;
+            self.index = ((self.index as isize) + (STEP_TAB0[idx] as isize)).max(0) as usize;
+        } else {
+            if idx < 2 {
+                pred = QUANT_TAB1[tab_idx][idx];
+            } else {
+                pred = -1 - QUANT_TAB1[tab_idx][4 - 1 - idx];
+            }
+            self.index -= self.index >> 5;
+            self.index = ((self.index as isize) + (STEP_TAB1[idx] as isize)).max(0) as usize;
+        }
+
+        pred
+    }
+    fn pred_mace3(&mut self, idx: usize, middle: bool) -> u8 {
+        let pred = self.get_quant(idx, middle);
+        let cur = clip(i32::from(pred) + i32::from(self.level));
+        self.level = cur - (cur >> 3);
+        to_sample(i32::from(cur))
+    }
+    fn pred_mace6(&mut self, idx: usize, middle: bool) -> (u8, u8) {
+        let pred = self.get_quant(idx, middle);
+        if (self.prev ^ pred) >= 0 {
+            self.scale = self.scale.saturating_add(506);
+        } else {
+            self.scale = clip(i32::from(self.scale) - 314);
+        }
+        let mut cur = clip(i32::from(pred) + i32::from(self.level));
+
+        self.level = ((i32::from(cur) * i32::from(self.scale)) >> 15) as i16;
+        cur >>= 1;
+
+        let diff = (i32::from(self.pprev) - i32::from(cur)) >> 2;
+        let s0 = i32::from(self.pprev) + i32::from(self.prev) - diff;
+        let s1 = i32::from(self.prev) + i32::from(cur) + diff;
+
+        self.pprev = self.prev;
+        self.prev  = cur;
+
+        (to_sample(s0), to_sample(s1))
+    }
+}
+
+struct MaceDecoder {
+    ainfo:      NAAudioInfo,
+    chmap:      NAChannelMap,
+    ch_pred:    [ChannelPredictor; 2],
+    is_mace6:   bool,
+}
+
+impl MaceDecoder {
+    fn new(is_mace6: bool) -> Self {
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_U8P_FORMAT, 1),
+            chmap:      NAChannelMap::new(),
+            ch_pred:    [ChannelPredictor::default(); 2],
+            is_mace6,
+        }
+    }
+}
+
+impl NADecoder for MaceDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+            let channels = ainfo.get_channels() as usize;
+            validate!(channels == 2 || channels == 1);
+            self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(), channels as u8, SND_U8P_FORMAT, 1);
+            self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            let channels = self.chmap.num_channels();
+            let nsamples = pktbuf.len() * (if self.is_mace6 { 6 } else { 3 }) / channels;
+            let abuf = alloc_audio_buffer(self.ainfo, nsamples, self.chmap.clone())?;
+            let mut adata = abuf.get_abuf_u8().unwrap();
+            let mut off = [adata.get_offset(0), adata.get_offset(1)];
+            let dst = adata.get_data_mut().unwrap();
+
+            if !self.is_mace6 {
+                for src in pktbuf.chunks(channels) {
+                    for ch in 0..channels {
+                        let val = src[ch];
+                        let idx0 = val & 7;
+                        let idx1 = (val >> 3) & 3;
+                        let idx2 = val >> 5;
+                        dst[off[ch]]     = self.ch_pred[ch].pred_mace3(idx0 as usize, false);
+                        dst[off[ch] + 1] = self.ch_pred[ch].pred_mace3(idx1 as usize, true);
+                        dst[off[ch] + 2] = self.ch_pred[ch].pred_mace3(idx2 as usize, false);
+                        off[ch] += 3;
+                    }
+                }
+            } else {
+                for src in pktbuf.chunks(channels) {
+                    for ch in 0..channels {
+                        let val = src[ch];
+                        let idx0 = val >> 5;
+                        let idx1 = (val >> 3) & 3;
+                        let idx2 = val & 7;
+                        let (s0, s1) = self.ch_pred[ch].pred_mace6(idx0 as usize, false);
+                        dst[off[ch]]     = s0;
+                        dst[off[ch] + 1] = s1;
+                        let (s0, s1) = self.ch_pred[ch].pred_mace6(idx1 as usize, true);
+                        dst[off[ch] + 2] = s0;
+                        dst[off[ch] + 3] = s1;
+                        let (s0, s1) = self.ch_pred[ch].pred_mace6(idx2 as usize, false);
+                        dst[off[ch] + 4] = s0;
+                        dst[off[ch] + 5] = s1;
+                        off[ch] += 6;
+                    }
+                }
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
+            frm.set_duration(Some(nsamples as u64));
+            frm.set_keyframe(false);
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for MaceDecoder {
+    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_3() -> Box<dyn NADecoder + Send> {
+    Box::new(MaceDecoder::new(false))
+}
+
+pub fn get_decoder_6() -> Box<dyn NADecoder + Send> {
+    Box::new(MaceDecoder::new(true))
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_mace3() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "mace-3", "assets/QT/surge-1-8-MAC3.mov", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x2df88db3, 0xa6167019, 0x6d4c64e7, 0xc89da2a5]));
+    }
+    #[test]
+    fn test_mace6() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "mace-6", "assets/QT/surge-1-8-MAC6.mov", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xc32857e2, 0xc1ea1ce8, 0x2d77dacf, 0xef504f1f]));
+    }
+}
+
+const STEP_TAB0: [i16; 8] = [ -13, 8, 76, 222, 222, 76, 8, -13 ];
+const STEP_TAB1: [i16; 4] = [ -18, 140, 140, -18 ];
+const QUANT_TAB0: [[i16; 4]; 128] = [
+    [    37,   116,   206,   330 ], [    39,   121,   216,   346 ],
+    [    41,   127,   225,   361 ], [    42,   132,   235,   377 ],
+    [    44,   137,   245,   392 ], [    46,   144,   256,   410 ],
+    [    48,   150,   267,   428 ], [    51,   157,   280,   449 ],
+    [    53,   165,   293,   470 ], [    55,   172,   306,   490 ],
+    [    58,   179,   319,   511 ], [    60,   187,   333,   534 ],
+    [    63,   195,   348,   557 ], [    66,   205,   364,   583 ],
+    [    69,   214,   380,   609 ], [    72,   223,   396,   635 ],
+    [    75,   233,   414,   663 ], [    79,   244,   433,   694 ],
+    [    82,   254,   453,   725 ], [    86,   265,   472,   756 ],
+    [    90,   278,   495,   792 ], [    94,   290,   516,   826 ],
+    [    98,   303,   538,   862 ], [   102,   316,   562,   901 ],
+    [   107,   331,   588,   942 ], [   112,   345,   614,   983 ],
+    [   117,   361,   641,  1027 ], [   122,   377,   670,  1074 ],
+    [   127,   394,   701,  1123 ], [   133,   411,   732,  1172 ],
+    [   139,   430,   764,  1224 ], [   145,   449,   799,  1280 ],
+    [   152,   469,   835,  1337 ], [   159,   490,   872,  1397 ],
+    [   166,   512,   911,  1459 ], [   173,   535,   951,  1523 ],
+    [   181,   558,   993,  1590 ], [   189,   584,  1038,  1663 ],
+    [   197,   610,  1085,  1738 ], [   206,   637,  1133,  1815 ],
+    [   215,   665,  1183,  1895 ], [   225,   695,  1237,  1980 ],
+    [   235,   726,  1291,  2068 ], [   246,   759,  1349,  2161 ],
+    [   257,   792,  1409,  2257 ], [   268,   828,  1472,  2357 ],
+    [   280,   865,  1538,  2463 ], [   293,   903,  1606,  2572 ],
+    [   306,   944,  1678,  2688 ], [   319,   986,  1753,  2807 ],
+    [   334,  1030,  1832,  2933 ], [   349,  1076,  1914,  3065 ],
+    [   364,  1124,  1999,  3202 ], [   380,  1174,  2088,  3344 ],
+    [   398,  1227,  2182,  3494 ], [   415,  1281,  2278,  3649 ],
+    [   434,  1339,  2380,  3811 ], [   453,  1398,  2486,  3982 ],
+    [   473,  1461,  2598,  4160 ], [   495,  1526,  2714,  4346 ],
+    [   517,  1594,  2835,  4540 ], [   540,  1665,  2961,  4741 ],
+    [   564,  1740,  3093,  4953 ], [   589,  1818,  3232,  5175 ],
+    [   615,  1898,  3375,  5405 ], [   643,  1984,  3527,  5647 ],
+    [   671,  2072,  3683,  5898 ], [   701,  2164,  3848,  6161 ],
+    [   733,  2261,  4020,  6438 ], [   766,  2362,  4199,  6724 ],
+    [   800,  2467,  4386,  7024 ], [   836,  2578,  4583,  7339 ],
+    [   873,  2692,  4786,  7664 ], [   912,  2813,  5001,  8008 ],
+    [   952,  2938,  5223,  8364 ], [   995,  3070,  5457,  8739 ],
+    [  1039,  3207,  5701,  9129 ], [  1086,  3350,  5956,  9537 ],
+    [  1134,  3499,  6220,  9960 ], [  1185,  3655,  6497, 10404 ],
+    [  1238,  3818,  6788, 10869 ], [  1293,  3989,  7091, 11355 ],
+    [  1351,  4166,  7407, 11861 ], [  1411,  4352,  7738, 12390 ],
+    [  1474,  4547,  8084, 12946 ], [  1540,  4750,  8444, 13522 ],
+    [  1609,  4962,  8821, 14126 ], [  1680,  5183,  9215, 14756 ],
+    [  1756,  5415,  9626, 15415 ], [  1834,  5657, 10057, 16104 ],
+    [  1916,  5909, 10505, 16822 ], [  2001,  6173, 10975, 17574 ],
+    [  2091,  6448, 11463, 18356 ], [  2184,  6736, 11974, 19175 ],
+    [  2282,  7037, 12510, 20032 ], [  2383,  7351, 13068, 20926 ],
+    [  2490,  7679, 13652, 21861 ], [  2601,  8021, 14260, 22834 ],
+    [  2717,  8380, 14897, 23854 ], [  2838,  8753, 15561, 24918 ],
+    [  2965,  9144, 16256, 26031 ], [  3097,  9553, 16982, 27193 ],
+    [  3236,  9979, 17740, 28407 ], [  3380, 10424, 18532, 29675 ],
+    [  3531, 10890, 19359, 31000 ], [  3688, 11375, 20222, 32382 ],
+    [  3853, 11883, 21125, 32767 ], [  4025, 12414, 22069, 32767 ],
+    [  4205, 12967, 23053, 32767 ], [  4392, 13546, 24082, 32767 ],
+    [  4589, 14151, 25157, 32767 ], [  4793, 14783, 26280, 32767 ],
+    [  5007, 15442, 27452, 32767 ], [  5231, 16132, 28678, 32767 ],
+    [  5464, 16851, 29957, 32767 ], [  5708, 17603, 31294, 32767 ],
+    [  5963, 18389, 32691, 32767 ], [  6229, 19210, 32767, 32767 ],
+    [  6507, 20067, 32767, 32767 ], [  6797, 20963, 32767, 32767 ],
+    [  7101, 21899, 32767, 32767 ], [  7418, 22876, 32767, 32767 ],
+    [  7749, 23897, 32767, 32767 ], [  8095, 24964, 32767, 32767 ],
+    [  8456, 26078, 32767, 32767 ], [  8833, 27242, 32767, 32767 ],
+    [  9228, 28457, 32767, 32767 ], [  9639, 29727, 32767, 32767 ]
+];
+const QUANT_TAB1: [[i16; 2]; 128] = [
+    [    64,   216 ], [    67,   226 ], [    70,   236 ], [    74,   246 ],
+    [    77,   257 ], [    80,   268 ], [    84,   280 ], [    88,   294 ],
+    [    92,   307 ], [    96,   321 ], [   100,   334 ], [   104,   350 ],
+    [   109,   365 ], [   114,   382 ], [   119,   399 ], [   124,   416 ],
+    [   130,   434 ], [   136,   454 ], [   142,   475 ], [   148,   495 ],
+    [   155,   519 ], [   162,   541 ], [   169,   564 ], [   176,   590 ],
+    [   185,   617 ], [   193,   644 ], [   201,   673 ], [   210,   703 ],
+    [   220,   735 ], [   230,   767 ], [   240,   801 ], [   251,   838 ],
+    [   262,   876 ], [   274,   914 ], [   286,   955 ], [   299,   997 ],
+    [   312,  1041 ], [   326,  1089 ], [   341,  1138 ], [   356,  1188 ],
+    [   372,  1241 ], [   388,  1297 ], [   406,  1354 ], [   424,  1415 ],
+    [   443,  1478 ], [   462,  1544 ], [   483,  1613 ], [   505,  1684 ],
+    [   527,  1760 ], [   551,  1838 ], [   576,  1921 ], [   601,  2007 ],
+    [   628,  2097 ], [   656,  2190 ], [   686,  2288 ], [   716,  2389 ],
+    [   748,  2496 ], [   781,  2607 ], [   816,  2724 ], [   853,  2846 ],
+    [   891,  2973 ], [   930,  3104 ], [   972,  3243 ], [  1016,  3389 ],
+    [  1061,  3539 ], [  1108,  3698 ], [  1158,  3862 ], [  1209,  4035 ],
+    [  1264,  4216 ], [  1320,  4403 ], [  1379,  4599 ], [  1441,  4806 ],
+    [  1505,  5019 ], [  1572,  5244 ], [  1642,  5477 ], [  1715,  5722 ],
+    [  1792,  5978 ], [  1872,  6245 ], [  1955,  6522 ], [  2043,  6813 ],
+    [  2134,  7118 ], [  2229,  7436 ], [  2329,  7767 ], [  2432,  8114 ],
+    [  2541,  8477 ], [  2655,  8854 ], [  2773,  9250 ], [  2897,  9663 ],
+    [  3026, 10094 ], [  3162, 10546 ], [  3303, 11016 ], [  3450, 11508 ],
+    [  3604, 12020 ], [  3765, 12556 ], [  3933, 13118 ], [  4108, 13703 ],
+    [  4292, 14315 ], [  4483, 14953 ], [  4683, 15621 ], [  4892, 16318 ],
+    [  5111, 17046 ], [  5339, 17807 ], [  5577, 18602 ], [  5826, 19433 ],
+    [  6086, 20300 ], [  6358, 21205 ], [  6642, 22152 ], [  6938, 23141 ],
+    [  7248, 24173 ], [  7571, 25252 ], [  7909, 26380 ], [  8262, 27557 ],
+    [  8631, 28786 ], [  9016, 30072 ], [  9419, 31413 ], [  9839, 32767 ],
+    [ 10278, 32767 ], [ 10737, 32767 ], [ 11216, 32767 ], [ 11717, 32767 ],
+    [ 12240, 32767 ], [ 12786, 32767 ], [ 13356, 32767 ], [ 13953, 32767 ],
+    [ 14576, 32767 ], [ 15226, 32767 ], [ 15906, 32767 ], [ 16615, 32767 ]
+];
diff --git a/nihav-qt/src/codecs/mod.rs b/nihav-qt/src/codecs/mod.rs
new file mode 100644 (file)
index 0000000..733d599
--- /dev/null
@@ -0,0 +1,93 @@
+use nihav_core::codecs::*;
+
+macro_rules! validate {
+    ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DecoderError::InvalidData); } };
+}
+
+#[cfg(feature="decoder_rle")]
+mod rle;
+
+#[cfg(feature="decoder_rpza")]
+mod rpza;
+
+#[cfg(feature="decoder_smc")]
+mod smc;
+
+#[cfg(feature="decoder_svq1")]
+mod svq1;
+#[cfg(feature="decoder_svq1")]
+mod svq1data;
+
+#[cfg(feature="decoder_svq3")]
+#[allow(clippy::collapsible_if)]
+#[allow(clippy::identity_op)]
+#[allow(clippy::needless_range_loop)]
+#[allow(clippy::too_many_arguments)]
+#[allow(clippy::verbose_bit_mask)]
+mod svq3;
+#[cfg(feature="decoder_svq3")]
+#[allow(clippy::collapsible_if)]
+#[allow(clippy::erasing_op)]
+#[allow(clippy::identity_op)]
+#[allow(clippy::many_single_char_names)]
+#[allow(clippy::needless_range_loop)]
+#[allow(clippy::unreadable_literal)]
+mod svq3dsp;
+
+#[cfg(feature="decoder_ima_adpcm_qt")]
+mod imaadpcm;
+
+#[cfg(feature="decoder_mace")]
+mod mace;
+
+#[cfg(any(feature="decoder_qdm",feature="decoder_qdm2"))]
+#[allow(clippy::unreadable_literal)]
+mod qdmcommon;
+#[cfg(feature="decoder_qdm")]
+#[allow(clippy::needless_range_loop)]
+#[allow(clippy::unreadable_literal)]
+mod qdmc;
+#[cfg(feature="decoder_qdm2")]
+#[allow(clippy::needless_range_loop)]
+#[allow(clippy::excessive_precision)]
+#[allow(clippy::unreadable_literal)]
+mod qdm2fft;
+#[cfg(feature="decoder_qdm2")]
+#[allow(clippy::needless_range_loop)]
+#[allow(clippy::excessive_precision)]
+#[allow(clippy::unreadable_literal)]
+mod qdm2qmf;
+#[cfg(feature="decoder_qdm2")]
+#[allow(clippy::excessive_precision)]
+#[allow(clippy::unreadable_literal)]
+mod qdm2;
+
+const QT_CODECS: &[DecoderInfo] = &[
+#[cfg(feature="decoder_rle")]
+    DecoderInfo { name: "qt-rle", get_decoder: rle::get_decoder },
+#[cfg(feature="decoder_rpza")]
+    DecoderInfo { name: "apple-video", get_decoder: rpza::get_decoder },
+#[cfg(feature="decoder_smc")]
+    DecoderInfo { name: "qt-smc", get_decoder: smc::get_decoder },
+#[cfg(feature="decoder_svq1")]
+    DecoderInfo { name: "sorenson-video", get_decoder: svq1::get_decoder },
+#[cfg(feature="decoder_svq3")]
+    DecoderInfo { name: "sorenson-video3", get_decoder: svq3::get_decoder },
+#[cfg(feature="decoder_ima_adpcm_qt")]
+    DecoderInfo { name: "ima-adpcm-qt", get_decoder: imaadpcm::get_decoder },
+#[cfg(feature="decoder_mace")]
+    DecoderInfo { name: "mace-3", get_decoder: mace::get_decoder_3 },
+#[cfg(feature="decoder_mace")]
+    DecoderInfo { name: "mace-6", get_decoder: mace::get_decoder_6 },
+#[cfg(feature="decoder_qdm")]
+    DecoderInfo { name: "qdesign-music", get_decoder: qdmc::get_decoder },
+#[cfg(feature="decoder_qdm2")]
+    DecoderInfo { name: "qdesign-music2", get_decoder: qdm2::get_decoder },
+];
+
+/// Registers all available codecs provided by this crate.
+pub fn qt_register_all_codecs(rd: &mut RegisteredDecoders) {
+    for decoder in QT_CODECS.iter() {
+        rd.add_decoder(decoder.clone());
+    }
+}
diff --git a/nihav-qt/src/codecs/qdm2.rs b/nihav-qt/src/codecs/qdm2.rs
new file mode 100644 (file)
index 0000000..ff9a337
--- /dev/null
@@ -0,0 +1,347 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use super::qdmcommon::*;
+use super::qdm2fft::*;
+use super::qdm2qmf::*;
+
+pub const MAX_FRAME_SIZE: usize = 8192;
+
+const SOFTCLIP_THRESHOLD: usize = 27600;
+const HARDCLIP_THRESHOLD: usize = 35716;
+const SOFTCLIP_SIZE: usize = HARDCLIP_THRESHOLD - SOFTCLIP_THRESHOLD + 1;
+
+#[derive(Clone,Copy)]
+struct Packet {
+    id:     u8,
+    size:   usize,
+    offset: usize,
+}
+
+impl Packet {
+    fn read(br: &mut ByteReader) -> DecoderResult<Self> {
+        let id                          = br.read_byte()?;
+        let size                        = if (id & 0x80) == 0 { br.read_byte()? as usize } else { br.read_u16be()? as usize };
+        validate!(size <= (br.left() as usize));
+        Ok(Packet { id: id & 0x7F, size, offset: br.tell() as usize })
+    }
+}
+
+struct Qdmc2Decoder {
+    ainfo:              NAAudioInfo,
+    chmap:              NAChannelMap,
+    softclip:           [i16; SOFTCLIP_SIZE],
+    qmf_part:           QDM2QMF,
+    fft_part:           QDM2FFT,
+    audio:              [[f32; MAX_FRAME_SIZE]; 2],
+
+    order:              u8,
+    frame_bits:         u8,
+    samples:            usize,
+    frm_bytes:          usize,
+    sf_len:             usize,
+    channels:           usize,
+
+    subsampling:        u8,
+    do_synth:           bool,
+}
+
+impl Qdmc2Decoder {
+    fn new() -> Self {
+        let mut softclip = [0; SOFTCLIP_SIZE];
+        let delta = 1.0 / ((32767 - SOFTCLIP_THRESHOLD) as f32);
+        let diff = f32::from((SOFTCLIP_THRESHOLD as i16) - 32767);
+        for (i, el) in softclip.iter_mut().enumerate() {
+            *el = (SOFTCLIP_THRESHOLD as i16) - ((((i as f32) * delta).sin() * diff) as i16);
+        }
+
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 1),
+            chmap:      NAChannelMap::new(),
+            audio:      [[0.0; MAX_FRAME_SIZE]; 2],
+            softclip,
+            qmf_part:   QDM2QMF::new(),
+            fft_part:   QDM2FFT::new(),
+
+            order:      0,
+            frame_bits: 0,
+            samples:    0,
+            frm_bytes:  0,
+            sf_len:     0,
+            channels:   0,
+
+            subsampling:        0,
+            do_synth:           false,
+        }
+    }
+}
+
+impl NADecoder for Qdmc2Decoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+            if let Some(edata) = info.get_extradata() {
+                validate!(edata.len() >= 36);
+                let mut mr = MemoryReader::new_read(edata.as_slice());
+                let mut br = ByteReader::new(&mut mr);
+                let size                = br.read_u32be()? as usize;
+                validate!(size >= 36 && size <= edata.len());
+                let tag                 = br.read_tag()?;
+                validate!(&tag == b"QDCA");
+                let ver                 = br.read_u32be()?;
+                validate!(ver == 1);
+                let channels            = br.read_u32be()? as usize;
+                validate!(channels == 2 || channels == 1);
+                let srate               = br.read_u32be()?;
+                let full_bitrate        = br.read_u32be()?;
+                let frame_len           = br.read_u32be()? as usize;
+                let packet_size         = br.read_u32be()? as usize;
+                validate!(packet_size > 0 && (packet_size & (packet_size - 1)) == 0);
+                validate!(frame_len == packet_size * 16);
+                let bytes_per_frame     = br.read_u32be()? as usize;
+                validate!(bytes_per_frame > 6);
+
+                self.order = (31 - (packet_size.leading_zeros() & 31)) as u8;
+                validate!(self.order >= 6 && self.order <= 8);
+                self.frame_bits = self.order + 4;
+                self.samples = frame_len;
+                self.frm_bytes = bytes_per_frame;
+                self.sf_len = packet_size;
+                self.channels = channels;
+
+                let srate = if ainfo.get_sample_rate() != 0 {
+                        ainfo.get_sample_rate()
+                    } else { srate };
+                self.ainfo = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 1);
+                self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
+
+                self.subsampling = self.order - 6;
+                self.fft_part.set_params(channels, self.sf_len, self.subsampling);
+                self.qmf_part.set_ch_and_subsampling(channels, self.subsampling, full_bitrate);
+            } else {
+                return Err(DecoderError::InvalidData);
+            }
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() == self.frm_bytes);
+
+            let mut mr = MemoryReader::new_read(pktbuf.as_slice());
+            let mut br = ByteReader::new(&mut mr);
+            let hdr = Packet::read(&mut br)?;
+
+            let (is_intra, has_checksum) = match hdr.id {
+                    2 => (true, true),
+                    3 => (true, false),
+                    4 | 5 => (false, true),
+                    6 | 7 => (false, false),
+                    _ => return Err(DecoderError::InvalidData),
+                };
+            if has_checksum {
+                let mut csum = u16::from(br.read_byte()?) * 0x101;
+                csum = csum.wrapping_add(u16::from(br.read_byte()?) * 2);
+                for byte in pktbuf.iter() {
+                    csum = csum.wrapping_sub(u16::from(*byte));
+                }
+                validate!(csum == 0);
+            }
+            self.fft_part.is_intra = is_intra;
+            self.qmf_part.is_intra = is_intra;
+            self.qmf_part.new_frame();
+
+            let mut tone_pkt_list = Vec::new();
+            let mut fft_pkt_list = Vec::new();
+            while br.left() > 1 {
+                let hdr                 = Packet::read(&mut br)?;
+                if hdr.id == 0 { break; }
+                match hdr.id {
+                    8 => return Err(DecoderError::NotImplemented),
+                    9..=12 => {
+                        tone_pkt_list.push(hdr);
+                    },
+                    13 => {
+                        let src = &pktbuf[hdr.offset..][..hdr.size];
+                        let mut br = QdmBitReader::new(src);
+                        self.fft_part.read_type_13(&mut br)?;
+                    },
+                    14 => {
+                        let src = &pktbuf[hdr.offset..][..hdr.size];
+                        let mut br = QdmBitReader::new(src);
+                        self.fft_part.read_type_14(&mut br)?;
+                    },
+                    15 => return Err(DecoderError::NotImplemented),
+                    16..=23 | 31..=39 | 46..=47 => {
+                        fft_pkt_list.push(hdr);
+                    },
+                    _ => {},
+                };
+                                          br.read_skip(hdr.size)?;
+            }
+
+            if !tone_pkt_list.is_empty() {
+                let mut has_9 = false;
+                let mut has_10 = false;
+                let mut has_11 = false;
+                let mut pkt_12 = Packet { id: 0, size: 0, offset: 0 };
+                for hdr in tone_pkt_list.iter() {
+                    let src = &pktbuf[hdr.offset..][..hdr.size];
+                    let mut br = QdmBitReader::new(src);
+                    match hdr.id {
+                         9 => { self.qmf_part.read_type_9(&mut br)?;  has_9 = true; },
+                        10 => { self.qmf_part.read_type_10(&mut br)?; has_10 = true; },
+                        11 => { self.qmf_part.read_type_11(&mut br)?; has_11 = true; },
+                        12 => { pkt_12 = *hdr; },
+                        _ => unreachable!(),
+                    };
+                }
+                if !has_10 {
+                    self.qmf_part.fill_default(10);
+                }
+                if !has_11 {
+                    self.qmf_part.fill_default(11);
+                }
+                if pkt_12.id == 12 && has_9 && has_10 {
+                    let src = &pktbuf[pkt_12.offset..][..pkt_12.size];
+                    let mut br = QdmBitReader::new(src);
+                    self.qmf_part.read_type_12(&mut br)?;
+                } else {
+                    self.qmf_part.fill_default(12);
+                }
+                self.do_synth = true;
+            }
+
+            if tone_pkt_list.is_empty() && self.do_synth {
+                self.qmf_part.fill_default(10);
+                self.qmf_part.fill_default(11);
+                self.qmf_part.fill_default(12);
+            }
+
+            let channels = self.chmap.num_channels();
+            let abuf = alloc_audio_buffer(self.ainfo, self.samples, self.chmap.clone())?;
+            let mut adata = abuf.get_abuf_i16().unwrap();
+            let off = [adata.get_offset(0), adata.get_offset(1)];
+            let dst = adata.get_data_mut().unwrap();
+
+            self.audio = [[0.0; MAX_FRAME_SIZE]; 2];
+            for subframe in 0..16 {
+                if subframe == 2 {
+                    self.fft_part.new_frame();
+                    for hdr in fft_pkt_list.iter() {
+                        let src = &pktbuf[hdr.offset..][..hdr.size];
+                        let mut br = QdmBitReader::new(src);
+                        self.fft_part.read_fft_packet(hdr.id, &mut br)?;
+                    }
+                }
+                self.fft_part.generate_tones(subframe);
+                for ch in 0..channels {
+                    let output = &mut self.audio[ch][subframe * self.sf_len..][..self.sf_len];
+                    self.fft_part.synth(output, ch);
+                    if self.do_synth {
+                        self.qmf_part.synth(output, subframe, ch);
+                    }
+                }
+            }
+            let frame_len = self.sf_len * 16;
+            for ch in 0..channels {
+                for (src, dst) in self.audio[ch].iter().take(frame_len).zip(dst[off[ch]..].iter_mut()) {
+                    let samp = *src as i32;
+                    if samp > (HARDCLIP_THRESHOLD as i32) {
+                        *dst = 0x7FFF;
+                    } else if samp > (SOFTCLIP_THRESHOLD as i32) {
+                        *dst = self.softclip[(samp as usize) - SOFTCLIP_THRESHOLD];
+                    } else if samp > -(SOFTCLIP_THRESHOLD as i32) {
+                        *dst = samp as i16;
+                    } else if samp > -(HARDCLIP_THRESHOLD as i32) {
+                        *dst = -self.softclip[(-samp as usize) - SOFTCLIP_THRESHOLD];
+                    } else {
+                        *dst = -0x8000;
+                    }
+                }
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
+            frm.set_duration(Some(self.samples as u64));
+            frm.set_keyframe(false);
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+        self.qmf_part.flush();
+        self.fft_part.flush();
+    }
+}
+
+impl NAOptionHandler for Qdmc2Decoder {
+    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(Qdmc2Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_qdm2() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        //test_decode_audio("mov", "assets/QT/0-22050HzSweep8kb.mov", None, Some("qdm2"), &dmx_reg, &dec_reg);
+        test_decoding("mov", "qdesign-music2", "assets/QT/0-22050HzSweep10kb.mov", None, &dmx_reg, &dec_reg,
+                      ExpectedTestResult::Decodes);
+    }
+}
+
+pub const TONE_SCALES: [[f32; 64]; 2] = [
+  [
+    0.17677669, 0.42677650, 0.60355347, 0.85355347,
+    1.20710683, 1.68359375, 2.37500000, 3.36718750,
+    4.75000000, 6.73437500, 9.50000000, 13.4687500,
+    19.0000000, 26.9375000, 38.0000000, 53.8750000,
+    76.0000000, 107.750000, 152.000000, 215.500000,
+    304.000000, 431.000000, 608.000000, 862.000000,
+    1216.00000, 1724.00000, 2432.00000, 3448.00000,
+    4864.00000, 6896.00000, 9728.00000, 13792.0000,
+    19456.0000, 27584.0000, 38912.0000, 55168.0000,
+    77824.0000, 110336.000, 155648.000, 220672.000,
+    311296.000, 441344.000, 622592.000, 882688.000,
+    1245184.00, 1765376.00, 2490368.00, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000
+  ], [
+    0.59375000, 0.84179688, 1.18750000, 1.68359375,
+    2.37500000, 3.36718750, 4.75000000, 6.73437500,
+    9.50000000, 13.4687500, 19.0000000, 26.9375000,
+    38.0000000, 53.8750000, 76.0000000, 107.750000,
+    152.000000, 215.500000, 304.000000, 431.000000,
+    608.000000, 862.000000, 1216.00000, 1724.00000,
+    2432.00000, 3448.00000, 4864.00000, 6896.00000,
+    9728.00000, 13792.0000, 19456.0000, 27584.0000,
+    38912.0000, 55168.0000, 77824.0000, 110336.000,
+    155648.000, 220672.000, 311296.000, 441344.000,
+    622592.000, 882688.000, 1245184.00, 1765376.00,
+    2490368.00, 3530752.00, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000,
+    0.00000000, 0.00000000, 0.00000000, 0.00000000
+  ]
+];
diff --git a/nihav-qt/src/codecs/qdm2fft.rs b/nihav-qt/src/codecs/qdm2fft.rs
new file mode 100644 (file)
index 0000000..22ca5dc
--- /dev/null
@@ -0,0 +1,596 @@
+use nihav_core::codecs::*;
+use nihav_core::io::codebook::*;
+use nihav_codec_support::dsp::fft::*;
+use super::qdmcommon::*;
+use super::qdm2::TONE_SCALES;
+use std::f32::consts::PI;
+
+struct Codebooks {
+    group_cb:           [Codebook<u8>; 5],
+    level_exp_alt_cb:   Codebook<u8>,
+    level_exp_cb:       Codebook<u8>,
+    stereo_exp_cb:      Codebook<u8>,
+    phase_diff_cb:      Codebook<u8>,
+}
+
+fn map_idx(idx: usize) -> u8 { idx as u8 }
+
+macro_rules! create_codebook {
+    ($codes: expr, $bits: expr) => ({
+        let mut cbr = TableCodebookDescReader::new($codes, $bits, map_idx);
+        Codebook::new(&mut cbr, CodebookMode::LSB).unwrap()
+    })
+}
+
+impl Codebooks {
+    fn new() -> Self {
+        let cb0 = create_codebook!(FFT_GROUP_CODES[0], FFT_GROUP_BITS[0]);
+        let cb1 = create_codebook!(FFT_GROUP_CODES[1], FFT_GROUP_BITS[1]);
+        let cb2 = create_codebook!(FFT_GROUP_CODES[2], FFT_GROUP_BITS[2]);
+        let cb3 = create_codebook!(FFT_GROUP_CODES[3], FFT_GROUP_BITS[3]);
+        let cb4 = create_codebook!(FFT_GROUP_CODES[4], FFT_GROUP_BITS[4]);
+        let group_cb = [cb0, cb1, cb2, cb3, cb4];
+        let level_exp_alt_cb = create_codebook!(FFT_LEVEL_EXP_ALT_CODES, FFT_LEVEL_EXP_ALT_BITS);
+        let level_exp_cb = create_codebook!(FFT_LEVEL_EXP_CODES, FFT_LEVEL_EXP_BITS);
+        let stereo_exp_cb = create_codebook!(FFT_STEREO_EXP_CODES, FFT_STEREO_EXP_BITS);
+        let phase_diff_cb = create_codebook!(FFT_STEREO_PHASE_CODES, FFT_STEREO_PHASE_BITS);
+        Self {
+            group_cb, level_exp_alt_cb, level_exp_cb,
+            stereo_exp_cb, phase_diff_cb,
+        }
+    }
+}
+
+#[derive(Clone,Copy)]
+struct OldTone {
+    used:       bool,
+    phase:      i32,
+    phase_add:  i32,
+    time:       u8,
+    scale:      f32,
+    cutoff:     usize,
+    grp:        u8,
+    offset:     u8,
+    freq:       u16,
+    ch:         u8,
+}
+
+struct Synth {
+    rdft:               RDFT,
+    sbuf:               [[FFTComplex; 256]; 2],
+    delay:              [[f32; 256]; 2],
+}
+
+impl Synth {
+    fn new() -> Self {
+        Self {
+            rdft:           RDFTBuilder::new_rdft(256, true, true),
+            sbuf:           [[FFTC_ZERO; 256]; 2],
+            delay:          [[0.0; 256]; 2],
+        }
+    }
+    fn new_sf(&mut self) {
+        self.sbuf = [[FFTC_ZERO; 256]; 2];
+    }
+    fn synth_old_tone(&mut self, tone: &mut OldTone) {
+        let off = tone.offset as usize;
+        let scale = tone.scale * TONE_ENVELOPE[tone.grp as usize][tone.time as usize];
+        tone.phase += tone.phase_add;
+
+        let val = FFTComplex::exp((tone.phase as f32) * PI / 256.0).scale(scale);
+        let ch = tone.ch as usize;
+
+        if tone.grp >= 3 || tone.cutoff >= 3 {
+            self.sbuf[ch][off]     += val;
+            self.sbuf[ch][off + 1] -= val;
+        } else {
+            let tab = &FFT_TONE_SAMPLES[tone.grp as usize][(tone.freq as usize) - (off << (4 - tone.grp))];
+            let wave = [tab[3] - tab[0], -tab[4], 1.0 - tab[2] - tab[3],
+                        tab[1] + tab[4] - 1.0, tab[0] - tab[1], tab[2]];
+            let cidx = CUTOFF_INDICES[tone.cutoff];
+            let coff0 = (off as isize) + (cidx[0] as isize);
+            let coff1 = (off as isize) + (cidx[1] as isize);
+            if coff0 >= 0 {
+                let imw = if tone.cutoff == 0 { -wave[0] } else { wave[0] };
+                self.sbuf[ch][coff0 as usize].re += val.re * wave[0];
+                self.sbuf[ch][coff0 as usize].im += val.im * imw;
+            }
+            if coff1 >= 0 {
+                let imw = if tone.cutoff <= 1 { -wave[1] } else { wave[1] };
+                self.sbuf[ch][coff1 as usize].re += val.re * wave[1];
+                self.sbuf[ch][coff1 as usize].im += val.im * imw;
+            }
+            for i in 0..4 {
+                self.sbuf[ch][off + i] += val.scale(wave[i + 2]);
+            }
+        }
+        tone.time += 1;
+        if tone.time >= (1 << (5 - tone.grp)) - 1 {
+            tone.used = false;
+        }
+    }
+    fn synth_tone(&mut self, tone: &mut Tone, cutoff: usize, scale: f32, off: usize, grp: usize) -> Option<OldTone> {
+        let mut old_tone = OldTone {
+                used:       true,
+                phase:      64 * i32::from(tone.phase) - (off as i32) * 256 - 128,
+                phase_add:  (2 * i32::from(tone.freq) + 1) << (grp + 3),
+                grp:        grp as u8,
+                time:       0,
+                scale,
+                cutoff,
+                offset:     off as u8,
+                ch:         tone.ch,
+                freq:       tone.freq,
+            };
+        self.synth_old_tone(&mut old_tone);
+        if old_tone.used {
+            Some(old_tone)
+        } else {
+            None
+        }
+    }
+    fn synth_tone4(&mut self, tone: Tone, scale: f32) {
+        let ch = tone.ch as usize;
+        let val = FFTComplex::exp(f32::from(tone.phase) * PI * 0.25).scale(scale);
+        let offset = tone.freq as usize;
+        self.sbuf[ch][offset]     += val;
+        self.sbuf[ch][offset + 1] -= val;
+    }
+    fn synth_rdft(&mut self, dst: &mut [f32], ch: usize, len: usize) {
+        self.sbuf[ch][0].re *= 2.0;
+        self.sbuf[ch][0].im  = 0.0;
+        self.rdft.do_rdft_inplace(&mut self.sbuf[ch]);
+        let scale = 1.0 / 2.0;
+        for ((src, dly), dst) in self.sbuf[ch].iter().take(len / 2).zip(self.delay[ch].chunks(2)).zip(dst.chunks_mut(2)) {
+            dst[0] += src.re * scale + dly[0];
+            dst[1] += src.im * scale + dly[1];
+        }
+        for (src, dly) in self.sbuf[ch].iter().skip(len / 2).take(len / 2).zip(self.delay[ch].chunks_mut(2)) {
+            dly[0] = src.re * scale;
+            dly[1] = src.im * scale;
+        }
+    }
+}
+
+pub struct QDM2FFT {
+    cbs:                Codebooks,
+    synth:              Synth,
+    packet_size:        usize,
+    frame_size:         usize,
+    channels:           usize,
+    subsampling:        u8,
+    freq_range:         usize,
+
+    fft_levels:         [u8; 6],
+
+    tones:              [Vec<Tone>; 5],
+    tone_start:         [usize; 5],
+    old_tones:          Vec<OldTone>,
+
+    pub is_intra:       bool,
+    frame_bits:         u8,
+}
+
+impl QDM2FFT {
+    pub fn new() -> Self {
+        Self {
+            cbs:            Codebooks::new(),
+            synth:          Synth::new(),
+            packet_size:    0,
+            frame_size:     0,
+            channels:       0,
+            subsampling:    0,
+            freq_range:     0,
+
+            fft_levels:     [0; 6],
+            tones:          [Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES),
+                             Vec::with_capacity(MAX_TONES)],
+            tone_start:     [0; 5],
+            old_tones:      Vec::new(),
+
+            is_intra:       false,
+            frame_bits:     0,
+        }
+    }
+    pub fn set_params(&mut self, channels: usize, packet_size: usize, subsampling: u8) {
+        self.subsampling = subsampling;
+        self.channels = channels;
+        self.synth.rdft = RDFTBuilder::new_rdft(packet_size, false, true);
+        self.packet_size = packet_size;
+        self.frame_size = packet_size * 16;
+        self.frame_bits = (31 - (self.frame_size.leading_zeros() & 31)) as u8;
+        self.freq_range = 255 >> (2 - self.subsampling);
+    }
+    pub fn read_type_13(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        for el in self.fft_levels.iter_mut() {
+            *el                 = br.read(6) as u8;
+        }
+        Ok(())
+    }
+    pub fn read_type_14(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        for el in self.fft_levels.iter_mut() {
+            *el                 = br.read_code(&self.cbs.level_exp_cb)? as u8;
+        }
+        Ok(())
+    }
+    fn read_tones(&mut self, br: &mut QdmBitReader, group: usize, use_cb2: bool) -> DecoderResult<()> {
+        let group_bits = 4 - group;
+        let group_size = 1 << (self.frame_bits - (group as u8));
+        let mut freq = 1;
+        let mut pos2 = 0;
+        let mut offset = 0;
+        let level_cb = if use_cb2 { &self.cbs.level_exp_cb } else { &self.cbs.level_exp_alt_cb };
+        while freq < self.frame_size {
+            if self.is_intra {
+                let mut diff = 0;
+                while diff < 2 {
+                    diff                = br.read_code_long(&self.cbs.group_cb[group_bits])?;
+                    if diff >= 2 { break; }
+                    freq = 1;
+                    if diff == 0 {
+                        pos2    += group_size;
+                        offset  += 1 << group_bits;
+                    } else {
+                        pos2    += 8 * group_size;
+                        offset  += 8 << group_bits;
+                    }
+                    if pos2 >= self.frame_size {
+                        return Ok(());
+                    }
+                }
+                freq += (diff - 2) as usize;
+            } else {
+                let diff                = br.read_code_long(&self.cbs.group_cb[group_bits])?;
+                freq += diff as usize;
+                while freq >= group_size - 1 {
+                    freq   -= group_size - 2;
+                    pos2   += group_size;
+                    offset += 1 << group_bits;
+                }
+            }
+            if pos2 >= self.frame_size {
+                return Ok(());
+            }
+
+            let pos = freq >> group_bits;
+            if pos > LEVEL_INDEX.len() - 1 {
+                return Ok(());
+            }
+            let stereo_mode = if self.channels == 2 {
+                                        br.read(2) as u8
+                    } else { 0 };
+
+            let mut amp                 = br.read_code(&level_cb)? as i8;
+            amp += self.fft_levels[LEVEL_INDEX[pos] as usize] as i8;
+            if amp < 0 {
+                amp = 0;
+            }
+            let phase                   = br.read(3) as u8;
+            let (amp2, phase2) = if stereo_mode > 1 {
+                    let amp_diff        = br.read_code(&self.cbs.stereo_exp_cb)? as i8;
+                    let phase_diff      = br.read_code(&self.cbs.phase_diff_cb)? as i8;
+                    let mut p2 = (phase as i8) - phase_diff;
+                    if p2 < 0 { p2 += 8; }
+                    (amp - amp_diff, p2 as u8)
+                } else { (0, 0) };
+
+            if pos <= self.freq_range {
+                if self.tones[group].len() >= MAX_TONES { return Ok(()); }
+                self.tones[group].push(Tone { freq: freq as u16, offset, phase, ch: stereo_mode & 1, amp_idx: amp as u8 });
+                if stereo_mode > 1 {
+                    if self.tones[group].len() >= MAX_TONES { return Ok(()); }
+                    self.tones[group].push(Tone { freq: freq as u16, offset, phase: phase2, ch: !stereo_mode & 1, amp_idx: amp2 as u8 });
+                }
+            }
+
+            freq += 1;
+        }
+        Ok(())
+    }
+    pub fn new_frame(&mut self) {
+        for tones in self.tones.iter_mut() {
+            tones.clear();
+        }
+        self.tone_start = [0; 5];
+    }
+    pub fn read_fft_packet(&mut self, id: u8, br: &mut QdmBitReader) -> DecoderResult<()> {
+        match id {
+            17..=23 => {
+                let grp = i16::from(self.subsampling) + 4 - i16::from(id - 17);
+                if grp >= 0 && grp < 5 {
+                    self.read_tones(br, grp as usize, false)?;
+                }
+            },
+            31 => {
+                for grp in 0..5 {
+                    self.read_tones(br, grp, false)?;
+                }
+            },
+            33..=39 => {
+                let grp = i16::from(self.subsampling) + 4 - i16::from(id - 33);
+                if grp >= 0 && grp < 5 {
+                    self.read_tones(br, grp as usize, true)?;
+                }
+            },
+            46 => {
+                for el in self.fft_levels.iter_mut() {
+                    *el                 = br.read(6) as u8;
+                }
+                for grp in 0..5 {
+                    self.read_tones(br, grp, true)?;
+                }
+            },
+            _ => {},
+        };
+        Ok(())
+    }
+    pub fn generate_tones(&mut self, sf: usize) {
+        self.synth.new_sf();
+        self.old_tones.retain(|el| el.used);
+
+        for otone in self.old_tones.iter_mut() {
+            self.synth.synth_old_tone(otone);
+        }
+
+        let sf_idx = (sf + 0xE) & 0xF;
+        let scales = if self.is_intra { &TONE_SCALES[0] } else { &TONE_SCALES[1] };
+        for group in 0..4 {
+            let group_bits = 4 - group;
+            for tone in self.tones[group].iter_mut().skip(self.tone_start[group]) {
+                if (tone.offset as usize) > sf_idx {
+                    break;
+                }
+
+                let off = (tone.freq >> group_bits) as usize;
+                if off < self.freq_range {
+                    let cutoff = if off < 2 { off } else if off < 60 { 2 } else { 3 };
+                    let scale = scales[(tone.amp_idx & 0x3F) as usize];
+                    let otone = self.synth.synth_tone(tone, cutoff, scale, off, group);
+                    if let Some(otone) = otone {
+                        self.old_tones.push(otone);
+                    }
+                }
+
+                self.tone_start[group] += 1;
+            }
+        }
+        {
+            let group = 4;
+            for tone in self.tones[group].iter().skip(self.tone_start[group]) {
+                if (tone.offset as usize) > sf_idx {
+                    break;
+                }
+                let scale = scales[(tone.amp_idx & 0x3F) as usize];
+                self.synth.synth_tone4(*tone, scale);
+                self.tone_start[group] += 1;
+            }
+        }
+    }
+    pub fn synth(&mut self, dst: &mut [f32], ch: usize) {
+        self.synth.synth_rdft(dst, ch, self.packet_size);
+    }
+    pub fn flush(&mut self) {
+    }
+}
+
+const FFT_GROUP_CODES: [&[u16]; 5] = [
+  &[
+    0x038E, 0x0001, 0x0000, 0x0022, 0x000A, 0x0006, 0x0012, 0x0002,
+    0x001E, 0x003E, 0x0056, 0x0016, 0x000E, 0x0032, 0x0072, 0x0042,
+    0x008E, 0x004E, 0x00F2, 0x002E, 0x0036, 0x00C2, 0x018E
+  ],
+  &[
+    0x07A4, 0x0001, 0x0020, 0x0012, 0x001C, 0x0008, 0x0006, 0x0010,
+    0x0000, 0x0014, 0x0004, 0x0032, 0x0070, 0x000C, 0x0002, 0x003A,
+    0x001A, 0x002C, 0x002A, 0x0022, 0x0024, 0x000A, 0x0064, 0x0030,
+    0x0062, 0x00A4, 0x01A4, 0x03A4
+  ],
+  &[
+    0x1760, 0x0001, 0x0000, 0x0082, 0x000C, 0x0006, 0x0003, 0x0007,
+    0x0008, 0x0004, 0x0010, 0x0012, 0x0022, 0x001A, 0x0000, 0x0020,
+    0x000A, 0x0040, 0x004A, 0x006A, 0x002A, 0x0042, 0x0002, 0x0060,
+    0x00AA, 0x00E0, 0x00C2, 0x01C2, 0x0160, 0x0360, 0x0760, 0x0F60
+  ],
+  &[
+    0x33EA, 0x0005, 0x0000, 0x000C, 0x0000, 0x0006, 0x0003, 0x0008,
+    0x0002, 0x0001, 0x0004, 0x0007, 0x001A, 0x000F, 0x001C, 0x002C,
+    0x000A, 0x001D, 0x002D, 0x002A, 0x000D, 0x004C, 0x008C, 0x006A,
+    0x00CD, 0x004D, 0x00EA, 0x020C, 0x030C, 0x010C, 0x01EA, 0x07EA,
+    0x0BEA, 0x03EA, 0x13EA
+  ],
+  &[
+    0x5282, 0x0016, 0x0000, 0x0136, 0x0004, 0x0000, 0x0007, 0x000A,
+    0x000E, 0x0003, 0x0001, 0x000D, 0x0006, 0x0009, 0x0012, 0x0005,
+    0x0025, 0x0022, 0x0015, 0x0002, 0x0076, 0x0035, 0x0042, 0x00C2,
+    0x0182, 0x00B6, 0x0036, 0x03C2, 0x0482, 0x01C2, 0x0682, 0x0882,
+    0x0A82, 0x0082, 0x0282, 0x1282, 0x3282, 0x2282
+  ]
+];
+const FFT_GROUP_BITS: [&[u8]; 5] = [
+  &[
+    10,  1,  2,  6,  4,  5,  6,  7,  6,  6,  7,  7,  8,  7,  8,  8,
+     9,  7,  8,  6,  6,  8, 10
+  ],
+  &[
+    11,  1,  6,  6,  5,  4,  3,  6,  6,  5,  6,  6,  7,  6,  6,  6,
+     6,  6,  6,  7,  8,  6,  7,  7,  7,  9, 10, 11
+  ],
+  &[
+    13,  2,  0,  8,  4,  3,  3,  3,  4,  4,  5,  5,  6,  5,  7,  7,
+     7,  7,  7,  7,  8,  8,  8,  9,  8,  8,  9,  9, 10, 11, 13, 12
+  ],
+  &[
+    14,  4,  0, 10,  4,  3,  3,  4,  4,  3,  4,  4,  5,  4,  5,  6,
+     6,  5,  6,  7,  7,  7,  8,  8,  8,  8,  9, 10, 10, 10, 10, 11,
+    12, 13, 14
+  ],
+  &[
+    15,  6,  0,  9,  3,  3,  3,  4,  4,  3,  4,  4,  5,  4,  5,  6,
+     6,  6,  6,  8,  7,  6,  8,  9,  9,  8,  9, 10, 11, 10, 11, 12,
+    12, 12, 14, 15, 14, 14
+  ]
+];
+
+const FFT_LEVEL_EXP_ALT_CODES: &[u16; 28] = &[
+    0x1EC6, 0x0006, 0x00C2, 0x0142, 0x0242, 0x0246, 0x00C6, 0x0046,
+    0x0042, 0x0146, 0x00A2, 0x0062, 0x0026, 0x0016, 0x000E, 0x0005,
+    0x0004, 0x0003, 0x0000, 0x0001, 0x000A, 0x0012, 0x0002, 0x0022,
+    0x01C6, 0x02C6, 0x06C6, 0x0EC6
+];
+const FFT_LEVEL_EXP_ALT_BITS: &[u8; 28] = &[
+    13,  7,  8,  9, 10, 10, 10, 10, 10,  9,  8,  7,  6,  5,  4,  3,
+     3,  2,  3,  3,  4,  5,  7,  8,  9, 11, 12, 13
+];
+
+const FFT_LEVEL_EXP_CODES: &[u16; 20] = &[
+    0x0F24, 0x0001, 0x0002, 0x0000, 0x0006, 0x0005, 0x0007, 0x000C,
+    0x000B, 0x0014, 0x0013, 0x0004, 0x0003, 0x0023, 0x0064, 0x00A4,
+    0x0024, 0x0124, 0x0324, 0x0724
+];
+const FFT_LEVEL_EXP_BITS: &[u8; 20] = &[
+    12, 3, 3, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 8, 9, 10, 11, 12
+];
+
+const FFT_STEREO_EXP_CODES: &[u8; 7] = &[ 0x3E, 0x01, 0x00, 0x02, 0x06, 0x0E, 0x1E ];
+const FFT_STEREO_EXP_BITS: &[u8; 7] = &[ 6, 1, 2, 3, 4, 5, 6 ];
+
+const FFT_STEREO_PHASE_CODES: &[u8; 9] = &[
+    0x35, 0x02, 0x00, 0x01, 0x0D, 0x15, 0x05, 0x09, 0x03
+];
+const FFT_STEREO_PHASE_BITS: &[u8; 9] = &[ 6, 2, 2, 4, 4, 6, 5, 4, 2 ];
+
+const CUTOFF_INDICES: [[i8; 2]; 4] = [ [1, 2], [-1, 0], [-1,-2], [0, 0] ];
+
+const LEVEL_INDEX: [u8; 256] = [
+    0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+    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, 3, 3, 3, 3, 3, 3, 3, 3,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+    4, 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, 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, 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, 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, 5, 5, 5, 5,
+    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
+];
+
+const FFT_TONE_SAMPLES: [[[f32; 5]; 16]; 4] = [
+  [
+    [ 0.0100000000,-0.0037037037,-0.0020000000,-0.0069444444,-0.0018416207 ],
+    [ 0.0416666667, 0.0000000000, 0.0000000000,-0.0208333333,-0.0123456791 ],
+    [ 0.1250000000, 0.0558035709, 0.0330687836,-0.0164473690,-0.0097465888 ],
+    [ 0.1562500000, 0.0625000000, 0.0370370370,-0.0062500000,-0.0037037037 ],
+    [ 0.1996007860, 0.0781250000, 0.0462962948, 0.0022727272, 0.0013468013 ],
+    [ 0.2000000000, 0.0625000000, 0.0370370373, 0.0208333333, 0.0074074073 ],
+    [ 0.2127659619, 0.0555555556, 0.0329218097, 0.0208333333, 0.0123456791 ],
+    [ 0.2173913121, 0.0473484844, 0.0280583613, 0.0347222239, 0.0205761325 ],
+    [ 0.2173913121, 0.0347222239, 0.0205761325, 0.0473484844, 0.0280583613 ],
+    [ 0.2127659619, 0.0208333333, 0.0123456791, 0.0555555556, 0.0329218097 ],
+    [ 0.2000000000, 0.0208333333, 0.0074074073, 0.0625000000, 0.0370370370 ],
+    [ 0.1996007860, 0.0022727272, 0.0013468013, 0.0781250000, 0.0462962948 ],
+    [ 0.1562500000,-0.0062500000,-0.0037037037, 0.0625000000, 0.0370370370 ],
+    [ 0.1250000000,-0.0164473690,-0.0097465888, 0.0558035709, 0.0330687836 ],
+    [ 0.0416666667,-0.0208333333,-0.0123456791, 0.0000000000, 0.0000000000 ],
+    [ 0.0100000000,-0.0069444444,-0.0018416207,-0.0037037037,-0.0020000000 ]
+  ], [
+    [ 0.0050000000,-0.0200000000, 0.0125000000,-0.3030303030, 0.0020000000 ],
+    [ 0.1041666642, 0.0400000000,-0.0250000000, 0.0333333333,-0.0200000000 ],
+    [ 0.1250000000, 0.0100000000, 0.0142857144,-0.0500000007,-0.0200000000 ],
+    [ 0.1562500000,-0.0006250000,-0.00049382716,-0.000625000,-0.00049382716 ],
+    [ 0.1562500000,-0.0006250000,-0.00049382716,-0.000625000,-0.00049382716 ],
+    [ 0.1250000000,-0.0500000000,-0.0200000000, 0.0100000000, 0.0142857144 ],
+    [ 0.1041666667, 0.0333333333,-0.0200000000, 0.0400000000,-0.0250000000 ],
+    [ 0.0050000000,-0.3030303030, 0.0020000001,-0.0200000000, 0.0125000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ]
+  ], [
+    [ 0.1428571492, 0.1250000000,-0.0285714287,-0.0357142873, 0.0208333333 ],
+    [ 0.1818181818, 0.0588235296, 0.0333333333, 0.0212765951, 0.0100000000 ],
+    [ 0.1818181818, 0.0212765951, 0.0100000000, 0.0588235296, 0.0333333333 ],
+    [ 0.1428571492,-0.0357142873, 0.0208333333, 0.1250000000,-0.0285714287 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ]
+  ], [
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ],
+    [ 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000, 0.0000000000 ]
+  ]
+];
+
+const TONE_ENVELOPE: [[f32; 31]; 4] = [
+  [
+    0.009607375, 0.038060248, 0.084265202, 0.146446645,
+    0.222214907, 0.308658302, 0.402454883, 0.500000060,
+    0.597545207, 0.691341758, 0.777785182, 0.853553414,
+    0.915734828, 0.961939812, 0.990392685, 1.00000000,
+    0.990392625, 0.961939752, 0.915734768, 0.853553295,
+    0.777785063, 0.691341639, 0.597545087, 0.500000000,
+    0.402454853, 0.308658272, 0.222214878, 0.146446615,
+    0.084265172, 0.038060218, 0.009607345
+  ], [
+    0.038060248, 0.146446645, 0.308658302, 0.500000060,
+    0.691341758, 0.853553414, 0.961939812, 1.00000000,
+    0.961939752, 0.853553295, 0.691341639, 0.500000000,
+    0.308658272, 0.146446615, 0.038060218, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000
+  ], [
+    0.146446645, 0.500000060, 0.853553414, 1.00000000,
+    0.853553295, 0.500000000, 0.146446615, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000
+  ], [
+    0.500000060, 1.00000000,  0.500000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000, 0.000000000,
+    0.000000000, 0.000000000, 0.000000000
+  ]
+];
diff --git a/nihav-qt/src/codecs/qdm2qmf.rs b/nihav-qt/src/codecs/qdm2qmf.rs
new file mode 100644 (file)
index 0000000..ece74c2
--- /dev/null
@@ -0,0 +1,806 @@
+use nihav_core::codecs::*;
+use nihav_core::io::codebook::*;
+use nihav_codec_support::dsp::qmf::QMF;
+use super::qdmcommon::*;
+use super::qdm2::TONE_SCALES;
+
+const MAX_BANDS: usize = 30;
+
+const NOISE_TAB_LEN: usize = 3840;
+
+struct NoiseGen {
+    noise_tab:          [f32; NOISE_TAB_LEN],
+    idx:                usize,
+}
+
+impl NoiseGen {
+    fn new() -> Self {
+        let mut noise_tab = [0.0; NOISE_TAB_LEN];
+        let mut rnd = RNG::new();
+        for el in noise_tab.iter_mut() {
+            *el = rnd.next_float() * 1.3;
+        }
+
+        Self { noise_tab, idx: 0 }
+    }
+    fn next(&mut self, band: usize) -> f32 {
+        let ret = self.noise_tab[self.idx];
+        self.idx += 1;
+        if self.idx >= NOISE_TAB_LEN {
+            self.idx -= NOISE_TAB_LEN;
+        }
+        ret * SB_NOISE_ATTENUATION[band]
+    }
+}
+
+struct Tables {
+    noise_samples:  [f32; 128],
+    mod3:           [[u8; 5]; 243],
+    mod5:           [[u8; 3]; 125],
+}
+
+impl Tables {
+    fn new() -> Self {
+        let mut noise_samples = [0.0; 128];
+        let mut rnd = RNG::new();
+        for el in noise_samples.iter_mut() {
+            *el = rnd.next_float();
+        }
+
+        let mut mod3 = [[0u8; 5]; 243];
+        for (i, row) in mod3.iter_mut().enumerate() {
+            let mut base = 81u8;
+            let mut low = i as u8;
+            for el in row.iter_mut() {
+                *el = low / base;
+                low %= base;
+                base /= 3;
+            }
+        }
+
+        let mut mod5 = [[0u8; 3]; 125];
+        for (i, row) in mod5.iter_mut().enumerate() {
+            let mut base = 25u8;
+            let mut low = i as u8;
+            for el in row.iter_mut() {
+                *el = low / base;
+                low %= base;
+                base /= 5;
+            }
+        }
+
+        Self {
+            noise_samples, mod3, mod5,
+        }
+    }
+}
+
+struct Codebooks {
+    level_cb:               Codebook<u8>,
+    level_diff_cb:          Codebook<u8>,
+    run_cb:                 Codebook<u8>,
+    tone_idx_mid_cb:        Codebook<u8>,
+    tone_idx_high1_cb:      Codebook<u8>,
+    tone_idx_high2_cb:      Codebook<u8>,
+    type30_codes_cb:        Codebook<u8>,
+    type34_codes_cb:        Codebook<u8>,
+}
+
+fn map_idx(idx: usize) -> u8 { idx as u8 }
+
+macro_rules! create_codebook {
+    ($codes: expr, $bits: expr) => ({
+        let mut cbr = TableCodebookDescReader::new($codes, $bits, map_idx);
+        Codebook::new(&mut cbr, CodebookMode::LSB).unwrap()
+    })
+}
+
+impl Codebooks {
+    fn new() -> Self {
+        let level_cb = create_codebook!(LEVEL_CODES, LEVEL_BITS);
+        let level_diff_cb = create_codebook!(LEVEL_DIFF_CODES, LEVEL_DIFF_BITS);
+        let run_cb = create_codebook!(RUN_CODES, RUN_BITS);
+
+        let tone_idx_mid_cb = create_codebook!(TONE_IDX_MID_CODES, TONE_IDX_MID_BITS);
+        let tone_idx_high1_cb = create_codebook!(TONE_IDX_HIGH1_CODES, TONE_IDX_HIGH1_BITS);
+        let tone_idx_high2_cb = create_codebook!(TONE_IDX_HIGH2_CODES, TONE_IDX_HIGH2_BITS);
+
+        let type30_codes_cb = create_codebook!(TYPE30_CODES, TYPE30_BITS);
+        let type34_codes_cb = create_codebook!(TYPE34_CODES, TYPE34_BITS);
+        Self {
+            level_cb, level_diff_cb, run_cb,
+            tone_idx_mid_cb, tone_idx_high1_cb, tone_idx_high2_cb,
+            type30_codes_cb, type34_codes_cb,
+        }
+    }
+}
+
+pub struct QDM2QMF {
+    qmf:        [QMF; 2],
+    cbs:        Codebooks,
+    tables:     Tables,
+    noisegen:   NoiseGen,
+
+    pub is_intra:       bool,
+
+    num_bands:          usize,
+    subsampling:        u8,
+    cm_selector:        usize,
+    coef_per_sb_sel:    usize,
+    channels:           usize,
+
+    grid_2_quant:       [[[i8; 8]; 10]; 2],
+    grid_1_quant:       [[[[i8; 8]; 8]; 3]; 2],
+    grid_3_quant:       [[i8; MAX_BANDS]; 2],
+    tone_idx_mid:       [[[i8; 8]; MAX_BANDS]; 2],
+    tone_idx_base:      [[[i8; 8]; MAX_BANDS]; 2],
+    tone_idx:           [[[i8; 64]; MAX_BANDS]; 2],
+    quant_weight:       [[[u8; 64]; MAX_BANDS]; 2],
+    sb_samples:         [[[f32; 32]; 128]; 2],
+    tone_scale:         [[[f32; 64]; MAX_BANDS]; 2],
+}
+
+impl QDM2QMF {
+    pub fn new() -> Self {
+        Self {
+            qmf:        [QMF::new(), QMF::new()],
+            cbs:        Codebooks::new(),
+            tables:     Tables::new(),
+            noisegen:   NoiseGen::new(),
+
+            num_bands:          0,
+            subsampling:        0,
+            cm_selector:        0,
+            coef_per_sb_sel:    0,
+            channels:           0,
+            is_intra:           false,
+
+            grid_2_quant:       [[[0; 8]; 10]; 2],
+            grid_1_quant:       [[[[0; 8]; 8]; 3]; 2],
+            grid_3_quant:       [[0; MAX_BANDS]; 2],
+            tone_idx_mid:       [[[0; 8]; MAX_BANDS]; 2],
+            tone_idx_base:      [[[0; 8]; MAX_BANDS]; 2],
+            tone_idx:           [[[0; 64]; MAX_BANDS]; 2],
+            quant_weight:       [[[0; 64]; MAX_BANDS]; 2],
+            sb_samples:         [[[0.0; 32]; 128]; 2],
+            tone_scale:         [[[0.0; 64]; MAX_BANDS]; 2],
+        }
+    }
+    pub fn set_ch_and_subsampling(&mut self, channels: usize, subsampling: u8, full_bitrate: u32) {
+        self.channels    = channels;
+        self.subsampling = subsampling;
+        self.num_bands   = (8 << self.subsampling).min(MAX_BANDS);
+
+        let br = match self.subsampling * 2 + (channels as u8) - 1 {
+                0 => 40,
+                1 => 48,
+                2 => 56,
+                3 => 72,
+                4 => 80,
+                5 => 100,
+                _ => unreachable!(),
+            };
+        self.cm_selector = if br * 1000 < full_bitrate {
+                1
+            } else if br * 1440 < full_bitrate {
+                2
+            } else if br * 1760 < full_bitrate {
+                3
+            } else if br * 2240 < full_bitrate {
+                4
+            } else {
+                0
+            };
+        self.coef_per_sb_sel = if full_bitrate <= 8000 { 0 } else if full_bitrate < 16000 { 1 } else { 2 };
+    }
+    fn average_grid_quants(&mut self) {
+        let ncoef = (COEFFS_PER_SB_AVG[self.coef_per_sb_sel][self.subsampling as usize] as usize) + 1;
+        for ch in 0..self.channels {
+            for i in 0..ncoef {
+                let mut sum = 0;
+                for el in self.grid_2_quant[ch][i].iter() {
+                    sum += i16::from(*el);
+                }
+                sum /= 8;
+                if sum > 0 {
+                    sum -= 1;
+                }
+                self.grid_2_quant[ch][i] = [sum as i8; 8];
+            }
+        }
+    }
+    fn read_array(br: &mut QdmBitReader, dst: &mut [i8; 8], codebooks: &Codebooks) -> DecoderResult<()> {
+        if br.left() < 15 { return Ok(()); }
+        let mut last                    = br.read_code(&codebooks.level_cb)? as i32;
+        dst[0] = last as i8;
+        let mut idx = 1;
+        while idx < 8 {
+            let len                     = (br.read_code(&codebooks.run_cb)? as usize) + 1;
+            let diff                    = br.read_code(&codebooks.level_diff_cb)? as i32;
+            let diff = to_signed(diff);
+            let val = last + diff;
+            validate!(len + idx <= 8);
+            for i in 1..=len {
+                dst[idx] = (last + (i as i32) * diff / (len as i32)) as i8;
+                idx += 1;
+            }
+            last = val;
+        }
+        Ok(())
+    }
+    pub fn read_type_9(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        let nbands = (COEFFS_PER_SB_AVG[self.coef_per_sb_sel][self.subsampling as usize] as usize) + 1;
+        for i in 1..nbands {
+            for ch in 0..self.channels {
+                Self::read_array(br, &mut self.grid_2_quant[ch][i], &self.cbs)?;
+            }
+        }
+        for ch in 0..self.channels {
+            self.grid_2_quant[ch][0] = [0; 8];
+        }
+        Ok(())
+    }
+    pub fn read_type_10(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        for ch in 0..self.channels {
+            let _ret = Self::read_array(br, &mut self.grid_2_quant[ch][0], &self.cbs);
+            if br.left() < 16 {
+                self.grid_2_quant[ch][0] = [0; 8];
+                break;
+            }
+        }
+
+        let n = (self.subsampling as usize) + 1;
+        for band in 0..n {
+            for ch in 0..self.channels {
+                for i in 0..8 {
+                    if br.read_bool() {
+                        for el in self.grid_1_quant[ch][band][i].iter_mut() {
+                            *el         = br.read_code(&self.cbs.tone_idx_high1_cb)? as i8;
+                        }
+                    } else {
+                        self.grid_1_quant[ch][band][i] = [0; 8];
+                    }
+                }
+            }
+        }
+        for band in 0..self.num_bands - 4 {
+            for ch in 0..self.channels {
+                if br.left() < 16 { break; }
+                self.grid_3_quant[ch][band] = br.read_code(&self.cbs.tone_idx_high2_cb)? as i8;
+                if band > 19 {
+                    self.grid_3_quant[ch][band] -= 16;
+                } else {
+                    self.tone_idx_mid[ch][band] = [-16; 8];
+                }
+            }
+        }
+        for band in 0..self.num_bands - 5 {
+            for ch in 0..self.channels {
+                for i in 0..8 {
+                    if br.left() < 16 { break; }
+                    self.tone_idx_mid[ch][band][i] = (br.read_code(&self.cbs.tone_idx_mid_cb)? as i8) - 32;
+                }
+            }
+        }
+
+        self.set_tone_scales(true);
+        Ok(())
+    }
+    fn inc_quant_weight(&mut self, band: usize) -> bool {
+        let rlen = 128 / self.channels;
+        for ch in 0..self.channels {
+            let mut idx = 0;
+            while idx < rlen {
+                if self.quant_weight[ch][band][idx] < 8 {
+                    return false;
+                }
+                let (val, run) = match self.quant_weight[ch][band][idx] {
+                        8  => (10, 16),
+                        10 => (16, 1),
+                        16 => (24, 5),
+                        24 => (30, 3),
+                        30 => (30, 1),
+                        _  => (8, 1),
+                    };
+                let len = run.min(rlen - idx);
+                let ref_val = self.quant_weight[ch][band][idx];
+                for _ in 0..len {
+                    if self.quant_weight[ch][band + idx / 64][idx % 64] > ref_val {
+                        self.quant_weight[ch][band][idx] = val;
+unimplemented!();
+                    }
+                    idx += 1;
+                }
+            }
+        }
+        true
+    }
+    fn set_tone_scales(&mut self, has_data: bool) {
+        const LAST_COEFF: [usize; 3] = [ 4, 7, 10 ];
+
+        let csel = self.coef_per_sb_sel;
+        for ch in 0..self.channels {
+            for band in 0..MAX_BANDS {
+                for i in 0..8 {
+                    let csb = COEFFS_PER_SB_DEQUANT[csel][band] as usize;
+                    let mut q = i32::from(self.grid_2_quant[ch][csb][i]) * i32::from(DEQUANT[csel][csb][band]);
+                    if csb < LAST_COEFF[csel] - 1 {
+                        q += i32::from(self.grid_2_quant[ch][csb + 1][i]) * i32::from(DEQUANT[csel][csb + 1][band]);
+                    }
+                    if q < 0 {
+                        q += 255;
+                    }
+                    self.tone_idx_base[ch][band][i] = (q / 256) as i8;
+                }
+            }
+        }
+        if !self.is_intra && !has_data {
+            for band in 0..self.num_bands {
+                for ch in 0..self.channels {
+                    for i in 0..64 {
+                        self.tone_idx[ch][band][i] = self.tone_idx[ch][band][i / 8];
+                        if self.tone_idx[ch][band][i] >= 0 {
+                            self.tone_scale[ch][band][i] = TONE_SCALES[0][(self.tone_idx[ch][band][i] & 0x3F) as usize];
+                        } else {
+                            self.tone_scale[ch][band][i] = 0.0;
+                        }
+                    }
+                }
+            }
+        } else {
+            for band in 0..self.num_bands {
+                for ch in 0..self.channels {
+                    for i in 0..64 {
+                        let mut q = self.tone_idx_base[ch][band][i / 8];
+                        if band >= 4 {
+                            q = q.wrapping_sub(self.grid_1_quant[ch][(band / 8).min(2)][i / 8][i % 8]);
+                            if band < 24 {
+                                q = q.wrapping_sub(self.tone_idx_mid[ch][band - 4][i / 8]);
+                            }
+                            q = q.wrapping_sub(self.grid_3_quant[ch][band - 4]);
+                        }
+                        self.tone_idx[ch][band][i] = q as i8;
+                        if q > 0 || (self.is_intra && q == 0) {
+                            self.tone_scale[ch][band][i] = TONE_SCALES[0][(q & 0x3F) as usize];
+                        } else {
+                            self.tone_scale[ch][band][i] = 0.0;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    #[allow(clippy::cyclomatic_complexity)]
+    fn read_noise_band(&mut self, br: &mut QdmBitReader, ch: usize, band: usize, samples: &mut [f32; 10], signs: &[bool; 16], jstereo: bool) -> DecoderResult<()> {
+        let mut type34_first = true;
+        let mut type34_pred = 0.0;
+        let mut type34_scale = 0.0;
+        let zero_coding                 = br.read_bool();
+        let mut idx = 0;
+        while idx < 128 {
+            let len;
+            match self.quant_weight[ch][band][idx / 2] {
+                8 => {
+                    if br.left() >= 10 {
+                        if zero_coding {
+                            for i in 0..5 {
+                                if idx + i * 2 >= 128 { break; }
+                                samples[i * 2] = if br.read_bool() {
+                                        let ix = (br.read(1) as usize) * 2;
+                                        QUANT_1BIT[jstereo as usize][ix]
+                                    } else { 0.0 };
+                            }
+                        } else {
+                            let idx = br.read(8) as usize;
+                            validate!(idx < self.tables.mod3.len());
+                            for i in 0..5 {
+                                let k = self.tables.mod3[idx][i] as usize; 
+                                samples[i * 2] = QUANT_1BIT[jstereo as usize][k];
+                            }
+                        }
+                        for el in samples.chunks_mut(2) {
+                            el[1] = self.noisegen.next(band);
+                        }
+                    } else {
+                        for el in samples.iter_mut() {
+                            *el = self.noisegen.next(band);
+                        }
+                    }
+                    len = 10;
+                },
+                10 => {
+                    if br.left() > 0 {
+                        let mut scale   = if br.read_bool() { -0.81 } else { 0.81 };
+                        scale -= self.tables.noise_samples[((band + 1) * (idx + 5 * ch + 1)) & 0x7F] * 9.0 / 40.0;
+                        samples[0] = scale;
+                    } else {
+                        samples[0] = self.noisegen.next(band);
+                    }
+                    len = 1;
+                },
+                16 => {
+                    if br.left() >= 10 {
+                        if zero_coding {
+                            for i in 0..5 {
+                                if idx + i >= 128 { break; }
+                                samples[i] = if br.read_bool() {
+                                        let ix = (br.read(1) as usize) * 2;
+                                        QUANT_1BIT[jstereo as usize][ix]
+                                    } else { 0.0 };
+                            }
+                        } else {
+                            let idx = br.read(8) as usize;
+                            validate!(idx < self.tables.mod3.len());
+                            for i in 0..5 {
+                                let k = self.tables.mod3[idx][i] as usize; 
+                                samples[i] = QUANT_1BIT[jstereo as usize][k];
+                            }
+                        }
+                    } else {
+                        for el in samples.iter_mut().take(5) {
+                            *el = self.noisegen.next(band);
+                        }
+                    }
+                    len = 5;
+                },
+                24 => {
+                    if br.left() >= 7 {
+                        let idx         = br.read(7) as usize;
+                        validate!(idx < self.tables.mod5.len());
+                        for i in 0..3 {
+                            let k = self.tables.mod5[idx][i] as usize; 
+                            samples[i] = ((k as f32) - 2.0) * 0.5;
+                        }
+                    } else {
+                        for el in samples.iter_mut().take(3) {
+                            *el = self.noisegen.next(band);
+                        }
+                    }
+                    len = 3;
+                },
+                30 => {
+                    if br.left() >= 4 {
+                        let idx         = br.read_code(&self.cbs.type30_codes_cb).unwrap_or(99) as usize;
+                        if idx < QUANT_TYPE30.len() - 1 {
+                            samples[0] = QUANT_TYPE30[idx];
+                        } else {
+                            samples[0] = self.noisegen.next(band);
+                        }
+                    } else {
+                        samples[0] = self.noisegen.next(band);
+                    }
+                    len = 1;
+                },
+                34 => {
+                    if br.left() >= 7 {
+                        if type34_first {
+                            type34_first = false;
+                            type34_scale = 1.0 / ((1 << br.read(2)) as f32);
+                            type34_pred = ((br.read(5) as f32) - 16.0) / 15.0;
+                            samples[0] = type34_pred;
+                        } else {
+                            let idx     = br.read_code(&self.cbs.type34_codes_cb).unwrap_or(99) as usize;
+                            if idx < TYPE34_DIFF.len() - 1 {
+                                samples[0] = type34_pred + TYPE34_DIFF[idx] * type34_scale;
+                                type34_pred = samples[0];
+                            } else {
+                                samples[0] = self.noisegen.next(band);
+                            }
+                        }
+                    } else {
+                        samples[0] = self.noisegen.next(band);
+                    }
+                    len = 1;
+                },
+                _ => {
+                    len = 1;
+                },
+            };
+            let llen = len.min(128 - idx);
+            if !jstereo {
+                for samp in samples.iter().take(llen) {
+                    self.sb_samples[ch][idx][band] = self.tone_scale[ch][band][idx / 2] * *samp;
+                    idx += 1;
+                }
+            } else {
+                for samp in samples.iter().take(llen) {
+                    self.sb_samples[0][idx][band] = self.tone_scale[0][band][idx / 2] * *samp;
+                    if self.channels == 2 {
+                        let sample = if signs[idx / 8] { -*samp } else { *samp };
+                        self.sb_samples[1][idx][band] = self.tone_scale[1][band][idx / 2] * sample;
+                    }
+                    idx += 1;
+                }
+            }
+        }
+        Ok(())
+    }
+    fn read_band_data(&mut self, br: &mut QdmBitReader, start: usize, end: usize) -> DecoderResult<()> {
+        let mut samples = [0.0f32; 10];
+        let mut signs = [false; 16];
+        for band in start..end {
+            let jstereo = if self.channels == 1 || band < 12 {
+                    false
+                } else if band >= 24 {
+                    true
+                } else {
+                                        br.read_bool()
+                };
+            if jstereo {
+                if br.left() >= 16 {
+                    for el in signs.iter_mut() {
+                        *el             = br.read_bool();
+                    }
+                }
+                for i in 0..64 {
+                    self.quant_weight[0][band][i] = self.quant_weight[0][band][i].max(self.quant_weight[1][band][i]);
+                }
+                if !self.inc_quant_weight(band) {
+                    self.fill_noise(band);
+                    continue;
+                }
+            }
+
+            let band_chan = if jstereo { 1 } else { self.channels };
+            for ch in 0..band_chan {
+                self.read_noise_band(br, ch, band, &mut samples, &signs, jstereo)?;
+            }
+        }
+        Ok(())
+    }
+    fn fill_noise(&mut self, band: usize) {
+        for ch in 0..self.channels {
+            for i in 0..128 {
+                self.sb_samples[ch][i][band] = self.noisegen.next(band) * self.tone_scale[ch][band][i / 2];
+            }
+        }
+    }
+    pub fn read_type_11(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        if br.left() >= 32 {
+            let c                       = br.read(13);
+            if c > 3 {
+                if self.is_intra {
+                    for ch in 0..self.channels {
+                        for band in 0..MAX_BANDS {
+                            let sb = QUANT_WEIGHT[self.cm_selector][band];
+                            self.quant_weight[ch][band] = [sb; 64];
+                        }
+                    }
+                } else {
+unimplemented!();
+                }
+            }
+        }
+        self.read_band_data(br, 0, 8)?;
+        Ok(())
+    }
+    pub fn read_type_12(&mut self, br: &mut QdmBitReader) -> DecoderResult<()> {
+        self.read_band_data(br, 8, self.num_bands)?;
+        Ok(())
+    }
+    pub fn fill_default(&mut self, id: u8) {
+        match id {
+            10 => {
+                self.set_tone_scales(false);
+            },
+            11 => {
+                for band in 0..8 {
+                    self.fill_noise(band);
+                }
+            },
+            12 => {
+                for band in 8..self.num_bands {
+                    self.fill_noise(band);
+                }
+            },
+            _ => {},
+        };
+    }
+    pub fn new_frame(&mut self) {
+        self.grid_1_quant = [[[[0; 8]; 8]; 3]; 2];
+        self.grid_3_quant = [[0; MAX_BANDS]; 2];
+        self.tone_idx_mid = [[[0; 8]; MAX_BANDS]; 2];
+        self.average_grid_quants();
+    }
+    pub fn synth(&mut self, dst: &mut [f32], sf: usize, ch: usize) {
+        let mut osamps = [0.0f32; 32 * 8];
+        let ssamp = 4 >> self.subsampling;
+        for (i, out) in osamps.chunks_mut(32).enumerate() {
+            self.qmf[ch].synth(&self.sb_samples[ch][sf * 8 + i], out);
+        }
+        let scale = 1.0 / ((1 << self.subsampling) as f32);
+        for (src, dst) in osamps.chunks(ssamp).zip(dst.iter_mut()) {
+            *dst += src[0] * scale;
+        }
+    }
+    pub fn flush(&mut self) {
+        for qmf in self.qmf.iter_mut() {
+            qmf.reset();
+        }
+    }
+}
+
+const LEVEL_CODES: &[u16; 24] = &[
+    0x37C, 0x004, 0x03C, 0x04C, 0x03A, 0x02C, 0x01C, 0x01A,
+    0x024, 0x014, 0x001, 0x002, 0x000, 0x003, 0x007, 0x005,
+    0x006, 0x008, 0x009, 0x00A, 0x00C, 0x0FC, 0x07C, 0x17C
+];
+const LEVEL_BITS: &[u8; 24] = &[
+    10,  6,  7,  7,  6,  6,  6,  6,  6,  5,  4,  4,  4,  3,  3,  3,
+     3,  4,  4,  5,  7,  8,  9, 10
+];
+
+const LEVEL_DIFF_CODES: &[u16; 37] = &[
+    0x1C57, 0x0004, 0x0000, 0x0001, 0x0003, 0x0002, 0x000F, 0x000E,
+    0x0007, 0x0016, 0x0037, 0x0027, 0x0026, 0x0066, 0x0006, 0x0097,
+    0x0046, 0x01C6, 0x0017, 0x0786, 0x0086, 0x0257, 0x00D7, 0x0357,
+    0x00C6, 0x0386, 0x0186, 0x0000, 0x0157, 0x0C57, 0x0057, 0x0000,
+    0x0B86, 0x0000, 0x1457, 0x0000, 0x0457
+];
+const LEVEL_DIFF_BITS: &[u8; 37] = &[
+    13,  3,  3,  2,  3,  3,  4,  4,  6,  5,  6,  6,  7,  7,  8,  8,
+     8,  9,  8, 11,  9, 10,  8, 10,  9, 12, 10,  0, 10, 13, 11,  0,
+    12,  0, 13,  0, 13
+];
+
+const RUN_CODES: &[u8; 6] = &[ 0x1F, 0x00, 0x01, 0x03, 0x07, 0x0F ];
+const RUN_BITS: &[u8; 6] = &[ 5, 1, 2, 3, 4, 5 ];
+
+const TONE_IDX_HIGH1_CODES: &[u16; 20] = &[
+    0x5714, 0x000C, 0x0002, 0x0001, 0x0000, 0x0004, 0x0034, 0x0054,
+    0x0094, 0x0014, 0x0114, 0x0214, 0x0314, 0x0614, 0x0E14, 0x0F14,
+    0x2714, 0x0714, 0x1714, 0x3714
+];
+const TONE_IDX_HIGH1_BITS: &[u8; 20] = &[
+    15, 4, 2, 1, 3, 5, 6, 7, 8, 10, 10, 11, 11, 12, 12, 12, 14, 14, 15, 14
+];
+
+const TONE_IDX_HIGH2_CODES: &[u16; 24] = &[
+    0x0664, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0064, 0x00E4,
+    0x00A4, 0x0068, 0x0004, 0x0008, 0x0014, 0x0018, 0x0000, 0x0001,
+    0x0002, 0x0003, 0x000C, 0x0028, 0x0024, 0x0164, 0x0000, 0x0264
+];
+const TONE_IDX_HIGH2_BITS: &[u8; 24] = &[
+    11, 0, 0, 0, 0, 0, 10, 8, 8, 7, 6, 6, 5, 5, 4, 2, 2, 2, 4, 7, 8, 9, 0, 11
+];
+
+const TONE_IDX_MID_CODES: &[u16; 24] = &[
+    0x0FEA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x03EA, 0x00EA, 0x002A, 0x001A,
+    0x0006, 0x0001, 0x0000, 0x0002, 0x000A, 0x006A, 0x01EA, 0x07EA
+];
+const TONE_IDX_MID_BITS: &[u8; 24] = &[
+    12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 11,  9,  7,  5,
+     3,  1,  2,  4,  6,  8, 10, 12
+];
+
+const TYPE30_CODES: &[u8; 9] = &[ 0x3C, 0x06, 0x00, 0x01, 0x03, 0x02, 0x04, 0x0C, 0x1C ];
+const TYPE30_BITS: &[u8; 9] = &[ 6, 3, 3, 2, 2, 3, 4, 5, 6 ];
+
+const TYPE34_CODES: &[u8; 10] = &[ 0x18, 0x00, 0x01, 0x04, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08 ];
+const TYPE34_BITS: &[u8; 10] = &[ 5, 4, 3, 3, 3, 3, 3, 3, 3, 5 ];
+
+const SB_NOISE_ATTENUATION: [f32; 32] = [
+    0.0, 0.0, 0.3, 0.4, 0.5, 0.7, 1.0, 1.0,
+    1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+    1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
+    1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
+];
+
+const QUANT_1BIT: [[f32; 3]; 2] = [[ -0.92, 0.0, 0.92 ], [ -0.89, 0.0, 0.89 ]];
+
+const QUANT_TYPE30: [f32; 8] = [
+    -1.0, -0.625, -0.291666656732559, 0.0, 0.25, 0.5, 0.75, 1.0
+];
+
+const TYPE34_DIFF: [f32; 10] = [
+    -1.0, -0.60947573184967, -0.333333343267441, -0.138071194291115, 0.0,
+    0.138071194291115, 0.333333343267441, 0.60947573184967, 1.0, 0.0
+];
+
+const DEQUANT: [[[u16; 30]; 10]; 3] = [
+  [
+    [ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 256, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 51, 102, 154, 205, 256, 238, 219, 201, 183, 165, 146, 128, 110, 91, 73, 55, 37, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 18, 37, 55, 73, 91, 110, 128, 146, 165, 183, 201, 219, 238, 256, 228, 199, 171, 142, 114, 85, 57, 28 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+  ], [
+    [ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 85, 171, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 85, 171, 256, 219, 183, 146, 110, 73, 37, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 73, 110, 146, 183, 219, 256, 228, 199, 171, 142, 114, 85, 57, 28, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 57, 85, 114, 142, 171, 199, 228, 256, 213, 171, 128, 85, 43 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+  ], [
+    [ 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 256, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 256, 171, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 85, 171, 256, 192, 128, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 128, 192, 256, 205, 154, 102, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 102, 154, 205, 256, 213, 171, 128, 85, 43, 0, 0, 0, 0, 0, 0 ],
+    [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 85, 128, 171, 213, 256, 213, 171, 128, 85, 43 ]
+  ]
+];
+
+/*const TONE_LEVEL_IDX_OFFSET: [[i8; 4]; 30] = [
+    [ -50, -50,  0, -50 ],
+    [ -50, -50,  0, -50 ],
+    [ -50,  -9,  0, -19 ],
+    [ -16,  -6,  0, -12 ],
+    [ -11,  -4,  0,  -8 ],
+    [  -8,  -3,  0,  -6 ],
+    [  -7,  -3,  0,  -5 ],
+    [  -6,  -2,  0,  -4 ],
+    [  -5,  -2,  0,  -3 ],
+    [  -4,  -1,  0,  -3 ],
+    [  -4,  -1,  0,  -2 ],
+    [  -3,  -1,  0,  -2 ],
+    [  -3,  -1,  0,  -2 ],
+    [  -3,  -1,  0,  -2 ],
+    [  -2,  -1,  0,  -1 ],
+    [  -2,  -1,  0,  -1 ],
+    [  -2,  -1,  0,  -1 ],
+    [  -2,   0,  0,  -1 ],
+    [  -2,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,  -1 ],
+    [  -1,   0,  0,   0 ],
+    [  -1,   0,  0,   0 ],
+    [  -1,   0,  0,   0 ],
+    [  -1,   0,  0,   0 ]
+];*/
+
+const COEFFS_PER_SB_AVG: [[u8; 4]; 3] = [
+    [ 2, 3, 3, 3 ],
+    [ 4, 5, 6, 6 ],
+    [ 5, 7, 9, 9 ]
+];
+
+/*const COEFFS_PER_SB_AVG: [[u8; 30]; 3] = [
+  [ 0, 1, 1, 1, 1, 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 ],
+  [ 0, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 ],
+  [ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9 ]
+];*/
+
+const COEFFS_PER_SB_DEQUANT: [[u8; 30]; 3] = [
+  [ 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3 ],
+  [ 0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6 ],
+  [ 0, 1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9 ]
+];
+
+const QUANT_WEIGHT: [[u8; 30]; 5] = [
+  [
+    34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+  ], [
+    34, 30, 24, 24, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+  ], [
+    34, 30, 30, 30, 24, 24, 16, 16, 16, 16, 16, 16, 10, 10, 10,
+    10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10
+  ], [
+    34, 34, 30, 30, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16,
+    16, 16, 16, 16, 16, 16, 16, 10, 10, 10, 10, 10, 10, 10, 10
+  ], [
+    34, 34, 30, 30, 30, 30, 30, 30, 24, 24, 24, 24, 24, 24, 24,
+    24, 24, 24, 24, 24, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
+  ]
+];
diff --git a/nihav-qt/src/codecs/qdmc.rs b/nihav-qt/src/codecs/qdmc.rs
new file mode 100644 (file)
index 0000000..818b02f
--- /dev/null
@@ -0,0 +1,481 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_codec_support::dsp::fft::*;
+use super::qdmcommon::*;
+
+const MAX_NOISE_BANDS: usize = 19;
+const MAX_FRAME_SIZE: usize = 8192;
+
+struct QdmcDecoder {
+    ainfo:          NAAudioInfo,
+    chmap:          NAChannelMap,
+    noise_val_cb:   Codebook<u8>,
+    noise_seg_cb:   Codebook<u8>,
+    amp_cb:         Codebook<u8>,
+    amp_diff_cb:    Codebook<u8>,
+    freq_diff_cb:   Codebook<u8>,
+    phase_diff_cb:  Codebook<u8>,
+    sin_tab:        [f32; 512],
+    tone_tab:       [[f32; 32]; 5],
+    rng:            RNG,
+    fft:            FFT,
+    fft_buf:        [[FFTComplex; MAX_FRAME_SIZE * 2]; 2],
+    noise_tab:      [[f32; 256]; MAX_NOISE_BANDS],
+    tmp:            [f32; MAX_FRAME_SIZE],
+    sbuf:           [FFTComplex; 512],
+    delay:          [[f32; 512]; 2],
+
+    noise:          [[[u8; 16]; MAX_NOISE_BANDS]; 2],
+    tones:          [Vec<Tone>; 5],
+
+    order:          u8,
+    frame_bits:     u8,
+    samples:        usize,
+    frm_bytes:      usize,
+    noise_cat:      usize,
+    sf_len:         usize,
+}
+
+fn def_cb_map(idx: usize) -> u8 { idx as u8 }
+fn noise_val_cb_map(idx: usize) -> u8 { NOISE_VAL_SYMS[idx] }
+fn noise_seg_cb_map(idx: usize) -> u8 { NOISE_SEG_SYMS[idx] }
+
+impl QdmcDecoder {
+    fn new() -> Self {
+        let mut cbr = TableCodebookDescReader::new(&NOISE_VAL_CODES, &NOISE_VAL_BITS, noise_val_cb_map);
+        let noise_val_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
+        let mut cbr = TableCodebookDescReader::new(&NOISE_SEG_CODES, &NOISE_SEG_BITS, noise_seg_cb_map);
+        let noise_seg_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
+        let mut cbr = TableCodebookDescReader::new(&FREQ_DIFF_CODES, &FREQ_DIFF_BITS, def_cb_map);
+        let freq_diff_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
+        let mut cbr = TableCodebookDescReader::new(&AMP_CODES, &AMP_BITS, def_cb_map);
+        let amp_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
+        let mut cbr = TableCodebookDescReader::new(&AMP_DIFF_CODES, &AMP_DIFF_BITS, def_cb_map);
+        let amp_diff_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
+        let mut cbr = TableCodebookDescReader::new(&PHASE_DIFF_CODES, &PHASE_DIFF_BITS, def_cb_map);
+        let phase_diff_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap();
+
+        let mut sin_tab = [0.0f32; 512];
+        for (i, tab) in sin_tab.iter_mut().enumerate() {
+            *tab = (2.0 * (i as f32) * std::f32::consts::PI / 512.0).sin();
+        }
+
+        let mut tone_tab = [[0.0; 32]; 5];
+        for group in 0..5 {
+            for i in 0..(1 << (5 - group)) {
+                tone_tab[group][i] = sin_tab[((i + 1) << (group + 3)) & 0x1FF];
+            }
+        }
+
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_F32P_FORMAT, 1),
+            chmap:      NAChannelMap::new(),
+            noise_val_cb, noise_seg_cb, freq_diff_cb, amp_cb, amp_diff_cb, phase_diff_cb,
+            sin_tab, tone_tab,
+            noise:      [[[0; 16]; MAX_NOISE_BANDS]; 2],
+            tones:      [Vec::with_capacity(MAX_TONES),
+                         Vec::with_capacity(MAX_TONES),
+                         Vec::with_capacity(MAX_TONES),
+                         Vec::with_capacity(MAX_TONES),
+                         Vec::with_capacity(MAX_TONES)],
+            rng:        RNG::new(),
+            fft:        FFTBuilder::new_fft(256, false),
+            fft_buf:    [[FFTC_ZERO; MAX_FRAME_SIZE * 2]; 2],
+            noise_tab:  [[0.0; 256]; MAX_NOISE_BANDS],
+            tmp:        [0.0; MAX_FRAME_SIZE],
+            sbuf:       [FFTC_ZERO; 512],
+            delay:      [[0.0; 512]; 2],
+
+            order:      0,
+            frame_bits: 0,
+            samples:    0,
+            frm_bytes:  0,
+            noise_cat:  0,
+            sf_len:     0,
+        }
+    }
+    fn fill_noise_table(&mut self) {
+        let noise_bands = NOISE_SUBBANDS[self.noise_cat];
+        self.noise_tab = [[0.0; 256]; MAX_NOISE_BANDS];
+        for band in 0..(noise_bands.len() - 2) {
+            let prev = noise_bands[band];
+            let cur  = noise_bands[band + 1];
+            let next = noise_bands[band + 2];
+
+            let noise = &mut self.noise_tab[band];
+            for i in prev..cur {
+                noise[i] = ((i - prev) as f32) / ((cur - prev) as f32);
+            }
+            for i in cur..next {
+                noise[i] = ((next - i) as f32) / ((next - cur) as f32);
+            }
+        }
+    }
+    fn read_noise_data(&mut self, br: &mut BitReader, ch: usize) -> DecoderResult<()> {
+        let noise_bands = NOISE_SUBBANDS[self.noise_cat];
+        for band in 0..(noise_bands.len() - 2) {
+            let val                     = br.read_code(&self.noise_val_cb)? as i32;
+            let mut last = to_signed(val);
+            validate!(last >= 0);
+            self.noise[ch][band][0] = last as u8;
+            let mut idx = 1;
+            while idx < 16 {
+                let len                 = (br.read_code_long(&self.noise_seg_cb)? as usize) + 1;
+                let val                 = br.read_code(&self.noise_val_cb)? as i32;
+                let val = to_signed(val) + last;
+                validate!(val >= 0);
+                validate!(len + idx <= 16);
+                for i in 1..=len {
+                    self.noise[ch][band][idx] = (last + (i as i32) * (val - last) / (len as i32) - 1) as u8;
+                    idx += 1;
+                }
+                last = val;
+            }
+        }
+        Ok(())
+    }
+    fn read_wave_data(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+        for tone in self.tones.iter_mut() {
+            tone.truncate(0);
+        }
+        for group in 0..5 {
+            let group_size = 1 << (self.frame_bits - group - 1);
+            let group_bits = 4 - group;
+            let mut freq = 1;
+            let mut off = 0;
+            let mut pos2 = 0;
+            while freq < group_size {
+                let diff                = br.read_code_long(&self.freq_diff_cb)?;
+                freq += diff as usize;
+                while freq >= group_size - 1 {
+                    freq -= group_size - 2;
+                    off  += 1 << group_bits;
+                    pos2 += group_size;
+                }
+                if pos2 >= (1 << self.frame_bits) {
+                    break;
+                }
+                let stereo_mode = if self.chmap.num_channels() > 1 { br.read(2)? as u8 } else { 0 };
+                let amp                 = br.read_code(&self.amp_cb)? as u8;
+                let phase               = br.read(3)? as u8;
+                let (amp2, phase2) = if (stereo_mode & 2) != 0 {
+                                         (br.read_code(&self.amp_diff_cb)? as u8,
+                                          br.read_code(&self.phase_diff_cb)? as u8)
+                    } else { (0, 0) };
+                if (freq >> group_bits) + 1 < self.sf_len {
+                    validate!(self.tones[group as usize].len() < MAX_TONES);
+                    self.tones[group as usize].push(Tone {
+                            offset: off, ch: stereo_mode & 1, phase,
+                            freq: freq as u16, amp_idx: amp
+                        });
+                    if (stereo_mode & 2) != 0 {
+                        validate!(self.tones[group as usize].len() < MAX_TONES);
+                        let phase = phase.wrapping_sub(phase2) & 7;
+                        let amp_idx = amp.wrapping_sub(amp2) & 0x3F;
+                        self.tones[group as usize].push(Tone {
+                                offset: off, ch: !stereo_mode & 1, phase,
+                                freq: freq as u16, amp_idx
+                            });
+                    }
+                }
+                freq += 1;
+            }
+        }
+        Ok(())
+    }
+    fn add_noise(&mut self, ch: usize, sf: usize) {
+        let noise_bands = NOISE_SUBBANDS[self.noise_cat];
+        self.tmp = [0.0; MAX_FRAME_SIZE];
+        for band in 0..(noise_bands.len() - 2) {
+            if noise_bands[band] >= self.sf_len {
+                break;
+            }
+            let scale = SCALES[(self.noise[ch][band][sf >> 1] & 0x3F) as usize] / 32768.0;
+            let start = noise_bands[band];
+            let end = noise_bands[band + 2].min(self.sf_len);
+            let linscale = &self.noise_tab[band];
+            for i in start..end {
+                self.tmp[i] += scale * linscale[i];
+            }
+        }
+
+        for i in 2..self.sf_len - 1 {
+            let im = -self.rng.next_float() * self.tmp[i];
+            let re =  self.rng.next_float() * self.tmp[i];
+            let noise = FFTComplex { re, im };
+            self.fft_buf[ch][sf * self.sf_len + i]     += noise;
+            self.fft_buf[ch][sf * self.sf_len + i + 1] -= noise;
+        }
+    }
+    fn add_tones(&mut self, sf: usize, start_idx: &mut [usize; 5]) {
+        for group in 0..5 {
+            let group_bits = 4 - group;
+            let group_size = (1 << (group_bits + 1)) - 1;
+            for tone in self.tones[group].iter().skip(start_idx[group]) {
+                if (tone.offset as usize) > sf {
+                    break;
+                }
+                start_idx[group] += 1;
+
+                let pos = (tone.freq >> group_bits) as usize;
+                let scale = SCALES[(tone.amp_idx & 0x3F) as usize] / 32768.0;
+                let mut phase_idx = ((tone.phase as usize) * 64).wrapping_sub((2 * pos + 1) * 128) & 0x1FF;
+                for i in 0..group_size {
+                    phase_idx = phase_idx.wrapping_add((2 * (tone.freq as usize) + 1) << (7 - group_bits));
+                    let factor = scale * self.tone_tab[group][i];
+                    let re =  factor * self.sin_tab[(phase_idx + 128) & 0x1FF];
+                    let im = -factor * self.sin_tab[ phase_idx        & 0x1FF];
+                    let val = FFTComplex { re, im };
+                    let ch = tone.ch as usize;
+                    self.fft_buf[ch][(sf + i) * self.sf_len + pos]     += val;
+                    self.fft_buf[ch][(sf + i) * self.sf_len + pos + 1] -= val;
+                }
+            }
+        }
+    }
+    fn synth_channel(&mut self, ch: usize, subframe: usize, dst: &mut [f32]) {
+        let sf_len = self.sf_len;
+        self.sbuf = [FFTC_ZERO; 512];
+        self.sbuf[..sf_len].copy_from_slice(&self.fft_buf[ch][subframe * sf_len..][..sf_len]);
+        self.fft.do_fft_inplace(&mut self.sbuf);
+        dst[..sf_len].copy_from_slice(&self.delay[ch][..sf_len]);
+        for (dst, src) in dst.iter_mut().take(sf_len).zip(self.sbuf.iter()) {
+            *dst += src.re;
+        }
+        for (dst, src) in self.delay[ch].iter_mut().take(sf_len).zip(self.sbuf.iter().skip(sf_len)) {
+            *dst = src.re;
+        }
+    }
+}
+
+impl NADecoder for QdmcDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+            if let Some(edata) = info.get_extradata() {
+                validate!(edata.len() >= 36);
+                let mut mr = MemoryReader::new_read(edata.as_slice());
+                let mut br = ByteReader::new(&mut mr);
+                let size                = br.read_u32be()? as usize;
+                validate!(size >= 36 && size <= edata.len());
+                let tag                 = br.read_tag()?;
+                validate!(&tag == b"QDCA");
+                let ver                 = br.read_u32be()?;
+                validate!(ver == 1);
+                let channels            = br.read_u32be()? as usize;
+                validate!(channels == 2 || channels == 1);
+                let srate               = br.read_u32be()?;
+                let full_bitrate        = br.read_u32be()?;
+                let frame_len           = br.read_u32be()? as usize;
+                let packet_size         = br.read_u32be()? as usize;
+                validate!(packet_size > 0 && (packet_size & (packet_size - 1)) == 0);
+                validate!(frame_len == packet_size * 32);
+                let bytes_per_frame     = br.read_u32be()? as usize;
+                validate!(bytes_per_frame > 6);
+
+                self.order = (31 - (packet_size.leading_zeros() & 31)) as u8;
+                self.frame_bits = self.order + 5;
+                self.samples = frame_len;
+                self.frm_bytes = bytes_per_frame;
+                self.sf_len = packet_size;
+
+                let srate = if ainfo.get_sample_rate() != 0 {
+                        ainfo.get_sample_rate()
+                    } else { srate };
+                self.ainfo = NAAudioInfo::new(srate, channels as u8, SND_F32P_FORMAT, 1);
+                self.chmap = NAChannelMap::from_str(if channels == 1 { "C" } else { "L,R" }).unwrap();
+                let (mut bitrate, fbits) = if srate >= 32000 {
+                        (28000, 13)
+                    } else if srate >= 16000 {
+                        (20000, 12)
+                    } else {
+                        (16000, 11)
+                    };
+                if channels == 2 {
+                    bitrate += bitrate / 2;
+                }
+                let idx = ((full_bitrate * 3 + bitrate / 2) / bitrate) as usize;
+                self.noise_cat = NOISE_BAND_SELECTOR[idx.min(NOISE_BAND_SELECTOR.len() - 1)];
+                validate!(frame_len == (1 << fbits));
+
+                self.fft_buf = [[FFTC_ZERO; MAX_FRAME_SIZE * 2]; 2];
+                self.fft = FFTBuilder::new_fft(packet_size * 2, false);
+
+                self.fill_noise_table();
+            } else {
+                return Err(DecoderError::InvalidData);
+            }
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() == self.frm_bytes);
+            validate!(&pktbuf[..3] == b"QMC" && pktbuf[3] == 1);
+            let checksum = u16::from(pktbuf[4]) + u16::from(pktbuf[5]) * 256;
+            let mut sum = 0xE2u16;
+            for el in pktbuf.iter().skip(6) {
+                sum = sum.wrapping_add(u16::from(*el));
+            }
+            validate!(sum == checksum);
+
+            let channels = self.chmap.num_channels();
+            let abuf = alloc_audio_buffer(self.ainfo, self.samples, self.chmap.clone())?;
+            let mut adata = abuf.get_abuf_f32().unwrap();
+            let mut off = [adata.get_offset(0), adata.get_offset(1)];
+            let dst = adata.get_data_mut().unwrap();
+
+            let mut br = BitReader::new(&pktbuf[6..], BitReaderMode::LE);
+            for ch in 0..channels {
+                self.read_noise_data(&mut br, ch)?;
+            }
+            self.read_wave_data(&mut br)?;
+
+            let mut tone_start = [0; 5];
+            for subframe in 0..32 {
+                for ch in 0..channels {
+                    self.add_noise(ch, subframe);
+                }
+                self.add_tones(subframe, &mut tone_start);
+                for ch in 0..channels {
+                    self.synth_channel(ch, subframe, &mut dst[off[ch]..]);
+                    off[ch] += self.sf_len;
+                }
+            }
+            for ch in 0..channels {
+                let mut chunks = self.fft_buf[ch].chunks_mut(1 << self.frame_bits);
+                let first = chunks.next().unwrap();
+                let second = chunks.next().unwrap();
+                first.copy_from_slice(&second);
+                for el in second.iter_mut() {
+                    *el = FFTC_ZERO;
+                }
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info.replace_info(NACodecTypeInfo::Audio(self.ainfo)), abuf);
+            frm.set_duration(Some(self.samples as u64));
+            frm.set_keyframe(false);
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+        self.fft_buf = [[FFTC_ZERO; MAX_FRAME_SIZE * 2]; 2];
+        self.delay = [[0.0; 512]; 2];
+    }
+}
+
+impl NAOptionHandler for QdmcDecoder {
+    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(QdmcDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_qdmc() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qdesign-music", "assets/QT/rumcoke.mov", Some(32), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::Decodes);
+    }
+}
+
+const NOISE_VAL_BITS: [u8; 27] = [
+    12,  2,  3,  2,  3,  3,  5,  5,
+     6,  7,  7,  9,  7, 10,  9, 11,
+     9,  9,  9,  9,  9,  9,  9,  9,
+    10, 10, 12
+];
+const NOISE_VAL_CODES: [u16; 27] = [
+    0xC7A, 0x000, 0x001, 0x003, 0x005, 0x006, 0x012, 0x00A,
+    0x022, 0x01A, 0x002, 0x0FA, 0x03A, 0x35A, 0x1C2, 0x07A,
+    0x1FA, 0x17A, 0x0DA, 0x142, 0x0C2, 0x042, 0x1DA, 0x05A,
+    0x15A, 0x27A, 0x47A
+];
+const NOISE_VAL_SYMS: [u8; 27] = [
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36
+];
+
+const NOISE_SEG_BITS: [u8; 12] = [ 10, 1, 2, 4, 4, 4, 6, 7, 9, 10, 8, 5 ];
+const NOISE_SEG_CODES: [u16; 12] = [
+    0x30B, 0x000, 0x001, 0x003, 0x007, 0x00F, 0x02B, 0x04B,
+    0x00B, 0x10B, 0x08B, 0x01B
+];
+const NOISE_SEG_SYMS: [u8; 12] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 13, 17 ];
+
+const FREQ_DIFF_BITS: [u8; 47] = [
+    18,  2,  4,  4,  5,  4,  4,  5,  5,  4,  5,  5,  5,  5,  6,  6,
+     6,  6,  6,  7,  7,  6,  7,  6,  6,  6,  7,  7,  7,  7,  7,  8,
+     9,  9,  8,  9, 11, 11, 12, 12, 13, 12, 14, 15, 18, 16, 17
+];
+const FREQ_DIFF_CODES: [u32; 47] = [
+    0x2AD46, 0x00001, 0x00000, 0x00003, 0x0000C, 0x0000A, 0x00007, 0x00018,
+    0x00012, 0x0000E, 0x00004, 0x00016, 0x0000F, 0x0001C, 0x00008, 0x00022,
+    0x00026, 0x00002, 0x0003B, 0x00034, 0x00074, 0x0001F, 0x00014, 0x0002B,
+    0x0001B, 0x0003F, 0x00028, 0x00054, 0x00006, 0x0004B, 0x0000B, 0x00068,
+    0x000E8, 0x00046, 0x000C6, 0x001E8, 0x00146, 0x00346, 0x00546, 0x00746,
+    0x01D46, 0x00F46, 0x00D46, 0x06D46, 0x0AD46, 0x02D46, 0x1AD46
+];
+
+const AMP_BITS: [u8; 28] = [
+    13,  7,  8,  9, 10, 10, 10, 10, 10,  9,  8,  7,  6,  5,  4,  3,
+     3,  2,  3,  3,  4,  5,  7,  8,  9, 11, 12, 13
+];
+const AMP_CODES: [u16; 28] = [
+    0x1EC6, 0x0006, 0x00C2, 0x0142, 0x0242, 0x0246, 0x00C6, 0x0046,
+    0x0042, 0x0146, 0x00A2, 0x0062, 0x0026, 0x0016, 0x000E, 0x0005,
+    0x0004, 0x0003, 0x0000, 0x0001, 0x000A, 0x0012, 0x0002, 0x0022,
+    0x01C6, 0x02C6, 0x06C6, 0x0EC6
+];
+
+const AMP_DIFF_BITS: [u8; 9] = [ 8, 2, 1, 3, 4, 5, 6, 7, 8 ];
+const AMP_DIFF_CODES: [u8; 9] = [
+    0xFE, 0x00, 0x01, 0x02, 0x06, 0x0E, 0x1E, 0x3E, 0x7E
+];
+
+const PHASE_DIFF_BITS: [u8; 9] = [ 6, 2, 2, 4, 4, 6, 5, 4, 2 ];
+const PHASE_DIFF_CODES: [u8; 9] = [
+    0x35, 0x02, 0x00, 0x01, 0x0D, 0x15, 0x05, 0x09, 0x03
+];
+
+const NOISE_BAND_SELECTOR: [usize; 5] = [ 4, 3, 2, 1, 0 ];
+const NOISE_SUBBANDS: [&[usize]; 5] = [
+    &[ 0, 1, 2, 4, 6, 8, 12, 16, 24, 32, 48, 56, 64, 80, 96, 120, 144, 176, 208, 240, 256 ],
+    &[ 0, 2, 4, 8, 16, 24, 32, 48, 56, 64, 80, 104, 128, 160, 208, 256 ],
+    &[ 0, 2, 4, 8, 16, 32, 48, 64, 80, 112, 160, 208, 256 ],
+    &[ 0, 4, 8, 16, 32, 48, 64, 96, 144, 208, 256 ],
+    &[ 0, 4, 16, 32, 64, 256 ]
+];
+
+const SCALES: [f32; 64] = [
+    1.1875, 1.6835938, 2.375, 3.3671875, 4.75, 6.734375, 9.5, 13.46875,
+    19.0, 26.9375, 38.0, 53.875, 76.0, 107.75, 152.0, 215.5,
+    304.0, 431.0, 608.0, 862.0, 1216.0, 1724.0, 2432.0, 3448.0,
+    4864.0, 6896.0, 9728.0, 13792.0, 19456.0, 27584.0, 38912.0, 55168.0,
+    77824.0, 110336.0, 155648.0, 220672.0, 311296.0, 441344.0, 622592.0, 882688.0,
+    1245184.0, 1765376.0, 2490368.0, 3530752.0, 4980736.0, 7061504.0, 0.0, 0.0,
+    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+    0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+];
diff --git a/nihav-qt/src/codecs/qdmcommon.rs b/nihav-qt/src/codecs/qdmcommon.rs
new file mode 100644 (file)
index 0000000..6011140
--- /dev/null
@@ -0,0 +1,199 @@
+use nihav_core::codecs::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+
+/// Bitstream reader.
+#[derive(Debug,Clone)]
+pub struct QdmBitReader<'a> {
+    cache: u32,
+    bits:  u8,
+    pos:   usize,
+    src:   &'a [u8],
+}
+
+#[allow(clippy::identity_op)]
+#[allow(dead_code)]
+impl<'a> QdmBitReader<'a> {
+    pub fn new(src: &'a [u8]) -> Self {
+        Self{ cache: 0, pos: 0, bits: 0, src }
+    }
+    pub fn tell(&self) -> usize {
+        self.pos * 8 - (self.bits as usize)
+    }
+    pub fn left(&self) -> isize {
+        ((self.src.len() as isize) - (self.pos as isize)) * 8 + (self.bits as isize)
+    }
+    fn refill(&mut self) {
+        while self.bits <= 24 {
+            let byte = if self.pos < self.src.len() {
+                    self.pos += 1;
+                    self.src[self.pos - 1]
+                } else {
+                    self.pos += 1;
+                    0
+                };
+            self.cache |= u32::from(byte) << self.bits;
+            self.bits += 8;
+        }
+    }
+    fn read_cache(&mut self, nbits: u8) -> u32 {
+        ((1 << nbits) - 1) & self.cache
+    }
+    fn skip_cache(&mut self, nbits: u8) {
+        self.cache >>= nbits;
+        self.bits -= nbits;
+    }
+    fn reset_cache(&mut self) {
+        self.bits = 0;
+        self.cache = 0;
+    }
+    pub fn read(&mut self, nbits: u8) -> u32 {
+        if nbits == 0 { return 0; }
+        if nbits > 32 { return 0; }
+        if self.bits < nbits {
+            self.refill();
+        }
+        let res = self.read_cache(nbits);
+        self.skip_cache(nbits);
+        res
+    }
+    pub fn read_bool(&mut self) -> bool {
+        if self.bits < 1 {
+            self.refill();
+        }
+        let res = self.read_cache(1);
+        self.skip_cache(1);
+        res == 1
+    }
+    pub fn peek(&mut self, nbits: u8) -> u32 {
+        if nbits > 32 { return 0 }
+        if self.bits < nbits { self.refill(); }
+        self.read_cache(nbits)
+    }
+    pub fn skip(&mut self, nbits: u32) {
+        if u32::from(self.bits) >= nbits {
+            self.skip_cache(nbits as u8);
+            return;
+        }
+        let mut skip_bits = nbits - u32::from(self.bits);
+        self.reset_cache();
+        self.pos += ((skip_bits / 32) * 4) as usize;
+        skip_bits &= 0x1F;
+        self.refill();
+        if skip_bits > 0 {
+            self.skip_cache(skip_bits as u8);
+        }
+    }
+}
+
+impl<'a, S: Copy> CodebookReader<S> for QdmBitReader<'a> {
+    #[allow(unused_variables)]
+    fn read_cb(&mut self, cb: &Codebook<S>) -> CodebookResult<S> {
+        let mut esc = true;
+        let mut idx = 0;
+        let mut lut_bits = cb.lut_bits;
+        while esc {
+            let lut_idx = (self.peek(lut_bits) as usize) + (idx as usize);
+            if cb.table[lut_idx] == TABLE_FILL_VALUE { return Err(CodebookError::InvalidCode); }
+            let bits = cb.table[lut_idx] & 0x7F;
+            esc  = (cb.table[lut_idx] & 0x80) != 0;
+            idx  = (cb.table[lut_idx] >> 8) as usize;
+            let skip_bits = if esc { u32::from(lut_bits) } else { bits };
+            self.skip(skip_bits as u32);
+            lut_bits = bits as u8;
+        }
+        Ok(cb.syms[idx])
+    }
+}
+
+
+pub fn to_signed(val: i32) -> i32 {
+    if (val & 1) != 0 {
+        (val + 1) >> 1
+    } else {
+        -(val >> 1)
+    }
+}
+
+pub trait QdmcCodeReader {
+    fn read_code(&mut self, cb: &Codebook<u8>) -> DecoderResult<u32>;
+    fn read_code_long(&mut self, cb: &Codebook<u8>) -> DecoderResult<u32>;
+}
+
+impl<'a> QdmcCodeReader for BitReader<'a> {
+    fn read_code(&mut self, cb: &Codebook<u8>) -> DecoderResult<u32> {
+        let idx                         = self.read_cb(cb)?;
+        if idx > 0 {
+            Ok(u32::from(idx - 1))
+        } else {
+            let len                     = (self.read(3)? as u8) + 1;
+            let val                     = self.read(len)?;
+            Ok(val)
+        }
+    }
+    fn read_code_long(&mut self, cb: &Codebook<u8>) -> DecoderResult<u32> {
+        let idx                         = self.read_code(cb)? as usize;
+        validate!(idx < ESCAPE_PREFIX.len());
+        let add                         = self.read((idx >> 2) as u8)?;
+        Ok(ESCAPE_PREFIX[idx] + add)
+    }
+}
+
+impl<'a> QdmcCodeReader for QdmBitReader<'a> {
+    fn read_code(&mut self, cb: &Codebook<u8>) -> DecoderResult<u32> {
+        let idx                         = self.read_cb(cb)?;
+        if idx > 0 {
+            Ok(u32::from(idx - 1))
+        } else {
+            let len                     = (self.read(3) as u8) + 1;
+            let val                     = self.read(len);
+            Ok(val)
+        }
+    }
+    fn read_code_long(&mut self, cb: &Codebook<u8>) -> DecoderResult<u32> {
+        let idx                         = self.read_code(cb)? as usize;
+        validate!(idx < ESCAPE_PREFIX.len());
+        let add                         = self.read((idx >> 2) as u8);
+        Ok(ESCAPE_PREFIX[idx] + add)
+    }
+}
+
+const ESCAPE_PREFIX: [u32; 65] = [
+    0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00006, 0x00008, 0x0000A,
+    0x0000C, 0x00010, 0x00014, 0x00018, 0x0001C, 0x00024, 0x0002C, 0x00034,
+    0x0003C, 0x0004C, 0x0005C, 0x0006C, 0x0007C, 0x0009C, 0x000BC, 0x000DC,
+    0x000FC, 0x0013C, 0x0017C, 0x001BC, 0x001FC, 0x0027C, 0x002FC, 0x0037C,
+    0x003FC, 0x004FC, 0x005FC, 0x006FC, 0x007FC, 0x009FC, 0x00BFC, 0x00DFC,
+    0x00FFC, 0x013FC, 0x017FC, 0x01BFC, 0x01FFC, 0x027FC, 0x02FFC, 0x037FC,
+    0x03FFC, 0x04FFC, 0x05FFC, 0x06FFC, 0x07FFC, 0x09FFC, 0x0BFFC, 0x0DFFC,
+    0x0FFFC, 0x13FFC, 0x17FFC, 0x1BFFC, 0x1FFFC, 0x27FFC, 0x2FFFC, 0x37FFC,
+    0x3FFFC
+];
+
+pub struct RNG {
+    pub seed:   u32,
+}
+
+impl RNG {
+    pub fn new() -> Self { Self { seed: 0 } }
+    pub fn next(&mut self) -> u32 {
+        self.seed = self.seed.wrapping_mul(0x343FD).wrapping_add(0x269EC3);
+        self.seed
+    }
+    pub fn next_float(&mut self) -> f32 {
+        self.next();
+        ((((self.seed >> 16) & 0x7FFF) as f32) - 16384.0) / 16384.0
+    }
+}
+
+#[derive(Clone,Copy)]
+pub struct Tone {
+    pub ch:         u8,
+    pub phase:      u8,
+    pub offset:     u8,
+    pub freq:       u16,
+    pub amp_idx:    u8,
+}
+
+pub const MAX_TONES: usize = 8192;
+
diff --git a/nihav-qt/src/codecs/rle.rs b/nihav-qt/src/codecs/rle.rs
new file mode 100644 (file)
index 0000000..0d3ed06
--- /dev/null
@@ -0,0 +1,623 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_codec_support::codecs::HAMShuffler;
+
+const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton {
+        model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
+        comp_info: [
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift:  5, comp_offs: 0, next_elem: 2 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift:  0, comp_offs: 0, next_elem: 2 }),
+            None, None],
+        elem_size: 2, be: false, alpha: false, palette: false };
+
+pub const ARGB_FORMAT: NAPixelFormaton = NAPixelFormaton {
+        model: ColorModel::RGB(RGBSubmodel::RGB), components: 4,
+        comp_info: [
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 1, next_elem: 4 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 2, next_elem: 4 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 3, next_elem: 4 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 8, shift: 0, comp_offs: 0, next_elem: 4 }),
+            None ],
+        elem_size: 4, be: false, alpha: true, palette: false };
+
+#[derive(Default)]
+struct RleDecoder {
+    info:       NACodecInfoRef,
+    hams:       HAMShuffler<u8>,
+    hams16:     HAMShuffler<u16>,
+    width:      usize,
+    height:     usize,
+    depth:      u8,
+}
+
+#[allow(clippy::needless_range_loop)]
+fn unpack_mono(src: u16, dst: &mut [u8; 16]) {
+    for i in 0..16 {
+        dst[i] = ((src >> (15 - i)) & 1) as u8;
+    }
+}
+
+#[allow(clippy::needless_range_loop)]
+fn unpack_pixels(src: u32, dst: &mut [u8; 16], depth: u8) {
+    let depth = depth as usize;
+    let mask = (1 << depth) - 1;
+    for i in 0..32 / depth {
+        dst[i] = ((src >> (32 - depth - i * depth)) & mask) as u8;
+    }
+}
+
+impl RleDecoder {
+    fn new() -> Self {
+        Self::default()
+    }
+    fn decode_mono(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>, start_line: usize, end_line: usize) -> DecoderResult<bool> {
+        let mut has_skips = false;
+        let mut pix_buf = [0u8; 16];
+        let npixels = 16;
+
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0] + start_line * stride;
+        let mut y = start_line;
+        while y < end_line {
+            let mut x = 0;
+            while x < self.width {
+                let skip_code               = br.read_byte()?;
+                let rle_code                = br.read_byte()? as i8;
+                if x == 0 {
+                    validate!((skip_code & 0x80) != 0);
+                }
+                if rle_code == 0 {
+                    return Ok(false);
+                }
+                if x != 0 && (skip_code & 0x80) != 0 {
+                    x = 0;
+                    y += 1;
+                    validate!(y < end_line);
+                    doff += stride;
+                    has_skips = true;
+                }
+                let skip = (skip_code & 0x1F) as usize;
+                if skip > 0 {
+                    has_skips = true;
+                }
+                validate!(x + skip * npixels <= self.width);
+                x += skip * npixels;
+                if rle_code < 0 {
+                    let len = (-i16::from(rle_code)) as usize;
+                    validate!(x + len * npixels <= self.width);
+                    let val                 = br.read_u16be()?;
+                    unpack_mono(val, &mut pix_buf);
+                    for _ in 0..len {
+                        for el in pix_buf.iter() {
+                            frm.data[doff + x] = *el;
+                            x += 1;
+                        }
+                    }
+                } else {
+                    let len = rle_code as usize;
+                    validate!(x + len * npixels <= self.width);
+                    for _ in 0..len {
+                        let val             = br.read_u16be()?;
+                        unpack_mono(val, &mut pix_buf);
+                        for el in pix_buf.iter() {
+                            frm.data[doff + x] = *el;
+                            x += 1;
+                        }
+                    }
+                }
+            }
+            doff += stride;
+            y += 1;
+        }
+
+        Ok(has_skips)
+    }
+    fn decode_pal(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>, start_line: usize, end_line: usize) -> DecoderResult<bool> {
+        let mut has_skips = false;
+        let mut pix_buf = [0u8; 16];
+        let npixels = match self.depth {
+                2 => 16,
+                4 => 8,
+                8 => 4,
+                _ => return Err(DecoderError::InvalidData),
+            };
+
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0] + start_line * stride;
+        for _ in start_line..end_line {
+            let mut x = 0;
+            let mut skip_mode = true;
+            while x < self.width {
+                if skip_mode {
+                    let skip_code           = br.read_byte()?;
+                    if skip_code == 0 {
+                        return Ok(true);
+                    } else {
+                        let skip = (skip_code - 1) as usize;
+                        validate!(x + skip * npixels <= self.width);
+                        x += skip * npixels;
+                        has_skips = true;
+                    }
+                    skip_mode = false;
+                } else {
+                    let rle_code            = br.read_byte()? as i8;
+                    if rle_code == 0 {
+                        skip_mode = true;
+                    } else if rle_code == -1 {
+                        if x < self.width {
+                            has_skips = true;
+                        }
+                        break;
+                    } else if rle_code < 0 {
+                        let len = (-i16::from(rle_code)) as usize;
+                        validate!(x + len * npixels <= self.width);
+                        let val             = br.read_u32be()?;
+                        unpack_pixels(val, &mut pix_buf, self.depth);
+                        for _ in 0..len {
+                            for el in pix_buf.iter().take(npixels) {
+                                frm.data[doff + x] = *el;
+                                x += 1;
+                            }
+                        }
+                    } else {
+                        let len = rle_code as usize;
+                        validate!(x + len * npixels <= self.width);
+                        for _ in 0..len {
+                            let val         = br.read_u32be()?;
+                            unpack_pixels(val, &mut pix_buf, self.depth);
+                            for el in pix_buf.iter().take(npixels) {
+                                frm.data[doff + x] = *el;
+                                x += 1;
+                            }
+                        }
+                    }
+                }
+            }
+            if x == self.width {
+                let eol                 = br.read_byte()? as i8;
+                validate!(eol == -1);
+            }
+            doff += stride;
+        }
+
+        Ok(has_skips)
+    }
+    fn decode_16bit(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u16>, start_line: usize, end_line: usize) -> DecoderResult<bool> {
+        let mut has_skips = false;
+
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0] + start_line * stride;
+        for _ in start_line..end_line {
+            let mut x = 0;
+            let mut skip_mode = true;
+            while x < self.width {
+                if skip_mode {
+                    let skip_code           = br.read_byte()?;
+                    if skip_code == 0 {
+                        return Ok(true);
+                    } else {
+                        let skip = (skip_code - 1) as usize;
+                        validate!(x + skip <= self.width);
+                        x += skip;
+                        has_skips = true;
+                    }
+                    skip_mode = false;
+                } else {
+                    let rle_code            = br.read_byte()? as i8;
+                    if rle_code == 0 {
+                        skip_mode = true;
+                    } else if rle_code == -1 {
+                        if x < self.width {
+                            has_skips = true;
+                        }
+                        break;
+                    } else if rle_code < 0 {
+                        let len = (-i16::from(rle_code)) as usize;
+                        validate!(x + len <= self.width);
+                        let pix             = br.read_u16be()?;
+                        for _ in 0..len {
+                            frm.data[doff + x] = pix;
+                            x += 1;
+                        }
+                    } else {
+                        let len = rle_code as usize;
+                        validate!(x + len <= self.width);
+                        for _ in 0..len {
+                            frm.data[doff + x] = br.read_u16be()?;
+                            x += 1;
+                        }
+                    }
+                }
+            }
+            if x == self.width {
+                let eol                 = br.read_byte()? as i8;
+                validate!(eol == -1);
+            }
+            doff += stride;
+        }
+
+        Ok(has_skips)
+    }
+    fn decode_24bit(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>, start_line: usize, end_line: usize) -> DecoderResult<bool> {
+        let mut has_skips = false;
+        let mut rgb = [0u8; 3];
+
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0] + start_line * stride;
+        for _ in start_line..end_line {
+            let mut x = 0;
+            let mut skip_mode = true;
+            while x < self.width {
+                if skip_mode {
+                    let skip_code           = br.read_byte()?;
+                    if skip_code == 0 {
+                        return Ok(true);
+                    } else {
+                        let skip = (skip_code - 1) as usize;
+                        validate!(x + skip <= self.width);
+                        x += skip;
+                        has_skips = true;
+                    }
+                    skip_mode = false;
+                } else {
+                    let rle_code            = br.read_byte()? as i8;
+                    if rle_code == 0 {
+                        skip_mode = true;
+                    } else if rle_code == -1 {
+                        if x < self.width {
+                            has_skips = true;
+                        }
+                        break;
+                    } else if rle_code < 0 {
+                        let len = (-i16::from(rle_code)) as usize;
+                        validate!(x + len <= self.width);
+                                              br.read_buf(&mut rgb)?;
+                        for _ in 0..len {
+                            frm.data[doff + x * 3]     = rgb[0];
+                            frm.data[doff + x * 3 + 1] = rgb[1];
+                            frm.data[doff + x * 3 + 2] = rgb[2];
+                            x += 1;
+                        }
+                    } else {
+                        let len = rle_code as usize;
+                        validate!(x + len  <= self.width);
+                                              br.read_buf(&mut frm.data[doff + x * 3..][..len * 3])?;
+                        x += len;
+                    }
+                }
+            }
+            if x == self.width {
+                let eol                 = br.read_byte()? as i8;
+                validate!(eol == -1);
+            }
+            doff += stride;
+        }
+
+        Ok(has_skips)
+    }
+    fn decode_32bit(&self, br: &mut ByteReader, frm: &mut NASimpleVideoFrame<u8>, start_line: usize, end_line: usize) -> DecoderResult<bool> {
+        let mut has_skips = false;
+        let mut rgb = [0u8; 4];
+
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0] + start_line * stride;
+        for _ in start_line..end_line {
+            let mut x = 0;
+            let mut skip_mode = true;
+            while x < self.width {
+                if skip_mode {
+                    let skip_code           = br.read_byte()?;
+                    if skip_code == 0 {
+                        return Ok(true);
+                    } else {
+                        let skip = (skip_code - 1) as usize;
+                        validate!(x + skip <= self.width);
+                        x += skip;
+                        has_skips = true;
+                    }
+                    skip_mode = false;
+                } else {
+                    let rle_code            = br.read_byte()? as i8;
+                    if rle_code == 0 {
+                        skip_mode = true;
+                    } else if rle_code == -1 {
+                        if x < self.width {
+                            has_skips = true;
+                        }
+                        break;
+                    } else if rle_code < 0 {
+                        let len = (-i16::from(rle_code)) as usize;
+                        validate!(x + len <= self.width);
+                                              br.read_buf(&mut rgb)?;
+                        for _ in 0..len {
+                            frm.data[doff + x * 4]     = rgb[0];
+                            frm.data[doff + x * 4 + 1] = rgb[1];
+                            frm.data[doff + x * 4 + 2] = rgb[2];
+                            frm.data[doff + x * 4 + 3] = rgb[3];
+                            x += 1;
+                        }
+                    } else {
+                        let len = rle_code as usize;
+                        validate!(x + len  <= self.width);
+                                              br.read_buf(&mut frm.data[doff + x * 4..][..len * 4])?;
+                        x += len;
+                    }
+                }
+            }
+            if x == self.width {
+                let eol                 = br.read_byte()? as i8;
+                validate!(eol == -1);
+            }
+            doff += stride;
+        }
+
+        Ok(has_skips)
+    }
+}
+
+impl NADecoder for RleDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            self.width  = vinfo.get_width();
+            self.height = vinfo.get_height();
+            self.depth = vinfo.bits;
+            let fmt = match self.depth {
+                    1 | 2 | 4 | 8 => PAL8_FORMAT,
+                    15 | 16 => RGB555_FORMAT,
+                    24 => RGB24_FORMAT,
+                    32 => ARGB_FORMAT,
+                    _ => return Err(DecoderError::InvalidData),
+                };
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, fmt));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() >= 2);
+        let mut mr = MemoryReader::new_read(src.as_slice());
+        let mut br = ByteReader::new(&mut mr);
+
+        let id                          = br.read_byte()?;
+        validate!(id == 0x40 || id == 0x00);
+        let length                      = br.read_u24be()? as usize;
+        validate!(length == src.len());
+
+        let flags                       = br.read_u16be()?;
+        let (start_line, end_line) = if (flags & 0x8) != 0 {
+                let start               = br.read_u16be()? as usize;
+                                          br.read_skip(2)?;
+                let h                   = br.read_u16be()? as usize;
+                                          br.read_skip(2)?;
+                validate!(start + h <= self.height);
+                (start, start + h)
+            } else {
+                (0, self.height)
+            };
+
+        let mut has_skips;
+        let buftype;
+        if self.depth <= 8 {
+            let bufret = self.hams.clone_ref();
+            let mut buf;
+            if let Some(bbuf) = bufret {
+                buf = bbuf;
+            } else {
+                let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+                buf = bufinfo.get_vbuf().unwrap();
+                self.hams.add_frame(buf);
+                buf = self.hams.get_output_frame().unwrap();
+            }
+            let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+            if self.depth != 1 {
+                has_skips = self.decode_pal(&mut br, &mut frm, start_line, end_line)?;
+            } else {
+                has_skips = self.decode_mono(&mut br, &mut frm, start_line, end_line)?;
+            }
+
+            let paloff = frm.offset[1];
+            let dpal = &mut frm.data[paloff..];
+            for sd in pkt.side_data.iter() {
+                match *sd {
+                    NASideData::Palette(_, ref pal) => {
+                        for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) {
+                            dst[0] = src[0];
+                            dst[1] = src[1];
+                            dst[2] = src[2];
+                        }
+                        break;
+                    },
+                    _ => {},
+                };
+            }
+            buftype = NABufferType::Video(buf);
+        } else if self.depth == 16 {
+            let bufret = self.hams16.clone_ref();
+            let mut buf;
+            if let Some(bbuf) = bufret {
+                buf = bbuf;
+            } else {
+                let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+                buf = bufinfo.get_vbuf16().unwrap();
+                self.hams16.add_frame(buf);
+                buf = self.hams16.get_output_frame().unwrap();
+            }
+            let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+            has_skips = self.decode_16bit(&mut br, &mut frm, start_line, end_line)?;
+            buftype = NABufferType::Video16(buf);
+        } else if self.depth == 24 {
+            let bufret = self.hams.clone_ref();
+            let mut buf;
+            if let Some(bbuf) = bufret {
+                buf = bbuf;
+            } else {
+                let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+                buf = bufinfo.get_vbuf().unwrap();
+                self.hams.add_frame(buf);
+                buf = self.hams.get_output_frame().unwrap();
+            }
+            let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+            has_skips = self.decode_24bit(&mut br, &mut frm, start_line, end_line)?;
+            buftype = NABufferType::Video(buf);
+        } else if self.depth == 32 {
+            let bufret = self.hams.clone_ref();
+            let mut buf;
+            if let Some(bbuf) = bufret {
+                buf = bbuf;
+            } else {
+                let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 0)?;
+                buf = bufinfo.get_vbuf().unwrap();
+                self.hams.add_frame(buf);
+                buf = self.hams.get_output_frame().unwrap();
+            }
+            let mut frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+            has_skips = self.decode_32bit(&mut br, &mut frm, start_line, end_line)?;
+            buftype = NABufferType::Video(buf);
+        } else {
+            return Err(DecoderError::InvalidData);
+        }
+        if (start_line != 0) || (end_line != self.height) {
+            has_skips = true;
+        }
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype);
+        frm.set_keyframe(!has_skips);
+        frm.set_frame_type(if !has_skips { FrameType::I } else { FrameType::P });
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.hams.clear();
+        self.hams16.clear();
+    }
+}
+
+impl NAOptionHandler for RleDecoder {
+    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(RleDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_qt_rle_1bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+//test_file_decoding("mov", "assets/QT/Animation-Monochrome.mov", Some(6), true, false, Some("qtrle-mono"), &dmx_reg, &dec_reg);
+        test_decoding("mov", "qt-rle", "assets/QT/Animation-Monochrome.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0xc5b6fd2b, 0x87aae95c, 0xc32d0aaa, 0x4ed21592],
+                            [0xe13aa599, 0x2ec6421e, 0xfcfdcc81, 0x8c2ee2ef],
+                            [0xd835547b, 0xe2ffd6c9, 0xe24135c1, 0x7d2bb64f],
+                            [0x6176e812, 0xb637444c, 0x71b1cbe5, 0xfc98905f],
+                            [0x53a6b414, 0xbbf266c0, 0x859c3d10, 0x179a2252],
+                            [0x56bc8cdd, 0x6438ba4d, 0x056e79c1, 0xb851e767],
+                            [0xc25b9fec, 0xfc93233a, 0x30301b6d, 0xb290f5d7]]));
+    }
+    #[test]
+    fn test_qt_rle_4bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-rle", "assets/QT/Animation-16Greys.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x280c82aa, 0xa8bd11a6, 0x5b5babda, 0xeff58dd9],
+                            [0x5c732231, 0x81d20be3, 0x41249639, 0xab2a9841],
+                            [0xb689268d, 0x26de8510, 0x506e0a06, 0xb0dcfc40],
+                            [0x09dced38, 0xbd0f5482, 0x3803efc9, 0x84bcaac4],
+                            [0x5c49f8cc, 0xc1e2bd17, 0x1c22b849, 0x8f09afd5],
+                            [0xe9f7b847, 0x13a4e429, 0x1b8af943, 0x82766ed2],
+                            [0x2833c41a, 0x53781343, 0xce083e07, 0xdc3b24e9]]));
+    }
+    #[test]
+    fn test_qt_rle_8bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-rle", "assets/QT/Animation-256Greys.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x3c439212, 0x419944a5, 0xb274d9f5, 0xf3c53b12],
+                            [0xd2a51886, 0xfbd37c2e, 0x899806c6, 0x465a66e0],
+                            [0xbd59029e, 0x9de8766c, 0xd681bf0c, 0xa7fe4dfe],
+                            [0x6150d380, 0xe8d67e0b, 0x0beb8455, 0xfcfd899d],
+                            [0xba0f6b50, 0xba253267, 0xb727c5d7, 0x10dbf0c7],
+                            [0x4f93f1aa, 0x2f10aa86, 0xfa97b35f, 0x687065df],
+                            [0x730270e2, 0x3a3e02f1, 0xb906f478, 0xdb42af87]]));
+    }
+    #[test]
+    fn test_qt_rle_16bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-rle", "assets/QT/Animation-Highcolour.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x8fa5361b, 0xd36d6def, 0x33b250e9, 0xab98a41c],
+                            [0xdd253ce0, 0xbc5fd3a1, 0x51fe2394, 0x950f18e4],
+                            [0xbf34ca8d, 0x1faa24ee, 0x8d70af09, 0x742a4056],
+                            [0x9feca59b, 0xdca7dc1d, 0xb6fe14f1, 0xd88c8b67],
+                            [0x2e1544b8, 0x89a7e788, 0x0efcde09, 0xec4e7995],
+                            [0x1e28b2a8, 0xd53495ca, 0x405a9b6e, 0x59338cad],
+                            [0xe90156a4, 0xb64bca4a, 0x5cdf6681, 0xc32945fb]]));
+    }
+    #[test]
+    fn test_qt_rle_24bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-rle", "assets/QT/Animation-Highcolour.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x8fa5361b, 0xd36d6def, 0x33b250e9, 0xab98a41c],
+                            [0xdd253ce0, 0xbc5fd3a1, 0x51fe2394, 0x950f18e4],
+                            [0xbf34ca8d, 0x1faa24ee, 0x8d70af09, 0x742a4056],
+                            [0x9feca59b, 0xdca7dc1d, 0xb6fe14f1, 0xd88c8b67],
+                            [0x2e1544b8, 0x89a7e788, 0x0efcde09, 0xec4e7995],
+                            [0x1e28b2a8, 0xd53495ca, 0x405a9b6e, 0x59338cad],
+                            [0xe90156a4, 0xb64bca4a, 0x5cdf6681, 0xc32945fb]]));
+    }
+    #[test]
+    fn test_qt_rle_32bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-rle", "assets/QT/Jag-finder-renaming.mov", Some(10), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xe82390cf, 0xfaceab34, 0xcc857b2f, 0xed47f125],
+                            [0xd453e404, 0x6418f0a2, 0x2a4008dc, 0x09db5c72]]));
+    }
+}
diff --git a/nihav-qt/src/codecs/rpza.rs b/nihav-qt/src/codecs/rpza.rs
new file mode 100644 (file)
index 0000000..a3b2e5f
--- /dev/null
@@ -0,0 +1,217 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_codec_support::codecs::HAMShuffler;
+
+const RGB555_FORMAT: NAPixelFormaton = NAPixelFormaton {
+        model: ColorModel::RGB(RGBSubmodel::RGB), components: 3,
+        comp_info: [
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift: 10, comp_offs: 0, next_elem: 2 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift:  5, comp_offs: 0, next_elem: 2 }),
+            Some(NAPixelChromaton{ h_ss: 0, v_ss: 0, packed: true, depth: 5, shift:  0, comp_offs: 0, next_elem: 2 }),
+            None, None],
+        elem_size: 2, be: false, alpha: false, palette: false };
+
+#[derive(Default)]
+struct RpzaDecoder {
+    info:       NACodecInfoRef,
+    hams:       HAMShuffler<u16>,
+    width:      usize,
+    height:     usize,
+}
+
+impl RpzaDecoder {
+    fn new() -> Self {
+        Self::default()
+    }
+    fn put_block(dst: &mut [u16], dstride: usize, block: &[u16; 16]) {
+        for (line, src) in dst.chunks_mut(dstride).take(4).zip(block.chunks(4)) {
+            (&mut line[..4]).copy_from_slice(src);
+        }
+    }
+}
+
+fn div3(a: u16, b: u16) -> u16 {
+    let r0 = (a >> 10) & 0x1F;
+    let g0 = (a >>  5) & 0x1F;
+    let b0 =  a        & 0x1F;
+    let r1 = (b >> 10) & 0x1F;
+    let g1 = (b >>  5) & 0x1F;
+    let b1 =  b        & 0x1F;
+
+    let r = (r0 * 21 + r1 * 11) / 32;
+    let g = (g0 * 21 + g1 * 11) / 32;
+    let b = (b0 * 21 + b1 * 11) / 32;
+
+    (r << 10) | (g << 5) | b
+}
+
+impl NADecoder for RpzaDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            self.width  = (vinfo.get_width()  + 3) & !3;
+            self.height = (vinfo.get_height() + 3) & !3;
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, RGB555_FORMAT));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() >= 2);
+        let mut mr = MemoryReader::new_read(src.as_slice());
+        let mut br = ByteReader::new(&mut mr);
+
+        let id                          = br.read_byte()?;
+        validate!(id == 0xE1);
+        let length                      = br.read_u24be()? as usize;
+        validate!(length == src.len());
+
+        let bufret = self.hams.clone_ref();
+        let mut buf;
+        if let Some(bbuf) = bufret {
+            buf = bbuf;
+        } else {
+            let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?;
+            buf = bufinfo.get_vbuf16().unwrap();
+            self.hams.add_frame(buf);
+            buf = self.hams.get_output_frame().unwrap();
+        }
+        let frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0];
+
+        let mut x = 0;
+        let nblocks = (self.width / 4) * (self.height / 4);
+        let mut blockpos = 0;
+        let mut has_skips = false;
+        let mut block = [0u16; 16];
+        while blockpos < nblocks {
+            let opcode                  = br.read_byte()?;
+            if (opcode & 0x80) == 0 {
+                let b2                  = br.read_byte()?;
+                let clr0 = u16::from(opcode) * 256 + u16::from(b2);
+                if (br.peek_byte()? & 0x80) == 0 {
+                    block[0] = clr0;
+                    for el in block.iter_mut().skip(1) {
+                        *el             = br.read_u16be()?;
+                    }
+                } else {
+                    let clr3            = br.read_u16be()?;
+                    let clr1 = div3(clr0, clr3);
+                    let clr2 = div3(clr3, clr0);
+                    let clr = [clr3, clr2, clr1, clr0];
+                    let flags       = br.read_u32be()? as usize;
+                    for i in 0..16 {
+                        block[i] = clr[(flags >> (30 - i * 2)) & 3];
+                    }
+                }
+                Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                x += 4;
+                if x == self.width {
+                    x = 0;
+                    doff += stride * 4;
+                }
+                blockpos += 1;
+                continue;
+            }
+            let len = ((opcode & 0x1F) as usize) + 1;
+            validate!(blockpos + len <= nblocks);
+            match opcode >> 5 {
+                4 => {
+                    has_skips = true;
+                    for _ in 0..len {
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                    }
+                },
+                5 => {
+                    let clr             = br.read_u16be()?;
+                    block = [clr; 16];
+                    for _ in 0..len {
+                        Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                    }
+                },
+                6 => {
+                    let clr0            = br.read_u16be()?;
+                    let clr3            = br.read_u16be()?;
+                    let clr1 = div3(clr0, clr3);
+                    let clr2 = div3(clr3, clr0);
+                    let clr = [clr3, clr2, clr1, clr0];
+                    for _ in 0..len {
+                        let flags       = br.read_u32be()? as usize;
+                        for i in 0..16 {
+                            block[i] = clr[(flags >> (30 - i * 2)) & 3];
+                        }
+                        Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                    }
+                },
+                _ => {
+                    return Err(DecoderError::InvalidData);
+                },
+            };
+            blockpos += len;
+        }
+
+        let buftype = NABufferType::Video16(buf);
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype);
+        frm.set_keyframe(!has_skips);
+        frm.set_frame_type(if !has_skips { FrameType::I } else { FrameType::P });
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.hams.clear();
+    }
+}
+
+impl NAOptionHandler for RpzaDecoder {
+    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(RpzaDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_rpza() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "apple-video", "assets/QT/aletrek-rpza.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0xe7cfc941, 0xa448841b, 0x75afc888, 0x94aa064b],
+                            [0xadaaec50, 0xff7319ff, 0xa1f3f64a, 0xc40c2985],
+                            [0xdfa5c4b9, 0xdac2d22b, 0x14f9f281, 0x7295eae7],
+                            [0x3f3420b9, 0xbe48b885, 0x91b0fb51, 0xd71462ac],
+                            [0xcaae1580, 0x16eecce3, 0x2ca0dd4b, 0x7f9c62e3],
+                            [0xb51fc759, 0xe1cfc171, 0xda854767, 0x878f6e17],
+                            [0x8d3abf6d, 0xeecec7a2, 0x5832e5d6, 0x86145fc9]]));
+    }
+}
diff --git a/nihav-qt/src/codecs/smc.rs b/nihav-qt/src/codecs/smc.rs
new file mode 100644 (file)
index 0000000..96fcba2
--- /dev/null
@@ -0,0 +1,329 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_codec_support::codecs::HAMShuffler;
+
+struct SmcDecoder {
+    info:       NACodecInfoRef,
+    hams:       HAMShuffler<u8>,
+    width:      usize,
+    height:     usize,
+    pairs:      [[u8; 2]; 256],
+    quads:      [[u8; 4]; 256],
+    octets:     [[u8; 8]; 256],
+}
+
+impl SmcDecoder {
+    fn new() -> Self {
+        Self {
+            info:       NACodecInfoRef::default(),
+            hams:       HAMShuffler::default(),
+            width:      0,
+            height:     0,
+            pairs:      [[0; 2]; 256],
+            quads:      [[0; 4]; 256],
+            octets:     [[0; 8]; 256],
+        }
+    }
+    fn put_block(dst: &mut [u8], dstride: usize, block: &[u8; 16]) {
+        for (line, src) in dst.chunks_mut(dstride).take(4).zip(block.chunks(4)) {
+            (&mut line[..4]).copy_from_slice(src);
+        }
+    }
+    fn put_blocks(&self, dst: &mut [u8], stride: usize, doff: &mut usize, x: &mut usize, len: usize, block: &[u8; 16]) {
+        for _ in 0..len {
+            Self::put_block(&mut dst[*doff + *x..], stride, block);
+            *x += 4;
+            if *x == self.width {
+                *x = 0;
+                *doff += stride * 4;
+            }
+
+        }
+    }
+}
+
+impl NADecoder for SmcDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            self.width  = (vinfo.get_width()  + 3) & !3;
+            self.height = (vinfo.get_height() + 3) & !3;
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, PAL8_FORMAT));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    #[allow(clippy::cyclomatic_complexity)]
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() >= 2);
+        let mut mr = MemoryReader::new_read(src.as_slice());
+        let mut br = ByteReader::new(&mut mr);
+
+        let id                          = br.read_byte()?;
+        validate!(id == 0x80);
+        let length                      = br.read_u24be()? as usize;
+        validate!(length == src.len());
+
+        let bufret = self.hams.clone_ref();
+        let mut buf;
+        if let Some(bbuf) = bufret {
+            buf = bbuf;
+        } else {
+            let bufinfo = alloc_video_buffer(self.info.get_properties().get_video_info().unwrap(), 2)?;
+            buf = bufinfo.get_vbuf().unwrap();
+            self.hams.add_frame(buf);
+            buf = self.hams.get_output_frame().unwrap();
+        }
+        let frm = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+        let stride = frm.stride[0];
+        let mut doff = frm.offset[0];
+
+        self.pairs      = [[0; 2]; 256];
+        self.quads      = [[0; 4]; 256];
+        self.octets     = [[0; 8]; 256];
+
+        let mut x = 0;
+        let nblocks = (self.width / 4) * (self.height / 4);
+        let mut blockpos = 0;
+        let mut pair_idx = 0;
+        let mut quad_idx = 0;
+        let mut oct_idx = 0;
+        let mut has_skips = false;
+        let mut block = [0u8; 16];
+        let mut lblock = [0u8; 16];
+        let mut llblock = [0u8; 16];
+        while blockpos < nblocks {
+            let opcode                  = br.read_byte()?;
+            let ext_opcode = (opcode & 0x10) != 0;
+            let len = if !ext_opcode || (opcode >= 0x80) {
+                    ((opcode & 0xF) as usize) + 1
+                } else {
+                                          (br.read_byte()? as usize) + 1
+                };
+            validate!(blockpos + len <= nblocks);
+            match opcode >> 5 {
+                0 => {
+                    has_skips = true;
+                    for _ in 0..len {
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                    }
+                },
+                1 => {
+                    self.put_blocks(frm.data, stride, &mut doff, &mut x, len, &lblock);
+                    llblock = lblock;
+                },
+                2 => {
+                    for i in 0..len {
+                        if (i & 1) == 0 {
+                            Self::put_block(&mut frm.data[doff + x..], stride, &llblock);
+                        } else {
+                            Self::put_block(&mut frm.data[doff + x..], stride, &lblock);
+                        }
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                    }
+                },
+                3 => {
+                    let clr             = br.read_byte()?;
+                    block = [clr; 16];
+                    self.put_blocks(frm.data, stride, &mut doff, &mut x, len, &block);
+                    if len > 1 {
+                        llblock = block;
+                    } else {
+                        llblock = lblock;
+                    }
+                    lblock = block;
+                },
+                4 => {
+                    let clr;
+                    if !ext_opcode {
+                                          br.read_buf(&mut self.pairs[pair_idx])?;
+                        clr = self.pairs[pair_idx];
+                        pair_idx = (pair_idx + 1) & 0xFF;
+                    } else {
+                        let idx         = br.read_byte()? as usize;
+                        clr = self.pairs[idx];
+                    }
+                    for _ in 0..len {
+                        let flags       = br.read_u16be()? as usize;
+                        for i in 0..16 {
+                            block[i] = clr[(flags >> (15 - i)) & 1];
+                        }
+                        Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                        llblock = lblock;
+                        lblock = block;
+                    }
+                },
+                5 => {
+                    let clr;
+                    if !ext_opcode {
+                                          br.read_buf(&mut self.quads[quad_idx])?;
+                        clr = self.quads[quad_idx];
+                        quad_idx = (quad_idx + 1) & 0xFF;
+                    } else {
+                        let idx         = br.read_byte()? as usize;
+                        clr = self.quads[idx];
+                    }
+                    for _ in 0..len {
+                        let flags       = br.read_u32be()? as usize;
+                        for i in 0..16 {
+                            block[i] = clr[(flags >> (30 - i * 2)) & 3];
+                        }
+                        Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                        llblock = lblock;
+                        lblock = block;
+                    }
+                },
+                6 => {
+                    let clr;
+                    if !ext_opcode {
+                                          br.read_buf(&mut self.octets[oct_idx])?;
+                        clr = self.octets[oct_idx];
+                        oct_idx = (oct_idx + 1) & 0xFF;
+                    } else {
+                        let idx         = br.read_byte()? as usize;
+                        clr = self.octets[idx];
+                    }
+                    for _ in 0..len {
+                        let flg0        = br.read_u16be()? as usize;
+                        let flg1        = br.read_u16be()? as usize;
+                        let flg2        = br.read_u16be()? as usize;
+
+                        let line0 = flg0 >> 4;
+                        let line1 = flg1 >> 4;
+                        let line2 = flg2 >> 4;
+                        let line3 = ((flg0 & 0xF) << 8) | ((flg1 & 0xF) << 4) | (flg2 & 0xF);
+                        let flags = [line0, line1, line2, line3];
+                        for j in 0..4 {
+                            let flg = flags[j];
+                            for i in 0..4 {
+                                block[i + j * 4] = clr[(flg >> (9 - i * 3)) & 7];
+                            }
+                        }
+                        Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                        llblock = lblock;
+                        lblock = block;
+                    }
+                },
+                _ => {
+                    validate!((opcode & 0xF0) != 0xF0);
+                    for _ in 0..len {
+                                          br.read_buf(&mut block)?;
+                        Self::put_block(&mut frm.data[doff + x..], stride, &block);
+                        x += 4;
+                        if x == self.width {
+                            x = 0;
+                            doff += stride * 4;
+                        }
+                        llblock = lblock;
+                        lblock = block;
+                    }
+                },
+            };
+            blockpos += len;
+        }
+
+        let paloff = frm.offset[1];
+        let dpal = &mut frm.data[paloff..];
+        for sd in pkt.side_data.iter() {
+            match *sd {
+                NASideData::Palette(_, ref pal) => {
+                    for (dst, src) in dpal.chunks_mut(3).zip(pal.chunks(4)) {
+                        dst[0] = src[0];
+                        dst[1] = src[1];
+                        dst[2] = src[2];
+                    }
+                    break;
+                },
+                _ => {},
+            };
+        }
+        let buftype = NABufferType::Video(buf);
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype);
+        frm.set_keyframe(!has_skips);
+        frm.set_frame_type(if !has_skips { FrameType::I } else { FrameType::P });
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.hams.clear();
+    }
+}
+
+impl NAOptionHandler for SmcDecoder {
+    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(SmcDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_smc() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-smc", "assets/QT/aletrek-smc.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x4ea351ee, 0x279beedd, 0x71738173, 0x0fba61e8],
+                            [0x2c5ea61c, 0x1f539c55, 0x9234aa95, 0xd60be3ef],
+                            [0x307955c9, 0x0bc6d4cb, 0x7bebef1e, 0x5f2f3aee],
+                            [0x00db3e90, 0x9f57baef, 0x23e6c43b, 0xe9d6dc44],
+                            [0x54f2e3eb, 0x6313a0df, 0xb4b52777, 0x10f020f0],
+                            [0xdefb0b7d, 0xbdaa77c8, 0xb053d60c, 0xe836b9b0],
+                            [0xb820f95b, 0x0ce11d8a, 0xcfd8f623, 0x2b3acb1d]]));
+    }
+    #[test]
+    fn test_smc_gray() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "qt-smc", "assets/QT/aletrek-smc-gray.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x72e87d61, 0x85cde631, 0x780eea35, 0x7dfb8dfb],
+                            [0xc41fa1a8, 0x1f038e2e, 0xd67189fd, 0x566e74a8],
+                            [0xc2d8e57f, 0x501c5618, 0xdd6cd85a, 0x2c05f0b0],
+                            [0x7d530e44, 0xf02646d6, 0xbab960d0, 0x39ea2344],
+                            [0x46a2d3dc, 0x93684f3e, 0x88102523, 0x02d19236],
+                            [0x78995cd8, 0x3fbcbba2, 0x692d6e19, 0x25334ed0],
+                            [0x9632de1a, 0xccbe20a8, 0x4cc5fabe, 0x4dadddbe]]));
+    }
+}
diff --git a/nihav-qt/src/codecs/svq1.rs b/nihav-qt/src/codecs/svq1.rs
new file mode 100644 (file)
index 0000000..68db3a3
--- /dev/null
@@ -0,0 +1,565 @@
+use nihav_core::codecs::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_core::io::intcode::*;
+use nihav_codec_support::codecs::{MV, ZERO_MV};
+use nihav_codec_support::codecs::blockdsp::*;
+
+use super::svq1data::*;
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+enum SVQ1FrameType {
+    I,
+    P,
+    Drop,
+}
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+enum BlockType {
+    Intra,
+    Skip,
+    OneMV,
+    FourMV,
+}
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+#[allow(clippy::enum_variant_names)]
+enum BlockDiv {
+    Div16x16,
+    Div16x8,
+    Div8x8,
+    Div8x4,
+    Div4x4,
+    Div4x2,
+}
+
+impl BlockDiv {
+    fn is_final(self) -> bool { self == BlockDiv::Div4x2 }
+    fn split(self) -> (Self, usize, usize) {
+        match self {
+            BlockDiv::Div16x16 => (BlockDiv::Div16x8, 0, 8),
+            BlockDiv::Div16x8  => (BlockDiv::Div8x8, 8, 0),
+            BlockDiv::Div8x8   => (BlockDiv::Div8x4, 0, 4),
+            BlockDiv::Div8x4   => (BlockDiv::Div4x4, 4, 0),
+            BlockDiv::Div4x4   => (BlockDiv::Div4x2, 0, 2),
+            BlockDiv::Div4x2   => unreachable!(),
+        }
+    }
+    fn get_size(self) -> (usize, usize) {
+        match self {
+            BlockDiv::Div16x16 => (16, 16),
+            BlockDiv::Div16x8  => (16,  8),
+            BlockDiv::Div8x8   => ( 8,  8),
+            BlockDiv::Div8x4   => ( 8,  4),
+            BlockDiv::Div4x4   => ( 4,  4),
+            BlockDiv::Div4x2   => ( 4,  2),
+        }
+    }
+    fn get_level(self) -> usize {
+        match self {
+            BlockDiv::Div16x16 => 5,
+            BlockDiv::Div16x8  => 4,
+            BlockDiv::Div8x8   => 3,
+            BlockDiv::Div8x4   => 2,
+            BlockDiv::Div4x4   => 1,
+            BlockDiv::Div4x2   => 0,
+        }
+    }
+}
+
+const BLOCK_TYPES: [BlockType; 4] = [ BlockType::Skip, BlockType::OneMV, BlockType::FourMV, BlockType::Intra ];
+
+impl SVQ1FrameType {
+    fn is_ref(self) -> bool {
+        self != SVQ1FrameType::Drop
+    }
+    fn is_intra(self) -> bool {
+        self == SVQ1FrameType::I
+    }
+    fn to_frame_type(self) -> FrameType {
+        match self {
+            SVQ1FrameType::I => FrameType::I,
+            SVQ1FrameType::P => FrameType::P,
+            SVQ1FrameType::Drop => FrameType::P,
+        }
+    }
+    fn from_id(id: u32) -> DecoderResult<Self> {
+        match id {
+            0 => Ok(SVQ1FrameType::I),
+            1 => Ok(SVQ1FrameType::P),
+            2 => Ok(SVQ1FrameType::Drop),
+            _ => Err(DecoderError::InvalidData),
+        }
+    }
+}
+
+struct SVQ1DescReader {
+    table:  &'static [[u8; 2]],
+    bias:   i16,
+}
+
+impl CodebookDescReader<i16> for SVQ1DescReader {
+    fn bits(&mut self, idx: usize) -> u8 { self.table[idx][1] }
+    fn code(&mut self, idx: usize) -> u32 { u32::from(self.table[idx][0]) }
+    fn sym(&mut self, idx: usize) -> i16 { (idx as i16) + self.bias }
+    fn len(&mut self) -> usize { self.table.len() }
+}
+
+struct SVQ1InterMeanDescReader {}
+
+impl CodebookDescReader<i16> for SVQ1InterMeanDescReader {
+    fn bits(&mut self, idx: usize) -> u8 { SVQ_INTER_MEAN_CODES[idx][1] as u8 }
+    fn code(&mut self, idx: usize) -> u32 { u32::from(SVQ_INTER_MEAN_CODES[idx][0]) }
+    fn sym(&mut self, idx: usize) -> i16 { (idx as i16) - 256 }
+    fn len(&mut self) -> usize { SVQ_INTER_MEAN_CODES.len() }
+}
+
+struct SVQ1Decoder {
+    info:       NACodecInfoRef,
+    width:      usize,
+    height:     usize,
+    ref_frm:    Option<NAVideoBufferRef<u8>>,
+    mvs:        Vec<MV>,
+    intra_stages_cb:    Vec<Codebook<i16>>,
+    inter_stages_cb:    Vec<Codebook<i16>>,
+    intra_mean_cb:      Codebook<i16>,
+    inter_mean_cb:      Codebook<i16>,
+    mv_cb:              Codebook<i16>,
+
+    div_list:           [(BlockDiv, usize); 64],
+}
+
+impl SVQ1Decoder {
+    #[allow(clippy::needless_range_loop)]
+    fn new() -> Self {
+        let mut intra_stages_cb = Vec::with_capacity(6);
+        for i in 0..6 {
+            let mut cbd = SVQ1DescReader { table: &SVQ_INTRA_STAGE_CODES[i], bias: -1 };
+            let cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+            intra_stages_cb.push(cb);
+        }
+        let mut inter_stages_cb = Vec::with_capacity(6);
+        for i in 0..6 {
+            let mut cbd = SVQ1DescReader { table: &SVQ_INTER_STAGE_CODES[i], bias: -1 };
+            let cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+            inter_stages_cb.push(cb);
+        }
+        let mut cbd = SVQ1DescReader { table: &SVQ_INTRA_MEAN_CODES, bias: 0 };
+        let intra_mean_cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+        let mut cbd = SVQ1InterMeanDescReader {};
+        let inter_mean_cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+        let mut cbd = SVQ1DescReader { table: &SVQ_MV_CODES, bias: 0 };
+        let mv_cb = Codebook::new(&mut cbd, CodebookMode::MSB).unwrap();
+        Self {
+            info:       NACodecInfoRef::default(),
+            width:      0,
+            height:     0,
+            ref_frm:    None,
+            mvs:        Vec::new(),
+            intra_stages_cb, inter_stages_cb, intra_mean_cb, inter_mean_cb, mv_cb,
+            div_list:   [(BlockDiv::Div16x16, 0); 64],
+        }
+    }
+    fn read_mv(&self, br: &mut BitReader) -> DecoderResult<MV> {
+        let mut x                       = br.read_cb(&self.mv_cb)?;
+        if x > 0 && br.read_bool()? {
+            x = -x;
+        }
+        let mut y                       = br.read_cb(&self.mv_cb)?;
+        if y > 0 && br.read_bool()? {
+            y = -y;
+        }
+        Ok(MV { x, y })
+    }
+    #[allow(clippy::too_many_arguments)]
+    fn pred_mv(&self, x: usize, y: usize, w: usize, mv_idx: usize, mvstride: usize, blk_idx: usize, diff: MV) -> MV {
+        let a_mv = if x > 0 || (blk_idx & 1) != 0 { self.mvs[mv_idx - 1] } else { ZERO_MV };
+        let b_mv = if y > 0 || (blk_idx & 2) != 0 { self.mvs[mv_idx - mvstride]  } else { a_mv };
+        let c_mv = match blk_idx {
+                0 => if y > 0 && x + 16 < w { self.mvs[mv_idx + 2 - mvstride] } else { ZERO_MV },
+                1 => if y > 0 && x + 16 < w { self.mvs[mv_idx + 1 - mvstride] } else { ZERO_MV },
+                2 => self.mvs[mv_idx + 1 - mvstride],
+                _ => self.mvs[mv_idx - 1 - mvstride],
+            };
+        let mut new_mv = diff + MV::pred(a_mv, b_mv, c_mv);
+        if      new_mv.x >=  32 { new_mv.x -= 64; }
+        else if new_mv.x <= -32 { new_mv.x += 64; }
+        if      new_mv.y >=  32 { new_mv.y -= 64; }
+        else if new_mv.y <= -32 { new_mv.y += 64; }
+        new_mv
+    }
+    fn decode_intra_block(&mut self, br: &mut BitReader, dst: &mut [u8], dstride: usize) -> DecoderResult<()> {
+        self.div_list[0] = (BlockDiv::Div16x16, 0);
+        let mut idx = 0;
+        let mut end = 1;
+        while idx < end {
+            let (div, off) = self.div_list[idx];
+            if !div.is_final() && br.read_bool()? {
+                let (ndiv, xoff, yoff) = div.split();
+                self.div_list[end] = (ndiv, off);
+                end += 1;
+                self.div_list[end] = (ndiv, off + xoff + yoff * dstride);
+                end += 1;
+            } else {
+                let level = div.get_level();
+                let stages              = br.read_cb(&self.intra_stages_cb[level])?;
+                if level > 3 {
+                    validate!(stages <= 0);
+                }
+                let (w, h) = div.get_size();
+                let fill = if stages < 0 { 0 } else { br.read_cb(&self.intra_mean_cb)? } as u8;
+                for line in dst[off..].chunks_mut(dstride).take(h) {
+                    for el in line.iter_mut().take(w) {
+                        *el = fill;
+                    }
+                }
+                if stages > 0 {
+                    for stage in 0..(stages as usize) {
+                        let idx         = br.read(4)? as usize;
+                        let src: &[i8] = match div {
+                                BlockDiv::Div8x8 => &SVQ_INTRA_CB_8X8[stage * 16 + idx],
+                                BlockDiv::Div8x4 => &SVQ_INTRA_CB_8X4[stage * 16 + idx],
+                                BlockDiv::Div4x4 => &SVQ_INTRA_CB_4X4[stage * 16 + idx],
+                                BlockDiv::Div4x2 => &SVQ_INTRA_CB_4X2[stage * 16 + idx],
+                                _ => unreachable!(),
+                            };
+                        for (line, src) in dst[off..].chunks_mut(dstride).zip(src.chunks(w)) {
+                            for x in 0..w {
+                                line[x] = (i16::from(line[x]) + i16::from(src[x])).max(0).min(255) as u8;
+                            }
+                        }
+                    }
+                }
+            }
+            idx += 1;
+        }
+        Ok(())
+    }
+    fn decode_inter_block(&mut self, br: &mut BitReader, dst: &mut [u8], dstride: usize) -> DecoderResult<()> {
+        self.div_list[0] = (BlockDiv::Div16x16, 0);
+        let mut idx = 0;
+        let mut end = 1;
+        while idx < end {
+            let (div, off) = self.div_list[idx];
+            if !div.is_final() && br.read_bool()? {
+                let (ndiv, xoff, yoff) = div.split();
+                self.div_list[end] = (ndiv, off);
+                end += 1;
+                self.div_list[end] = (ndiv, off + xoff + yoff * dstride);
+                end += 1;
+            } else {
+                let level = div.get_level();
+                let stages              = br.read_cb(&self.inter_stages_cb[level])?;
+                if level > 3 {
+                    validate!(stages <= 0);
+                }
+                let (w, h) = div.get_size();
+                let fill = if stages < 0 { 0 } else { br.read_cb(&self.inter_mean_cb)? };
+                if fill != 0 {
+                    for line in dst[off..].chunks_mut(dstride).take(h) {
+                        for el in line.iter_mut().take(w) {
+                            *el = (i16::from(*el) + fill).max(0).min(255) as u8;
+                        }
+                    }
+                }
+                if stages > 0 {
+                    for stage in 0..(stages as usize) {
+                        let idx         = br.read(4)? as usize;
+                        let src: &[i8] = match div {
+                                BlockDiv::Div8x8 => &SVQ_INTER_CB_8X8[stage * 16 + idx],
+                                BlockDiv::Div8x4 => &SVQ_INTER_CB_8X4[stage * 16 + idx],
+                                BlockDiv::Div4x4 => &SVQ_INTER_CB_4X4[stage * 16 + idx],
+                                BlockDiv::Div4x2 => &SVQ_INTER_CB_4X2[stage * 16 + idx],
+                                _ => unreachable!(),
+                            };
+                        for (line, src) in dst[off..].chunks_mut(dstride).zip(src.chunks(w)) {
+                            for x in 0..w {
+                                line[x] = (i16::from(line[x]) + i16::from(src[x])).max(0).min(255) as u8;
+                            }
+                        }
+                    }
+                }
+            }
+            idx += 1;
+        }
+        Ok(())
+    }
+    fn decode_plane(&mut self, br: &mut BitReader, dframe: &mut NASimpleVideoFrame<u8>, plane: usize, is_intra: bool) -> DecoderResult<()> {
+        let (w, h) = if plane == 0 {
+                ((self.width + 15) & !15, (self.height + 15) & !15)
+            } else {
+                ((self.width / 4 + 15) & !15, (self.height / 4 + 15) & !15)                
+            };
+        let mvstride = w / 8;
+        self.mvs.truncate(0);
+        self.mvs.resize(mvstride * (h / 8), ZERO_MV);
+        let mut mv_idx = 0;
+
+        let mut doff = dframe.offset[plane];
+        let dstride = dframe.stride[plane];
+        for y in (0..h).step_by(16) {
+            for x in (0..w).step_by(16) {
+                let block_type = if is_intra {
+                        BlockType::Intra
+                    } else {
+                        let idx         = br.read_code(UintCodeType::LimitedZeroes(3))? as usize;
+                        BLOCK_TYPES[idx]
+                    };
+                match block_type {
+                    BlockType::Intra => {
+                        self.decode_intra_block(br, &mut dframe.data[doff + x..], dstride)?;
+                    },
+                    BlockType::Skip => {
+                        if let Some(ref rfrm) = self.ref_frm {
+                            let sstride = rfrm.get_stride(plane);
+                            let soff = rfrm.get_offset(plane) + y * sstride;
+                            let src = &rfrm.get_data()[soff + x..];
+                            let dst = &mut dframe.data[doff + x..];
+                            for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(16) {
+                                dline[..16].copy_from_slice(&sline[..16]);
+                            }
+                        }
+                    },
+                    BlockType::OneMV => {
+                        let mv = self.read_mv(br)?;
+                        let new_mv = self.pred_mv(x, y, w, mv_idx + x / 8, mvstride, 0, mv);
+                        self.mvs[mv_idx + x / 8] = new_mv;
+                        self.mvs[mv_idx + x / 8 + 1] = new_mv;
+                        self.mvs[mv_idx + mvstride + x / 8] = new_mv;
+                        self.mvs[mv_idx + mvstride + x / 8 + 1] = new_mv;
+                        if let Some(ref rfrm) = self.ref_frm {
+                            let mode = ((new_mv.x & 1) + (new_mv.y & 1) * 2) as usize;
+                            copy_block(dframe, rfrm.clone(), plane, x, y, new_mv.x >> 1, new_mv.y >> 1, 16, 16, 0, 1, mode, HALFPEL_INTERP_FUNCS);
+                        }
+                        self.decode_inter_block(br, &mut dframe.data[doff + x..], dstride)?;
+                    },
+                    BlockType::FourMV => {
+                        for i in 0..4 {
+                            let mv = self.read_mv(br)?;
+                            let cur_idx = mv_idx + x / 8 + (i & 1) + (i >> 1) * mvstride;
+                            let new_mv = self.pred_mv(x, y, w, cur_idx, mvstride, i, mv);
+                            self.mvs[cur_idx] = new_mv;
+                            if let Some(ref rfrm) = self.ref_frm {
+                                let mode = ((new_mv.x & 1) + (new_mv.y & 1) * 2) as usize;
+                                copy_block(dframe, rfrm.clone(), plane, x + (i & 1) * 8, y + (i >> 1) * 8, new_mv.x >> 1, new_mv.y >> 1, 8, 8, 0, 1, mode, HALFPEL_INTERP_FUNCS);
+                            }
+                        }
+                        self.decode_inter_block(br, &mut dframe.data[doff + x..], dstride)?;
+                    },
+                };
+            }
+            doff += dstride * 16;
+            mv_idx += mvstride * 2;
+        }
+        Ok(())
+    }
+}
+
+impl NADecoder for SVQ1Decoder {
+    fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            self.width  = vinfo.get_width();
+            self.height = vinfo.get_height();
+            let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(self.width, self.height, false, YUV410_FORMAT));
+            self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref();
+            supp.pool_u8.set_dec_bufs(2);
+            supp.pool_u8.prealloc_video(NAVideoInfo::new(vinfo.get_width(), vinfo.get_height(), false, YUV410_FORMAT), 6)?;
+            self.mvs = Vec::with_capacity((self.width + 15) / 4 * ((self.height + 15) / 4));
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    #[allow(clippy::collapsible_if)]
+    fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() >= 2);
+        let mut br = BitReader::new(&src, BitReaderMode::BE);
+
+        let fcode                       = br.read(22)?;
+        validate!((fcode & 0x60) != 0);
+        let _pts                        = br.read(8)?;
+        let ptype                       = br.read(2)?;
+        let ftype = SVQ1FrameType::from_id(ptype)?;
+        let mut frm_data = Vec::new();
+        if fcode != 0x20 {
+            frm_data.extend_from_slice(&src);
+            for i in 0..4 {
+                let a = frm_data[i * 4 + 4];
+                let b = frm_data[i * 4 + 5];
+                let c = frm_data[i * 4 + 6];
+                let d = frm_data[i * 4 + 7];
+                frm_data[i * 4 + 4] = c ^ frm_data[32 - i * 4];
+                frm_data[i * 4 + 5] = d ^ frm_data[33 - i * 4];
+                frm_data[i * 4 + 6] = a ^ frm_data[34 - i * 4];
+                frm_data[i * 4 + 7] = b ^ frm_data[35 - i * 4];
+            }
+            br = BitReader::new(&frm_data, BitReaderMode::BE);
+            br.skip(32)?;
+        }
+        if ftype.is_intra() {
+            if fcode == 0x50 || fcode == 0x60 {
+                let _checksum           = br.read(16)? as u16;
+//                let crc = calc_crc(frm_data.as_slice(), 0);
+//                validate!(crc == _checksum);
+            }
+            if fcode == 0x40 || fcode == 0x60 || fcode == 0x70 {
+                let str_len             = br.read(8)? as usize;
+                for _ in 0..str_len {
+                                          br.skip(8)?;
+                }
+            }
+                                          br.skip(2)?;
+                                          br.skip(2)?;
+                                          br.skip(1)?;
+            let size_id                 = br.read(3)? as usize;
+            let (w, h) = if size_id < FRAME_SIZES.len() {
+                    FRAME_SIZES[size_id]
+                } else {
+                    let w               = br.read(12)? as usize;
+                    let h               = br.read(12)? as usize;
+                    validate!(w >= 16 && h >= 16);
+                    (w, h)
+                };
+            if self.width != w || self.height != h {
+                self.flush();
+                self.width  = w;
+                self.height = h;
+                let vinfo = NAVideoInfo::new(self.width, self.height, false, YUV410_FORMAT);
+                supp.pool_u8.reset();
+                supp.pool_u8.prealloc_video(vinfo, 6)?;
+                let nmb = ((w + 15) / 4) * ((h + 15) / 4);
+                if self.mvs.capacity() < nmb {
+                    let add = nmb - self.mvs.capacity();
+                    self.mvs.reserve(add);
+                }
+            }
+        } else {
+            if self.ref_frm.is_none() {
+                return Err(DecoderError::MissingReference);
+            }
+        }
+        if br.read_bool()? {
+            let _pkt_crc                = br.read_bool()?;
+            let _comp_crc               = br.read_bool()?;
+            let marker                  = br.read(2)?;
+            validate!(marker == 0);
+        }
+        if br.read_bool()? {
+                                          br.skip(1)?;
+                                          br.skip(4)?;
+                                          br.skip(1)?;
+                                          br.skip(2)?;
+            while br.read_bool()? { }
+        }
+
+        let ret = supp.pool_u8.get_free();
+        if ret.is_none() {
+            return Err(DecoderError::AllocError);
+        }
+
+        let mut buf = ret.unwrap();
+        let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+        self.decode_plane(&mut br, &mut dframe, 0, ftype.is_intra())?;
+        self.decode_plane(&mut br, &mut dframe, 1, ftype.is_intra())?;
+        self.decode_plane(&mut br, &mut dframe, 2, ftype.is_intra())?;
+
+        if ftype.is_ref() {
+            self.ref_frm = Some(buf.clone());
+        }
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
+        frm.set_keyframe(ftype.is_intra());
+        frm.set_frame_type(ftype.to_frame_type());
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.ref_frm = None;
+    }
+}
+
+impl NAOptionHandler for SVQ1Decoder {
+    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(SVQ1Decoder::new())
+}
+
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_svq1() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+        test_decoding("mov", "sorenson-video", "assets/QT/adpcm-bug.mov", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                            [0x90c5eb74, 0xcb942d7d, 0x84c5e444, 0x7f1ba2c2],
+                            [0x650ae6f7, 0x9a0a6ec2, 0x0d907064, 0xb4c37321],
+                            [0xa04e865b, 0xdbd65920, 0x4703d7dd, 0x962707a1],
+                            [0xe89c98bc, 0x356791bb, 0xfb6f7302, 0x2250ef05],
+                            [0x282ef2a7, 0x235541b4, 0x55055d99, 0x1a8d0b29],
+                            [0x56328694, 0x27157f78, 0x4bc6ddda, 0x03dcde68],
+                            [0x5a694576, 0xd2434aea, 0x6859d48c, 0x275e02c9]]));
+    }
+}
+
+const FRAME_SIZES: [(usize, usize); 7] = [
+    (160, 120), (128,  96), (176, 144), (352, 288),
+    (704, 576), (240, 180), (320, 240)
+];
+
+/*const CRC_TABLE: [u16; 256] = [ //CCITT 16-bit CRC?
+    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+    0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+    0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+    0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+    0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+    0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+    0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+    0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+    0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+    0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+    0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+    0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+    0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+    0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+    0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+    0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+    0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+    0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+    0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+    0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+    0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+    0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+    0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+    0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+    0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+    0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+    0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+    0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+    0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+    0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+    0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+    0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+];
+
+fn calc_crc(src: &[u8], start: u16) -> u16 {
+    let mut crc = start;
+    for byte in src.iter() {
+        crc = CRC_TABLE[(*byte ^ ((crc >> 8) as u8)) as usize] ^ (crc << 8);
+    }
+    crc
+}*/
diff --git a/nihav-qt/src/codecs/svq1data.rs b/nihav-qt/src/codecs/svq1data.rs
new file mode 100644 (file)
index 0000000..fcfa47b
--- /dev/null
@@ -0,0 +1,2583 @@
+pub const SVQ_MV_CODES: [[u8; 2]; 33] = [ // same as H.263
+    [ 1,  1], [ 1,  2], [ 1,  3], [ 1,  4], [ 3,  6], [ 5,  7], [ 4,  7], [ 3,  7],
+    [11,  9], [10,  9], [ 9,  9], [17, 10], [16, 10], [15, 10], [14, 10], [13, 10],
+    [12, 10], [11, 10], [10, 10], [ 9, 10], [ 8, 10], [ 7, 10], [ 6, 10], [ 5, 10],
+    [ 4, 10], [ 7, 11], [ 6, 11], [ 5, 11], [ 4, 11], [ 3, 11], [ 2, 11], [ 3, 12],
+    [ 2, 12]
+];
+
+pub const SVQ_INTRA_STAGE_CODES: [[[u8; 2]; 8]; 6] = [
+  [
+    [ 0x1, 5 ],  [ 0x1, 1 ],  [ 0x3, 3 ],  [ 0x2, 3 ],
+    [ 0x3, 4 ],  [ 0x2, 4 ],  [ 0x0, 5 ],  [ 0x1, 4 ]
+  ], [
+    [ 0x1, 4 ],  [ 0x3, 2 ],  [ 0x5, 3 ],  [ 0x4, 3 ],
+    [ 0x3, 3 ],  [ 0x2, 3 ],  [ 0x0, 4 ],  [ 0x1, 3 ]
+  ], [
+    [ 0x1, 5 ],  [ 0x1, 1 ],  [ 0x3, 3 ],  [ 0x0, 5 ],
+    [ 0x3, 4 ],  [ 0x2, 3 ],  [ 0x2, 4 ],  [ 0x1, 4 ]
+  ], [
+    [ 0x1, 6 ],  [ 0x1, 1 ],  [ 0x1, 2 ],  [ 0x0, 6 ],
+    [ 0x3, 4 ],  [ 0x2, 4 ],  [ 0x1, 5 ],  [ 0x1, 4 ]
+  ], [
+    [ 0x1, 6 ],  [ 0x1, 1 ],  [ 0x1, 2 ],  [ 0x3, 5 ],
+    [ 0x2, 5 ],  [ 0x0, 6 ],  [ 0x1, 5 ],  [ 0x1, 3 ]
+  ], [
+    [ 0x1, 7 ],  [ 0x1, 1 ],  [ 0x1, 2 ],  [ 0x1, 3 ],
+    [ 0x1, 4 ],  [ 0x1, 6 ],  [ 0x0, 7 ],  [ 0x1, 5 ]
+  ]
+];
+pub const SVQ_INTER_STAGE_CODES: [[[u8; 2]; 8]; 6] = [
+  [
+    [ 0x3, 2 ],  [ 0x5, 3 ],  [ 0x4, 3 ],  [ 0x3, 3 ],
+    [ 0x2, 3 ],  [ 0x1, 3 ],  [ 0x1, 4 ],  [ 0x0, 4 ]
+  ], [
+    [ 0x3, 2 ],  [ 0x5, 3 ],  [ 0x4, 3 ],  [ 0x3, 3 ],
+    [ 0x2, 3 ],  [ 0x1, 3 ],  [ 0x1, 4 ],  [ 0x0, 4 ]
+  ], [
+    [ 0x1, 1 ],  [ 0x3, 3 ],  [ 0x2, 3 ],  [ 0x3, 4 ],
+    [ 0x2, 4 ],  [ 0x1, 4 ],  [ 0x1, 5 ],  [ 0x0, 5 ]
+  ], [
+    [ 0x1, 1 ],  [ 0x3, 3 ],  [ 0x2, 3 ],  [ 0x3, 4 ],
+    [ 0x2, 4 ],  [ 0x1, 4 ],  [ 0x1, 5 ],  [ 0x0, 5 ]
+  ], [
+    [ 0x1, 1 ],  [ 0x3, 3 ],  [ 0x2, 3 ],  [ 0x3, 4 ],
+    [ 0x2, 4 ],  [ 0x1, 4 ],  [ 0x1, 5 ],  [ 0x0, 5 ]
+  ], [
+    [ 0x1, 1 ],  [ 0x1, 2 ],  [ 0x1, 3 ],  [ 0x3, 5 ],
+    [ 0x2, 5 ],  [ 0x1, 5 ],  [ 0x1, 6 ],  [ 0x0, 6 ]
+  ]
+];
+
+pub const SVQ_INTRA_MEAN_CODES: [[u8; 2]; 256] = [
+    [ 0x37,  6 ],  [ 0x56,  7 ],  [ 0x01, 17 ],  [ 0x01, 20 ],
+    [ 0x02, 20 ],  [ 0x03, 20 ],  [ 0x00, 20 ],  [ 0x04, 20 ],
+    [ 0x05, 20 ],  [ 0x03, 19 ],  [ 0x15, 11 ],  [ 0x42,  9 ],
+    [ 0x14, 11 ],  [ 0x03, 14 ],  [ 0x02, 14 ],  [ 0x01, 15 ],
+    [ 0x01, 16 ],  [ 0x01, 12 ],  [ 0x2B, 10 ],  [ 0x18, 11 ],
+    [ 0x0C, 11 ],  [ 0x41,  9 ],  [ 0x78,  8 ],  [ 0x6C,  8 ],
+    [ 0x55,  7 ],  [ 0x0F,  4 ],  [ 0x0E,  4 ],  [ 0x34,  6 ],
+    [ 0x51,  7 ],  [ 0x72,  8 ],  [ 0x6E,  8 ],  [ 0x40,  9 ],
+    [ 0x3F,  9 ],  [ 0x3E,  9 ],  [ 0x3D,  9 ],  [ 0x3C,  9 ],
+    [ 0x3B,  9 ],  [ 0x3A,  9 ],  [ 0x39,  9 ],  [ 0x38,  9 ],
+    [ 0x37,  9 ],  [ 0x43,  9 ],  [ 0x46,  9 ],  [ 0x47,  9 ],
+    [ 0x45,  9 ],  [ 0x44,  9 ],  [ 0x49,  9 ],  [ 0x48,  9 ],
+    [ 0x4A,  8 ],  [ 0x79,  8 ],  [ 0x76,  8 ],  [ 0x77,  8 ],
+    [ 0x71,  8 ],  [ 0x75,  8 ],  [ 0x74,  8 ],  [ 0x73,  8 ],
+    [ 0x6A,  8 ],  [ 0x55,  8 ],  [ 0x70,  8 ],  [ 0x6F,  8 ],
+    [ 0x52,  8 ],  [ 0x6D,  8 ],  [ 0x4C,  8 ],  [ 0x6B,  8 ],
+    [ 0x40,  7 ],  [ 0x69,  8 ],  [ 0x68,  8 ],  [ 0x67,  8 ],
+    [ 0x66,  8 ],  [ 0x65,  8 ],  [ 0x64,  8 ],  [ 0x63,  8 ],
+    [ 0x62,  8 ],  [ 0x61,  8 ],  [ 0x60,  8 ],  [ 0x5F,  8 ],
+    [ 0x5E,  8 ],  [ 0x5D,  8 ],  [ 0x5C,  8 ],  [ 0x5B,  8 ],
+    [ 0x5A,  8 ],  [ 0x59,  8 ],  [ 0x58,  8 ],  [ 0x57,  8 ],
+    [ 0x56,  8 ],  [ 0x3D,  7 ],  [ 0x54,  8 ],  [ 0x53,  8 ],
+    [ 0x3F,  7 ],  [ 0x51,  8 ],  [ 0x50,  8 ],  [ 0x4F,  8 ],
+    [ 0x4E,  8 ],  [ 0x4D,  8 ],  [ 0x41,  7 ],  [ 0x4B,  8 ],
+    [ 0x53,  7 ],  [ 0x3E,  7 ],  [ 0x48,  8 ],  [ 0x4F,  7 ],
+    [ 0x52,  7 ],  [ 0x45,  8 ],  [ 0x50,  7 ],  [ 0x43,  8 ],
+    [ 0x42,  8 ],  [ 0x41,  8 ],  [ 0x42,  7 ],  [ 0x43,  7 ],
+    [ 0x3E,  8 ],  [ 0x44,  7 ],  [ 0x3C,  8 ],  [ 0x45,  7 ],
+    [ 0x46,  7 ],  [ 0x47,  7 ],  [ 0x48,  7 ],  [ 0x49,  7 ],
+    [ 0x4A,  7 ],  [ 0x4B,  7 ],  [ 0x4C,  7 ],  [ 0x4D,  7 ],
+    [ 0x4E,  7 ],  [ 0x58,  7 ],  [ 0x59,  7 ],  [ 0x5A,  7 ],
+    [ 0x5B,  7 ],  [ 0x5C,  7 ],  [ 0x5D,  7 ],  [ 0x44,  8 ],
+    [ 0x49,  8 ],  [ 0x29,  8 ],  [ 0x3F,  8 ],  [ 0x3D,  8 ],
+    [ 0x3B,  8 ],  [ 0x2C,  8 ],  [ 0x28,  8 ],  [ 0x25,  8 ],
+    [ 0x26,  8 ],  [ 0x5E,  7 ],  [ 0x57,  7 ],  [ 0x54,  7 ],
+    [ 0x5F,  7 ],  [ 0x62,  7 ],  [ 0x63,  7 ],  [ 0x64,  7 ],
+    [ 0x61,  7 ],  [ 0x65,  7 ],  [ 0x67,  7 ],  [ 0x66,  7 ],
+    [ 0x35,  6 ],  [ 0x36,  6 ],  [ 0x60,  7 ],  [ 0x39,  8 ],
+    [ 0x3A,  8 ],  [ 0x38,  8 ],  [ 0x37,  8 ],  [ 0x36,  8 ],
+    [ 0x35,  8 ],  [ 0x34,  8 ],  [ 0x33,  8 ],  [ 0x32,  8 ],
+    [ 0x31,  8 ],  [ 0x30,  8 ],  [ 0x2D,  8 ],  [ 0x2B,  8 ],
+    [ 0x2A,  8 ],  [ 0x27,  8 ],  [ 0x40,  8 ],  [ 0x46,  8 ],
+    [ 0x47,  8 ],  [ 0x26,  9 ],  [ 0x25,  9 ],  [ 0x24,  9 ],
+    [ 0x23,  9 ],  [ 0x22,  9 ],  [ 0x2E,  8 ],  [ 0x2F,  8 ],
+    [ 0x1F,  9 ],  [ 0x36,  9 ],  [ 0x1D,  9 ],  [ 0x21,  9 ],
+    [ 0x1B,  9 ],  [ 0x1C,  9 ],  [ 0x19,  9 ],  [ 0x1A,  9 ],
+    [ 0x18,  9 ],  [ 0x17,  9 ],  [ 0x16,  9 ],  [ 0x1E,  9 ],
+    [ 0x20,  9 ],  [ 0x27,  9 ],  [ 0x28,  9 ],  [ 0x29,  9 ],
+    [ 0x2A,  9 ],  [ 0x2B,  9 ],  [ 0x2C,  9 ],  [ 0x2D,  9 ],
+    [ 0x2E,  9 ],  [ 0x2F,  9 ],  [ 0x30,  9 ],  [ 0x35,  9 ],
+    [ 0x31,  9 ],  [ 0x32,  9 ],  [ 0x33,  9 ],  [ 0x34,  9 ],
+    [ 0x19, 10 ],  [ 0x2A, 10 ],  [ 0x17, 10 ],  [ 0x16, 10 ],
+    [ 0x15, 10 ],  [ 0x28, 10 ],  [ 0x26, 10 ],  [ 0x25, 10 ],
+    [ 0x22, 10 ],  [ 0x21, 10 ],  [ 0x18, 10 ],  [ 0x14, 10 ],
+    [ 0x29, 10 ],  [ 0x12, 10 ],  [ 0x0D, 10 ],  [ 0x0E, 10 ],
+    [ 0x0F, 10 ],  [ 0x10, 10 ],  [ 0x11, 10 ],  [ 0x1A, 10 ],
+    [ 0x1B, 10 ],  [ 0x1C, 10 ],  [ 0x1D, 10 ],  [ 0x1E, 10 ],
+    [ 0x1F, 10 ],  [ 0x20, 10 ],  [ 0x13, 10 ],  [ 0x23, 10 ],
+    [ 0x24, 10 ],  [ 0x09, 11 ],  [ 0x08, 11 ],  [ 0x07, 11 ],
+    [ 0x27, 10 ],  [ 0x05, 11 ],  [ 0x0B, 11 ],  [ 0x06, 11 ],
+    [ 0x04, 11 ],  [ 0x03, 11 ],  [ 0x02, 11 ],  [ 0x01, 11 ],
+    [ 0x0A, 11 ],  [ 0x16, 11 ],  [ 0x19, 11 ],  [ 0x17, 11 ],
+    [ 0x0D, 11 ],  [ 0x0E, 11 ],  [ 0x0F, 11 ],  [ 0x10, 11 ],
+    [ 0x11, 11 ],  [ 0x12, 11 ],  [ 0x13, 11 ],  [ 0x01, 14 ]
+];
+pub const SVQ_INTER_MEAN_CODES: [[u16; 2]; 512] = [
+    [ 0x5A, 22 ],  [ 0xD4, 22 ],  [ 0xD5, 22 ],  [ 0xD6, 22 ],
+    [ 0xD7, 22 ],  [ 0xD8, 22 ],  [ 0xD9, 22 ],  [ 0xDA, 22 ],
+    [ 0xDB, 22 ],  [ 0xDC, 22 ],  [ 0xDD, 22 ],  [ 0xDE, 22 ],
+    [ 0xDF, 22 ],  [ 0xE0, 22 ],  [ 0xE1, 22 ],  [ 0xE2, 22 ],
+    [ 0xE3, 22 ],  [ 0xE4, 22 ],  [ 0xE5, 22 ],  [ 0xE6, 22 ],
+    [ 0xE8, 22 ],  [ 0xCB, 22 ],  [ 0xE9, 22 ],  [ 0xEA, 22 ],
+    [ 0xE7, 22 ],  [ 0xEC, 22 ],  [ 0xED, 22 ],  [ 0xEE, 22 ],
+    [ 0xEF, 22 ],  [ 0xF0, 22 ],  [ 0xF1, 22 ],  [ 0xF2, 22 ],
+    [ 0xF3, 22 ],  [ 0xF4, 22 ],  [ 0xF5, 22 ],  [ 0xF6, 22 ],
+    [ 0xF7, 22 ],  [ 0xF8, 22 ],  [ 0x102,22 ],  [ 0xEB, 22 ],
+    [ 0xF9, 22 ],  [ 0xFC, 22 ],  [ 0xFD, 22 ],  [ 0xFE, 22 ],
+    [ 0x100,22 ],  [ 0x5C, 22 ],  [ 0x60, 22 ],  [ 0x101,22 ],
+    [ 0x71, 22 ],  [ 0x104,22 ],  [ 0x105,22 ],  [ 0xFB, 22 ],
+    [ 0xFF, 22 ],  [ 0x86, 21 ],  [ 0xFA, 22 ],  [ 0x7C, 22 ],
+    [ 0x75, 22 ],  [ 0x103,22 ],  [ 0x78, 22 ],  [ 0xD3, 22 ],
+    [ 0x7B, 22 ],  [ 0x82, 22 ],  [ 0xD2, 22 ],  [ 0xD1, 22 ],
+    [ 0xD0, 22 ],  [ 0xCF, 22 ],  [ 0xCE, 22 ],  [ 0xCD, 22 ],
+    [ 0xCC, 22 ],  [ 0xC3, 22 ],  [ 0xCA, 22 ],  [ 0xC9, 22 ],
+    [ 0xC8, 22 ],  [ 0xC7, 22 ],  [ 0xC6, 22 ],  [ 0xC5, 22 ],
+    [ 0x8B, 22 ],  [ 0xC4, 22 ],  [ 0xC2, 22 ],  [ 0xC1, 22 ],
+    [ 0xC0, 22 ],  [ 0xBF, 22 ],  [ 0xBE, 22 ],  [ 0xBD, 22 ],
+    [ 0xBC, 22 ],  [ 0xBB, 22 ],  [ 0xBA, 22 ],  [ 0xB9, 22 ],
+    [ 0x61, 22 ],  [ 0x84, 22 ],  [ 0x85, 22 ],  [ 0x86, 22 ],
+    [ 0x87, 22 ],  [ 0x88, 22 ],  [ 0x89, 22 ],  [ 0x8A, 22 ],
+    [ 0x8C, 22 ],  [ 0x8D, 22 ],  [ 0x8E, 22 ],  [ 0x8F, 22 ],
+    [ 0x90, 22 ],  [ 0x91, 22 ],  [ 0x92, 22 ],  [ 0x93, 22 ],
+    [ 0x94, 22 ],  [ 0x95, 22 ],  [ 0x96, 22 ],  [ 0x97, 22 ],
+    [ 0x98, 22 ],  [ 0x99, 22 ],  [ 0x9A, 22 ],  [ 0x9B, 22 ],
+    [ 0x9C, 22 ],  [ 0x9D, 22 ],  [ 0x9E, 22 ],  [ 0x9F, 22 ],
+    [ 0xA0, 22 ],  [ 0xA1, 22 ],  [ 0xA2, 22 ],  [ 0xA3, 22 ],
+    [ 0xA4, 22 ],  [ 0xA5, 22 ],  [ 0xA6, 22 ],  [ 0xA7, 22 ],
+    [ 0xA8, 22 ],  [ 0xA9, 22 ],  [ 0xAA, 22 ],  [ 0xAB, 22 ],
+    [ 0x7F, 22 ],  [ 0x8F, 21 ],  [ 0xAC, 22 ],  [ 0xAD, 22 ],
+    [ 0xAE, 22 ],  [ 0xAF, 22 ],  [ 0xB0, 22 ],  [ 0xB1, 22 ],
+    [ 0x53, 20 ],  [ 0x90, 21 ],  [ 0xB2, 22 ],  [ 0x91, 21 ],
+    [ 0xB3, 22 ],  [ 0xB4, 22 ],  [ 0x54, 20 ],  [ 0xB5, 22 ],
+    [ 0xB6, 22 ],  [ 0x8C, 21 ],  [ 0x34, 19 ],  [ 0x3D, 18 ],
+    [ 0x55, 20 ],  [ 0xB7, 22 ],  [ 0xB8, 22 ],  [ 0x8B, 21 ],
+    [ 0x56, 20 ],  [ 0x3D, 19 ],  [ 0x57, 20 ],  [ 0x58, 20 ],
+    [ 0x40, 19 ],  [ 0x43, 19 ],  [ 0x47, 19 ],  [ 0x2A, 18 ],
+    [ 0x2E, 19 ],  [ 0x2C, 18 ],  [ 0x46, 19 ],  [ 0x59, 20 ],
+    [ 0x49, 19 ],  [ 0x2D, 19 ],  [ 0x38, 18 ],  [ 0x36, 18 ],
+    [ 0x39, 18 ],  [ 0x45, 19 ],  [ 0x28, 18 ],  [ 0x30, 18 ],
+    [ 0x35, 18 ],  [ 0x20, 17 ],  [ 0x44, 19 ],  [ 0x32, 18 ],
+    [ 0x31, 18 ],  [ 0x1F, 17 ],  [ 0x2F, 18 ],  [ 0x2E, 18 ],
+    [ 0x2D, 18 ],  [ 0x21, 17 ],  [ 0x22, 17 ],  [ 0x23, 17 ],
+    [ 0x24, 17 ],  [ 0x27, 16 ],  [ 0x23, 16 ],  [ 0x20, 16 ],
+    [ 0x1D, 16 ],  [ 0x25, 16 ],  [ 0x1E, 16 ],  [ 0x24, 16 ],
+    [ 0x2A, 16 ],  [ 0x26, 16 ],  [ 0x21, 15 ],  [ 0x29, 16 ],
+    [ 0x22, 15 ],  [ 0x23, 15 ],  [ 0x24, 15 ],  [ 0x1B, 15 ],
+    [ 0x1A, 15 ],  [ 0x1D, 15 ],  [ 0x1F, 15 ],  [ 0x27, 15 ],
+    [ 0x17, 14 ],  [ 0x18, 14 ],  [ 0x19, 14 ],  [ 0x1B, 14 ],
+    [ 0x1C, 14 ],  [ 0x1E, 14 ],  [ 0x25, 14 ],  [ 0x20, 14 ],
+    [ 0x21, 14 ],  [ 0x13, 13 ],  [ 0x14, 13 ],  [ 0x15, 13 ],
+    [ 0x16, 13 ],  [ 0x17, 13 ],  [ 0x18, 13 ],  [ 0x19, 13 ],
+    [ 0x1A, 13 ],  [ 0x18, 12 ],  [ 0x17, 12 ],  [ 0x15, 12 ],
+    [ 0x14, 12 ],  [ 0x13, 12 ],  [ 0x12, 12 ],  [ 0x0F, 11 ],
+    [ 0x10, 11 ],  [ 0x12, 11 ],  [ 0x13, 11 ],  [ 0x1B, 11 ],
+    [ 0x1A, 11 ],  [ 0x0E, 10 ],  [ 0x13, 10 ],  [ 0x0F, 10 ],
+    [ 0x10, 10 ],  [ 0x11, 10 ],  [ 0x12, 10 ],  [ 0x0D,  9 ],
+    [ 0x14,  9 ],  [ 0x15,  9 ],  [ 0x0C,  9 ],  [ 0x13,  9 ],
+    [ 0x0F,  8 ],  [ 0x0E,  8 ],  [ 0x10,  8 ],  [ 0x11,  8 ],
+    [ 0x0C,  7 ],  [ 0x09,  7 ],  [ 0x0A,  7 ],  [ 0x08,  6 ],
+    [ 0x09,  6 ],  [ 0x09,  5 ],  [ 0x08,  5 ],  [ 0x05,  4 ],
+    [ 0x01,  1 ],  [ 0x03,  3 ],  [ 0x07,  5 ],  [ 0x06,  5 ],
+    [ 0x0B,  6 ],  [ 0x0A,  6 ],  [ 0x0E,  7 ],  [ 0x0F,  7 ],
+    [ 0x0B,  7 ],  [ 0x0D,  7 ],  [ 0x0B,  8 ],  [ 0x0D,  8 ],
+    [ 0x0C,  8 ],  [ 0x0F,  9 ],  [ 0x10,  9 ],  [ 0x11,  9 ],
+    [ 0x0E,  9 ],  [ 0x12,  9 ],  [ 0x17, 10 ],  [ 0x14, 10 ],
+    [ 0x16, 10 ],  [ 0x15, 10 ],  [ 0x19, 11 ],  [ 0x18, 11 ],
+    [ 0x17, 11 ],  [ 0x16, 11 ],  [ 0x15, 11 ],  [ 0x14, 11 ],
+    [ 0x11, 11 ],  [ 0x19, 12 ],  [ 0x1A, 12 ],  [ 0x16, 12 ],
+    [ 0x1D, 12 ],  [ 0x1B, 12 ],  [ 0x1C, 12 ],  [ 0x20, 13 ],
+    [ 0x1C, 13 ],  [ 0x23, 13 ],  [ 0x22, 13 ],  [ 0x21, 13 ],
+    [ 0x1F, 13 ],  [ 0x1E, 13 ],  [ 0x1B, 13 ],  [ 0x1D, 13 ],
+    [ 0x24, 14 ],  [ 0x16, 14 ],  [ 0x1A, 14 ],  [ 0x22, 14 ],
+    [ 0x1D, 14 ],  [ 0x1F, 14 ],  [ 0x15, 14 ],  [ 0x23, 14 ],
+    [ 0x18, 15 ],  [ 0x20, 15 ],  [ 0x29, 15 ],  [ 0x28, 15 ],
+    [ 0x26, 15 ],  [ 0x25, 15 ],  [ 0x19, 15 ],  [ 0x1C, 15 ],
+    [ 0x1E, 15 ],  [ 0x17, 15 ],  [ 0x2C, 16 ],  [ 0x2B, 16 ],
+    [ 0x1C, 16 ],  [ 0x21, 16 ],  [ 0x2D, 16 ],  [ 0x28, 16 ],
+    [ 0x1F, 16 ],  [ 0x1B, 16 ],  [ 0x1A, 16 ],  [ 0x22, 16 ],
+    [ 0x2D, 17 ],  [ 0x32, 17 ],  [ 0x2C, 17 ],  [ 0x27, 17 ],
+    [ 0x31, 17 ],  [ 0x33, 17 ],  [ 0x2F, 17 ],  [ 0x2B, 17 ],
+    [ 0x37, 18 ],  [ 0x2A, 17 ],  [ 0x2E, 17 ],  [ 0x30, 17 ],
+    [ 0x29, 17 ],  [ 0x28, 17 ],  [ 0x26, 17 ],  [ 0x25, 17 ],
+    [ 0x2F, 19 ],  [ 0x33, 18 ],  [ 0x34, 18 ],  [ 0x30, 19 ],
+    [ 0x3A, 18 ],  [ 0x3B, 18 ],  [ 0x31, 19 ],  [ 0x3C, 18 ],
+    [ 0x2B, 18 ],  [ 0x29, 18 ],  [ 0x48, 19 ],  [ 0x27, 18 ],
+    [ 0x42, 19 ],  [ 0x41, 19 ],  [ 0x26, 18 ],  [ 0x52, 20 ],
+    [ 0x51, 20 ],  [ 0x3F, 19 ],  [ 0x3E, 19 ],  [ 0x39, 19 ],
+    [ 0x3C, 19 ],  [ 0x3B, 19 ],  [ 0x3A, 19 ],  [ 0x25, 18 ],
+    [ 0x38, 19 ],  [ 0x50, 20 ],  [ 0x37, 19 ],  [ 0x36, 19 ],
+    [ 0x87, 21 ],  [ 0x4F, 20 ],  [ 0x35, 19 ],  [ 0x4E, 20 ],
+    [ 0x33, 19 ],  [ 0x32, 19 ],  [ 0x4D, 20 ],  [ 0x4C, 20 ],
+    [ 0x83, 22 ],  [ 0x4B, 20 ],  [ 0x81, 22 ],  [ 0x80, 22 ],
+    [ 0x8E, 21 ],  [ 0x7E, 22 ],  [ 0x7D, 22 ],  [ 0x84, 21 ],
+    [ 0x8D, 21 ],  [ 0x7A, 22 ],  [ 0x79, 22 ],  [ 0x4A, 20 ],
+    [ 0x77, 22 ],  [ 0x76, 22 ],  [ 0x89, 21 ],  [ 0x74, 22 ],
+    [ 0x73, 22 ],  [ 0x72, 22 ],  [ 0x49, 20 ],  [ 0x70, 22 ],
+    [ 0x6F, 22 ],  [ 0x6E, 22 ],  [ 0x6D, 22 ],  [ 0x6C, 22 ],
+    [ 0x6B, 22 ],  [ 0x6A, 22 ],  [ 0x69, 22 ],  [ 0x68, 22 ],
+    [ 0x67, 22 ],  [ 0x66, 22 ],  [ 0x65, 22 ],  [ 0x64, 22 ],
+    [ 0x63, 22 ],  [ 0x62, 22 ],  [ 0x8A, 21 ],  [ 0x88, 21 ],
+    [ 0x5F, 22 ],  [ 0x5E, 22 ],  [ 0x5D, 22 ],  [ 0x85, 21 ],
+    [ 0x5B, 22 ],  [ 0x83, 21 ],  [ 0x59, 22 ],  [ 0x58, 22 ],
+    [ 0x57, 22 ],  [ 0x56, 22 ],  [ 0x55, 22 ],  [ 0x54, 22 ],
+    [ 0x53, 22 ],  [ 0x52, 22 ],  [ 0x51, 22 ],  [ 0x50, 22 ],
+    [ 0x4F, 22 ],  [ 0x4E, 22 ],  [ 0x4D, 22 ],  [ 0x4C, 22 ],
+    [ 0x4B, 22 ],  [ 0x4A, 22 ],  [ 0x49, 22 ],  [ 0x48, 22 ],
+    [ 0x47, 22 ],  [ 0x46, 22 ],  [ 0x45, 22 ],  [ 0x44, 22 ],
+    [ 0x43, 22 ],  [ 0x42, 22 ],  [ 0x41, 22 ],  [ 0x40, 22 ],
+    [ 0x3F, 22 ],  [ 0x3E, 22 ],  [ 0x3D, 22 ],  [ 0x3C, 22 ],
+    [ 0x3B, 22 ],  [ 0x3A, 22 ],  [ 0x39, 22 ],  [ 0x38, 22 ],
+    [ 0x37, 22 ],  [ 0x36, 22 ],  [ 0x35, 22 ],  [ 0x34, 22 ],
+    [ 0x33, 22 ],  [ 0x32, 22 ],  [ 0x31, 22 ],  [ 0x30, 22 ],
+    [ 0x2F, 22 ],  [ 0x2E, 22 ],  [ 0x2D, 22 ],  [ 0x2C, 22 ],
+    [ 0x2B, 22 ],  [ 0x2A, 22 ],  [ 0x29, 22 ],  [ 0x28, 22 ],
+    [ 0x27, 22 ],  [ 0x26, 22 ],  [ 0x25, 22 ],  [ 0x24, 22 ],
+    [ 0x23, 22 ],  [ 0x22, 22 ],  [ 0x21, 22 ],  [ 0x20, 22 ],
+    [ 0x1F, 22 ],  [ 0x1E, 22 ],  [ 0x1D, 22 ],  [ 0x1C, 22 ],
+    [ 0x1B, 22 ],  [ 0x1A, 22 ],  [ 0x19, 22 ],  [ 0x18, 22 ],
+    [ 0x17, 22 ],  [ 0x16, 22 ],  [ 0x15, 22 ],  [ 0x14, 22 ],
+    [ 0x13, 22 ],  [ 0x12, 22 ],  [ 0x11, 22 ],  [ 0x10, 22 ],
+    [ 0x0F, 22 ],  [ 0x0E, 22 ],  [ 0x0D, 22 ],  [ 0x0C, 22 ],
+    [ 0x0B, 22 ],  [ 0x0A, 22 ],  [ 0x09, 22 ],  [ 0x08, 22 ],
+    [ 0x07, 22 ],  [ 0x06, 22 ],  [ 0x05, 22 ],  [ 0x04, 22 ],
+    [ 0x03, 22 ],  [ 0x02, 22 ],  [ 0x01, 22 ],  [ 0x00, 22 ]
+];
+
+pub const SVQ_INTRA_CB_8X8: [[i8; 64]; 96] = [
+  [
+     4,   4,   3,   2,   2,   1,   0,  -1,   4,   3,   3,   2,   1,   0,  -1,  -1,
+     3,   3,   2,   2,   1,   0,  -1,  -2,   3,   2,   2,   1,   0,  -1,  -2,  -3,
+     2,   2,   1,   0,  -1,  -1,  -2,  -3,   2,   1,   0,   0,  -1,  -2,  -3,  -4,
+     1,   0,   0,  -1,  -2,  -3,  -4,  -4,   0,   0,  -1,  -2,  -2,  -3,  -4,  -4,
+  ], [
+     2,   3,   3,   3,   3,   3,   3,   3,   2,   2,   2,   2,   2,   2,   3,   3,
+     1,   2,   2,   2,   2,   2,   2,   2,   0,   1,   1,   1,   1,   1,   1,   1,
+    -1,   0,   0,   0,   0,   0,   1,   1,  -2,  -2,  -1,  -1,  -1,  -1,  -1,  -1,
+    -3,  -3,  -3,  -3,  -3,  -3,  -2,  -2,  -5,  -4,  -4,  -4,  -4,  -4,  -4,  -3,
+  ], [
+    -4,  -2,  -1,   0,   1,   2,   2,   3,  -4,  -2,  -1,   0,   1,   2,   3,   3,
+    -4,  -3,  -1,   0,   1,   2,   3,   3,  -4,  -3,  -1,   0,   1,   2,   3,   3,
+    -5,  -3,  -1,   0,   1,   2,   3,   3,  -5,  -3,  -1,   0,   1,   2,   3,   3,
+    -5,  -3,  -1,   0,   1,   1,   2,   3,  -5,  -3,  -2,  -1,   0,   1,   2,   3,
+  ], [
+     4,   4,   5,   5,   6,   6,   7,   7,   2,   2,   2,   3,   3,   4,   4,   4,
+     0,   0,   0,   0,   1,   1,   1,   2,  -2,  -2,  -2,  -2,  -1,  -1,  -1,   0,
+    -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,
+    -1,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -1,  -1,  -1,  -1,  -2,  -2,  -2,  -2,
+  ], [
+     5,   3,   1,  -1,  -2,  -3,  -3,  -3,   5,   3,   1,  -1,  -2,  -3,  -3,  -3,
+     5,   3,   1,  -1,  -2,  -3,  -3,  -3,   5,   3,   1,  -1,  -2,  -3,  -3,  -3,
+     5,   4,   1,   0,  -2,  -3,  -3,  -3,   6,   4,   2,   0,  -2,  -2,  -3,  -3,
+     6,   4,   2,   0,  -1,  -2,  -2,  -3,   6,   4,   2,   1,  -1,  -2,  -2,  -2,
+  ], [
+    -1,   1,   3,   3,   2,   0,  -3,  -6,  -1,   1,   3,   4,   3,   0,  -3,  -6,
+    -1,   1,   4,   4,   3,   1,  -3,  -6,  -1,   1,   3,   4,   3,   1,  -3,  -6,
+    -2,   1,   3,   4,   3,   1,  -3,  -6,  -2,   1,   3,   4,   3,   1,  -3,  -7,
+    -2,   1,   3,   3,   2,   0,  -3,  -7,  -2,   0,   2,   3,   2,   0,  -3,  -6,
+  ], [
+    10,   9,   8,   6,   6,   5,   4,   4,   6,   5,   4,   3,   2,   2,   2,   1,
+     2,   1,   0,  -1,  -2,  -2,  -2,  -1,  -1,  -2,  -3,  -4,  -4,  -4,  -4,  -3,
+    -2,  -3,  -4,  -4,  -5,  -4,  -4,  -3,  -2,  -2,  -3,  -3,  -3,  -3,  -2,  -2,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   1,   1,   1,   1,   1,   1,   1,   2,
+  ], [
+    -2,  -1,   1,   2,   4,   5,   7,   8,  -3,  -2,   0,   1,   3,   5,   7,   8,
+    -4,  -3,  -1,   0,   2,   4,   6,   7,  -5,  -4,  -2,  -1,   1,   3,   5,   7,
+    -6,  -5,  -3,  -2,   0,   2,   4,   6,  -6,  -5,  -4,  -2,  -1,   1,   3,   5,
+    -7,  -6,  -5,  -3,  -2,   0,   2,   3,  -8,  -7,  -5,  -4,  -3,  -1,   1,   2,
+  ], [
+    11,   9,   7,   5,   3,   1,  -1,  -1,  10,   8,   6,   3,   1,   0,  -2,  -2,
+     9,   7,   5,   2,   0,  -2,  -3,  -4,   8,   6,   3,   1,  -1,  -3,  -4,  -4,
+     6,   4,   2,  -1,  -3,  -4,  -5,  -5,   5,   3,   0,  -2,  -4,  -5,  -6,  -6,
+     3,   1,  -1,  -3,  -5,  -6,  -7,  -7,   2,   0,  -2,  -4,  -6,  -6,  -7,  -7,
+  ], [
+     5,   6,   7,   7,   7,   8,   8,   8,   3,   4,   5,   5,   6,   6,   6,   6,
+     0,   2,   2,   3,   4,   4,   4,   5,  -2,  -1,   0,   1,   2,   2,   3,   3,
+    -4,  -3,  -2,  -1,   0,   1,   1,   2,  -6,  -5,  -4,  -3,  -2,  -2,  -1,   0,
+    -8,  -7,  -6,  -6,  -5,  -4,  -3,  -3, -10,  -9,  -8,  -8,  -7,  -6,  -6,  -5,
+  ], [
+     6,   5,   3,   1,  -1,  -3,  -6,  -8,   6,   5,   4,   2,  -1,  -3,  -6,  -8,
+     6,   5,   4,   2,   0,  -3,  -6,  -8,   6,   5,   4,   2,   0,  -3,  -6,  -8,
+     6,   6,   4,   2,   0,  -3,  -6,  -8,   6,   5,   4,   2,   0,  -3,  -6,  -8,
+     6,   5,   4,   2,   0,  -3,  -6,  -8,   6,   5,   4,   2,  -1,  -3,  -5,  -8,
+  ], [
+    11,  10,   9,   8,   7,   6,   5,   4,   8,   8,   7,   6,   5,   4,   3,   2,
+     6,   5,   4,   4,   2,   2,   1,   0,   3,   3,   2,   1,   0,   0,  -1,  -2,
+     1,   1,   0,  -1,  -2,  -2,  -3,  -3,  -1,  -1,  -2,  -3,  -4,  -4,  -5,  -5,
+    -3,  -4,  -4,  -5,  -6,  -6,  -7,  -7,  -5,  -5,  -6,  -7,  -8,  -8,  -8,  -8,
+  ], [
+   -14, -13, -12, -11,  -9,  -7,  -6,  -4, -12, -11, -10,  -9,  -7,  -5,  -3,  -1,
+   -10,  -9,  -7,  -6,  -3,  -2,   0,   2,  -8,  -6,  -4,  -2,   0,   2,   4,   5,
+    -5,  -3,   0,   2,   4,   5,   7,   8,  -2,   0,   2,   4,   6,   8,   9,  10,
+     0,   3,   5,   7,   8,  10,  11,  12,   3,   5,   7,   8,  10,  11,  12,  12,
+  ], [
+   -19, -19, -18, -18, -17, -16, -15, -14, -15, -15, -14, -13, -12, -11, -10,  -9,
+   -11, -10,  -9,  -8,  -6,  -5,  -4,  -3,  -6,  -5,  -3,  -2,  -1,   0,   1,   2,
+    -1,   0,   2,   3,   4,   5,   6,   6,   4,   6,   7,   8,   9,  10,  10,  10,
+     9,  10,  11,  12,  13,  14,  14,  14,  12,  14,  14,  15,  16,  16,  16,  16,
+  ], [
+    22,  21,  19,  17,  14,  11,   9,   5,  20,  19,  17,  14,  11,   8,   4,   1,
+    17,  15,  13,  10,   6,   3,   0,  -4,  13,  11,   8,   5,   1,  -2,  -5,  -9,
+     9,   6,   3,  -1,  -4,  -7, -11, -13,   4,   0,  -3,  -6,  -9, -12, -15, -17,
+    -2,  -5,  -8, -11, -14, -16, -18, -20,  -8, -10, -13, -16, -17, -19, -21, -22,
+  ], [
+    17,  18,  18,  18,  17,  16,  16,  14,  16,  16,  15,  15,  14,  13,  12,  11,
+    12,  12,  11,  10,   9,   8,   7,   5,   7,   6,   6,   4,   3,   2,   1,  -1,
+     1,   0,  -1,  -2,  -3,  -4,  -5,  -6,  -5,  -6,  -7,  -8,  -9, -10, -11, -12,
+   -11, -12, -13, -14, -15, -16, -16, -17, -16, -17, -17, -18, -19, -20, -20, -20,
+  ], [
+     0,   0,   0,   0,  -1,  -1,  -2,  -3,   1,   0,   0,   0,   0,  -1,  -2,  -3,
+     1,   1,   0,   0,  -1,  -1,  -2,  -2,   1,   1,   1,   0,   0,  -1,  -1,  -2,
+     2,   1,   1,   1,   0,  -1,  -1,  -2,   2,   2,   1,   1,   0,   0,  -1,  -2,
+     2,   2,   1,   1,   1,   0,  -1,  -1,   2,   2,   1,   1,   1,   0,   0,  -2,
+  ], [
+     0,  -1,  -1,   0,   0,   1,   2,   3,   0,  -1,  -1,   0,   1,   1,   2,   2,
+    -1,  -1,  -1,  -1,   0,   1,   2,   2,  -1,  -1,  -2,  -1,   0,   1,   1,   2,
+    -1,  -2,  -2,  -1,   0,   0,   1,   2,  -1,  -2,  -2,  -2,  -1,   0,   1,   2,
+    -1,  -1,  -2,  -1,   0,   0,   1,   2,  -1,  -1,  -1,  -1,   0,   1,   1,   2,
+  ], [
+     3,   2,   2,   2,   1,   1,   0,   0,   3,   2,   2,   2,   2,   1,   0,   0,
+     2,   2,   2,   1,   1,   1,   0,   0,   2,   2,   1,   1,   1,   0,   0,  -1,
+     1,   1,   1,   0,   0,   0,  -1,  -1,   0,   0,  -1,  -1,  -1,  -1,  -1,  -1,
+    -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -3,  -3,  -3,  -2,  -2,  -2,  -2,
+  ], [
+     5,   2,   0,   0,  -1,   0,   0,   0,   4,   2,   0,  -1,  -1,  -1,   0,  -1,
+     4,   1,  -1,  -1,  -2,  -1,  -1,  -1,   4,   1,  -1,  -1,  -2,  -1,  -1,  -1,
+     4,   1,  -1,  -2,  -2,  -1,  -1,  -1,   4,   1,  -1,  -2,  -2,  -1,  -1,  -1,
+     4,   1,  -1,  -1,  -1,  -1,  -1,  -1,   4,   2,   0,  -1,   0,   0,   0,  -1,
+  ], [
+    -2,  -1,   0,   1,   1,   1,   1,   1,  -3,  -1,   0,   1,   1,   1,   1,   1,
+    -3,  -1,   0,   1,   1,   1,   1,   1,  -3,  -1,   0,   1,   1,   1,   1,   1,
+    -3,  -2,   0,   1,   2,   2,   1,   1,  -4,  -2,   0,   1,   2,   2,   2,   2,
+    -5,  -3,  -1,   1,   1,   2,   1,   2,  -5,  -3,  -2,   0,   1,   1,   1,   1,
+  ], [
+     3,   3,   1,   0,  -2,  -4,  -4,  -5,   3,   3,   2,   0,  -1,  -2,  -3,  -4,
+     2,   2,   1,   1,   0,  -1,  -2,  -2,   1,   1,   1,   1,   1,   0,   0,   0,
+     0,   0,   0,   1,   1,   1,   1,   1,  -2,  -1,  -1,   0,   0,   1,   2,   2,
+    -3,  -2,  -2,  -1,   0,   1,   2,   3,  -3,  -3,  -2,  -1,   0,   1,   2,   3,
+  ], [
+    -3,  -3,  -3,  -3,  -3,  -2,  -2,  -2,  -3,  -3,  -2,  -2,  -2,  -1,  -1,  -1,
+    -2,  -2,  -2,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,
+     0,   0,   0,   0,   1,   1,   1,   1,   0,   0,   1,   1,   2,   2,   2,   2,
+     1,   1,   1,   2,   2,   3,   3,   3,   2,   2,   2,   2,   3,   3,   3,   3,
+  ], [
+    -8,  -7,  -5,  -3,  -2,  -1,   0,  -1,  -4,  -3,  -1,   0,   1,   2,   1,   1,
+    -1,   1,   2,   3,   3,   2,   2,   1,   1,   2,   3,   3,   2,   2,   1,   0,
+     2,   3,   3,   2,   1,   0,   0,  -1,   1,   2,   1,   0,  -1,  -1,  -1,  -1,
+     1,   1,   0,  -1,  -1,  -2,  -2,  -1,   1,   1,   0,   0,  -1,  -1,   0,  -1,
+  ], [
+    -4,  -3,  -2,   0,   1,   2,   3,   3,  -4,  -3,  -2,   0,   1,   2,   2,   2,
+    -3,  -3,  -2,  -1,   0,   1,   1,   1,  -2,  -2,  -2,  -1,  -1,   0,   0,   0,
+     0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   2,   1,   1,   0,   0,  -1,  -1,  -2,
+     3,   3,   3,   1,   0,  -1,  -2,  -2,   5,   4,   4,   2,   1,   0,  -1,  -2,
+  ], [
+     0,   0,   0,   0,   1,   2,   3,   3,   0,  -1,   0,   0,   1,   2,   3,   3,
+     0,  -1,   0,   0,   1,   2,   3,   2,   0,   0,   0,   1,   1,   2,   2,   2,
+     2,   1,   1,   1,   1,   1,   1,   0,   2,   2,   2,   1,   0,   0,  -1,  -2,
+     2,   1,   0,   0,  -2,  -3,  -5,  -6,   0,  -1,  -1,  -3,  -5,  -6,  -8,  -9,
+  ], [
+    -2,   0,   1,   2,   2,   1,  -1,  -4,  -2,   0,   2,   2,   2,   1,  -1,  -4,
+    -2,   0,   2,   2,   2,   1,  -1,  -3,  -2,   0,   2,   2,   2,   1,  -1,  -3,
+    -2,  -1,   2,   2,   2,   1,  -1,  -3,  -2,  -1,   1,   2,   2,   1,  -1,  -3,
+    -3,  -1,   1,   2,   2,   1,  -1,  -3,  -2,  -1,   1,   2,   2,   1,  -1,  -3,
+  ], [
+    -1,   1,   1,  -1,  -3,  -3,   0,   4,  -1,   1,   1,  -1,  -3,  -3,   0,   4,
+    -1,   1,   1,   0,  -3,  -3,   0,   4,  -1,   1,   2,   0,  -3,  -3,   0,   5,
+     0,   1,   2,   0,  -3,  -4,   0,   4,   0,   1,   2,   0,  -3,  -4,   0,   5,
+     0,   1,   2,   0,  -3,  -3,   0,   4,   0,   1,   2,  -1,  -2,  -2,   0,   4,
+  ], [
+     6,   6,   5,   6,   5,   5,   5,   5,   2,   2,   2,   2,   2,   2,   2,   2,
+     0,   0,   0,   0,   0,   0,   0,   0,  -1,  -1,  -1,  -1,  -2,  -2,  -2,  -2,
+    -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,
+    -1,  -1,  -2,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+  ], [
+     2,   2,   2,   2,   2,   2,   2,   2,   0,   1,   1,   0,   0,   0,   0,   0,
+    -1,  -2,  -2,  -2,  -2,  -2,  -2,  -1,  -3,  -3,  -3,  -3,  -3,  -3,  -3,  -2,
+    -3,  -4,  -4,  -3,  -3,  -3,  -2,  -2,  -2,  -2,  -2,  -2,  -1,  -1,   0,   0,
+     0,   1,   1,   1,   2,   2,   3,   3,   3,   4,   4,   5,   5,   6,   6,   6,
+  ], [
+     4,   1,  -2,  -3,  -3,  -1,   1,   3,   4,   1,  -2,  -4,  -3,  -1,   1,   3,
+     5,   1,  -2,  -4,  -3,  -1,   1,   4,   5,   1,  -2,  -3,  -3,  -1,   2,   4,
+     5,   1,  -2,  -3,  -3,  -1,   2,   4,   4,   0,  -3,  -4,  -3,  -1,   2,   4,
+     4,   0,  -3,  -3,  -3,  -1,   1,   3,   3,   0,  -2,  -3,  -2,  -1,   1,   3,
+  ], [
+    -3,  -4,  -4,  -4,  -4,  -4,  -4,  -4,  -1,  -1,  -1,  -1,  -1,  -1,  -2,  -2,
+     2,   1,   1,   2,   2,   1,   1,   1,   3,   3,   3,   4,   4,   3,   3,   3,
+     3,   3,   3,   4,   4,   4,   3,   3,   1,   2,   1,   2,   2,   2,   2,   2,
+    -2,  -2,  -2,  -1,  -1,  -1,   0,   0,  -4,  -4,  -4,  -4,  -3,  -3,  -3,  -3,
+  ], [
+    -1,  -2,  -3,  -3,  -2,  -2,  -1,   0,   0,  -1,  -2,  -2,  -2,  -1,   0,   1,
+     2,   1,  -1,  -1,  -1,  -1,   0,   1,   3,   1,   0,  -1,  -1,   0,   0,   1,
+     3,   2,   0,  -1,   0,   0,   0,   1,   3,   1,   0,  -1,   0,   0,   0,   1,
+     3,   1,   0,  -1,   0,   0,   0,   1,   2,   1,   0,   0,   0,   0,   0,   1,
+  ], [
+     0,   0,   0,   1,   1,   2,   3,   4,   0,   0,  -1,   0,   0,   0,   2,   3,
+     0,  -1,  -1,  -1,  -1,  -1,   0,   1,   0,  -1,  -1,  -1,  -1,  -1,  -1,   0,
+     0,   0,  -1,  -1,  -1,  -2,  -2,  -1,   1,   0,   0,  -1,  -1,  -2,  -2,  -1,
+     2,   2,   1,   0,  -1,  -1,  -1,  -1,   3,   3,   2,   1,   0,  -1,  -1,   0,
+  ], [
+     1,   0,   1,   0,   0,  -1,  -2,  -1,   0,   0,   0,   0,  -1,  -1,  -2,  -1,
+     0,  -1,   0,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,   0,
+    -1,  -1,  -1,   0,   0,   0,   1,   1,  -1,  -1,  -1,   0,   1,   1,   2,   3,
+    -2,  -2,  -1,   0,   1,   2,   3,   4,  -2,  -2,  -1,   0,   1,   2,   4,   5,
+  ], [
+    -3,  -1,   1,   0,   0,  -1,   0,   1,  -3,   0,   1,   0,  -1,  -1,   0,   2,
+    -3,   0,   1,   0,  -1,  -1,   0,   2,  -2,   1,   2,   0,  -1,  -1,   0,   2,
+    -2,   1,   2,   0,  -1,  -1,   0,   2,  -2,   1,   2,   0,  -1,  -1,   0,   2,
+    -1,   2,   2,   0,  -1,  -1,   0,   2,  -1,   1,   1,   0,  -1,  -1,  -1,   1,
+  ], [
+    -2,  -2,  -1,   1,   3,   4,   3,   1,  -2,  -2,  -1,   0,   2,   3,   2,   0,
+    -2,  -2,  -1,   0,   1,   2,   1,  -1,  -1,  -1,  -1,   0,   1,   2,   1,  -1,
+    -1,  -1,  -1,   0,   1,   1,   0,  -2,   0,  -1,  -1,   0,   1,   1,   0,  -1,
+     0,  -1,  -1,   0,   1,   1,   1,  -1,   0,  -1,  -1,   0,   0,   1,   0,  -1,
+  ], [
+    -2,  -1,   0,   1,   1,   1,   1,   1,  -2,  -1,   0,   0,   0,   0,   0,   0,
+    -2,  -1,  -1,   0,  -1,  -1,  -2,  -2,  -2,  -1,  -1,  -1,  -1,  -2,  -2,  -3,
+    -1,   0,   1,   1,   0,  -1,  -2,  -2,   1,   2,   3,   3,   2,   1,   0,   0,
+     1,   2,   3,   3,   3,   2,   1,   0,   0,   0,   1,   1,   1,   1,   0,   0,
+  ], [
+     0,  -1,  -1,  -1,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   1,   1,
+     1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   2,   2,   1,   1,   1,   1,
+     1,   1,   1,   1,   1,   1,   1,   1,  -1,   0,   0,   1,   1,   0,   0,   0,
+    -3,  -2,  -1,  -1,  -1,  -1,   0,  -1,  -5,  -5,  -4,  -3,  -2,  -2,  -2,  -1,
+  ], [
+     1,   1,   1,   1,   2,   1,   0,  -1,   1,   1,   1,   2,   1,   1,   0,  -1,
+     1,   1,   1,   1,   1,   1,   0,  -2,   2,   1,   1,   1,   1,   1,   0,  -2,
+     1,   1,   0,   0,   0,   0,  -1,  -3,   1,   1,   0,   0,   0,  -1,  -2,  -3,
+     1,   1,   0,   0,  -1,  -1,  -2,  -4,   1,   0,   0,  -1,  -2,  -2,  -3,  -4,
+  ], [
+     8,   7,   5,   3,   2,   1,   1,   1,   2,   1,   0,   0,  -1,  -1,  -2,  -1,
+    -1,  -1,  -1,  -2,  -2,  -2,  -2,  -1,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,
+     0,   0,   0,   1,   1,   0,   0,   0,   0,   0,   1,   1,   1,   0,   0,   0,
+    -1,   0,   0,   0,   0,   0,  -1,  -1,  -2,  -2,  -1,  -1,  -1,  -2,  -2,  -1,
+  ], [
+     9,   4,   0,  -2,  -2,  -2,  -1,  -1,   7,   2,  -1,  -2,  -2,  -1,   0,   0,
+     4,   0,  -2,  -2,  -1,   0,   1,   1,   1,  -2,  -2,  -2,  -1,   0,   1,   1,
+    -1,  -2,  -2,  -1,   0,   1,   1,   1,  -1,  -2,  -1,   0,   1,   1,   1,   0,
+    -1,  -1,   0,   1,   1,   1,   0,  -1,   0,  -1,   0,   1,   0,   0,  -1,  -1,
+  ], [
+     0,   1,   1,   1,   1,   1,   0,   0,   1,   2,   2,   2,   1,   0,   0,   0,
+     2,   2,   2,   2,   1,   0,  -1,  -1,   1,   1,   1,   0,  -1,  -2,  -2,  -2,
+     0,   0,   0,  -1,  -2,  -3,  -2,  -2,  -1,  -1,  -1,  -2,  -2,  -2,  -1,   0,
+    -1,  -1,  -1,  -1,   0,   0,   1,   2,  -1,  -1,  -1,   0,   1,   2,   3,   4,
+  ], [
+    -1,  -1,   0,   0,  -1,  -2,  -3,  -3,  -1,  -1,   0,   0,   0,  -1,  -1,  -1,
+    -2,  -2,  -1,   0,   1,   1,   1,   1,  -2,  -2,  -2,   0,   1,   2,   3,   3,
+    -1,  -1,  -1,   0,   1,   3,   3,   3,   1,   0,   0,   0,   1,   1,   2,   2,
+     2,   2,   1,   0,   0,  -1,  -1,  -1,   3,   2,   1,   0,  -1,  -2,  -3,  -3,
+  ], [
+    -1,  -1,  -1,  -2,  -2,  -3,  -4,  -5,   0,   0,   0,  -1,  -1,  -3,  -3,  -4,
+     1,   1,   1,   0,   0,  -1,  -2,  -3,   2,   2,   2,   1,   1,   0,  -1,  -1,
+     2,   2,   2,   2,   1,   1,   0,  -1,   2,   2,   2,   2,   2,   1,   0,   0,
+     1,   1,   2,   1,   1,   1,   0,   0,   0,   0,   1,   1,   0,   0,   0,  -1,
+  ], [
+    -2,   2,   3,   1,  -1,   1,   1,  -1,  -3,   2,   3,   0,  -1,   1,   1,  -1,
+    -3,   2,   3,   0,  -1,   1,   1,  -1,  -4,   2,   3,   0,  -1,   1,   1,  -2,
+    -4,   1,   3,   0,  -1,   1,   1,  -2,  -4,   1,   3,  -1,  -2,   1,   1,  -2,
+    -3,   1,   2,   0,  -1,   1,   1,  -2,  -3,   1,   2,   0,  -1,   1,   1,  -1,
+  ], [
+    -1,  -1,  -1,  -2,  -2,  -2,  -2,  -2,   1,   1,   1,   1,   0,   0,   0,   0,
+     1,   2,   2,   2,   2,   2,   2,   2,   0,   0,   1,   1,   1,   2,   2,   2,
+    -2,  -2,  -1,  -1,  -1,   0,   0,   0,  -3,  -3,  -3,  -3,  -3,  -3,  -3,  -2,
+    -1,  -1,  -1,  -1,  -2,  -2,  -2,  -2,   4,   4,   4,   4,   4,   3,   3,   2,
+  ], [
+    -3,  -3,  -2,  -1,   0,   1,   2,   5,  -3,  -3,  -3,  -2,  -1,   1,   3,   6,
+    -3,  -3,  -2,  -2,   0,   2,   3,   5,  -3,  -2,  -2,  -2,   0,   1,   3,   5,
+    -2,  -2,  -2,  -1,  -1,   1,   3,   5,  -2,  -2,  -1,  -1,   0,   1,   2,   4,
+    -1,  -1,  -1,  -1,   0,   1,   1,   4,  -1,  -1,  -1,  -1,   0,   1,   2,   3,
+  ], [
+     0,  -1,   0,   1,   1,   0,  -1,  -1,   0,   0,   0,   1,   2,   0,  -1,  -1,
+     1,   0,  -1,   0,   1,   0,   0,   0,   1,  -1,  -2,  -1,   0,   0,   0,   0,
+     1,  -2,  -3,  -1,   0,   0,   0,   1,   1,  -1,  -3,  -2,   0,   1,   1,   2,
+     1,  -1,  -2,  -1,   0,   1,   1,   2,   2,   0,  -1,   0,   1,   1,   2,   2,
+  ], [
+     1,   1,   1,   1,   0,   0,   1,   2,  -1,   0,   0,  -1,   0,   0,   0,   1,
+    -3,  -2,  -1,  -1,  -1,   0,   1,   1,  -4,  -2,  -1,   0,   0,   1,   1,   1,
+    -3,  -2,   0,   0,   1,   1,   1,   1,  -3,  -1,   0,   1,   1,   1,   0,   0,
+    -1,   0,   1,   1,   1,   0,   0,  -1,   0,   1,   2,   2,   1,   0,   0,  -1,
+  ], [
+    -4,  -4,  -4,  -3,  -2,  -1,  -1,  -1,  -2,  -2,  -2,  -1,   0,   0,   0,   0,
+    -1,   0,   0,   0,   1,   1,   1,   1,   0,   0,   1,   1,   1,   1,   1,   1,
+     0,   0,   1,   1,   2,   2,   1,   0,   0,   0,   1,   1,   1,   1,   1,   0,
+     0,   0,   0,   1,   1,   1,   1,   0,  -1,   0,   0,   1,   1,   1,   0,   0,
+  ], [
+     1,   2,   2,   2,   1,  -1,  -2,  -4,   1,   1,   2,   2,   1,   0,  -2,  -4,
+     0,   1,   1,   1,   1,   0,  -1,  -3,  -1,   0,   1,   1,   0,   0,  -1,  -2,
+    -1,   0,   1,   1,   1,   0,   0,  -1,  -2,  -1,   0,   0,   0,   0,   0,  -1,
+    -1,  -1,   0,   1,   1,   0,   0,   0,  -1,   0,   1,   1,   1,   1,   1,   0,
+  ], [
+     2,   2,   0,  -1,  -2,  -1,  -1,  -2,   1,   1,  -1,  -2,  -2,  -1,  -1,  -2,
+     1,   1,  -1,  -2,  -2,   0,   0,  -1,   1,   1,   0,  -2,  -1,   1,   1,   0,
+     1,   1,   0,  -1,  -1,   1,   2,   1,   1,   1,   0,  -1,  -1,   1,   2,   1,
+     1,   1,   0,  -1,  -1,   1,   1,   1,   1,   1,   0,  -1,   0,   1,   1,   1,
+  ], [
+     0,   0,  -1,  -2,  -4,  -4,  -4,  -4,   3,   3,   3,   2,   1,   0,   0,   0,
+     3,   3,   3,   3,   2,   2,   2,   2,   0,   0,   0,   0,   0,   0,   0,   1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,  -1,   0,   0,  -1,   0,   0,   0,
+     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  -1,  -1,   0,
+  ], [
+    -1,  -1,   0,  -1,  -1,   1,   2,  -1,   1,   1,   0,   0,   0,   2,   3,  -1,
+     1,   1,   0,  -1,  -1,   1,   3,  -1,   1,   1,   0,  -2,  -2,   0,   1,  -2,
+     1,   0,   0,  -2,  -2,   0,   1,  -3,   0,   0,   0,   0,  -1,   1,   1,  -3,
+     0,   1,   1,   0,   1,   2,   1,  -3,  -1,   0,   1,   1,   1,   2,   1,  -4,
+  ], [
+    -4,  -3,   0,   1,   1,   1,   0,   0,  -4,  -2,   0,   1,   1,   1,   0,  -1,
+    -3,  -1,   1,   1,   1,   0,  -1,  -1,  -1,   1,   1,   1,   1,   0,  -1,   0,
+     1,   2,   2,   1,   0,  -1,   0,   0,   2,   2,   1,   0,  -1,  -1,   0,   1,
+     2,   1,   0,  -1,  -2,  -1,   0,   1,   2,   2,   0,  -1,  -2,  -1,   1,   1,
+  ], [
+     1,   1,   0,   0,  -1,  -1,  -1,  -1,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,  -1,  -1,  -1,  -1,  -1,  -1,
+     1,   0,   0,  -1,  -1,  -1,  -1,  -1,   2,   1,   0,   0,  -1,  -1,  -1,  -1,
+     5,   3,   2,   1,   0,   0,   0,   0,   6,   5,   3,   2,   1,   0,   0,   0,
+  ], [
+     4,   4,   3,   1,   0,   0,   0,   1,   3,   3,   2,   1,   0,   0,   0,   1,
+     2,   2,   1,   0,  -1,  -1,   0,   1,   0,   0,   0,  -1,  -1,  -1,   0,   1,
+     0,   0,  -1,  -1,  -2,  -1,   0,   2,   0,  -1,  -1,  -2,  -2,  -2,   0,   1,
+     0,  -1,  -1,  -2,  -2,  -2,  -1,   0,   0,   0,  -1,  -2,  -2,  -2,  -1,   0,
+  ], [
+     0,   0,  -1,  -1,  -1,   0,   2,   3,   0,  -1,  -2,  -2,  -1,  -1,   1,   2,
+     1,   0,  -1,  -1,  -1,   0,   0,   0,   1,   1,   1,   0,   0,   0,  -1,  -1,
+     1,   2,   1,   0,   0,  -1,  -1,  -1,  -1,   0,   0,   0,  -1,  -1,  -1,  -1,
+    -3,  -2,  -1,  -1,   0,   1,   1,   2,  -4,  -3,  -1,   1,   2,   3,   5,   5,
+  ], [
+     0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,
+     0,   0,   0,  -1,   0,   0,   0,   1,  -1,  -1,  -2,  -2,  -2,  -1,  -1,   0,
+     0,   0,   0,   0,   0,   1,   1,   1,   2,   2,   2,   2,   2,   3,   3,   3,
+     1,   1,   1,   1,   2,   2,   1,   1,  -4,  -3,  -4,  -4,  -4,  -4,  -3,  -3,
+  ], [
+    -1,   0,   1,   2,   2,   3,   3,   3,  -1,  -1,  -1,  -1,   0,   0,   0,   0,
+     0,   0,  -1,  -2,  -2,  -3,  -3,  -2,   3,   2,   1,   0,  -1,  -2,  -2,  -2,
+     4,   3,   2,   1,   1,   0,   0,   0,   2,   2,   1,   1,   0,   1,   1,   1,
+     0,  -1,  -1,  -1,  -1,   0,   0,   1,  -2,  -2,  -2,  -2,  -2,  -1,   0,   0,
+  ], [
+     1,  -1,   0,   2,   1,  -2,  -1,   1,   1,  -1,   0,   2,   1,  -2,  -2,   1,
+     1,  -1,   0,   3,   2,  -2,  -1,   1,   0,  -2,   0,   3,   2,  -2,  -2,   1,
+     0,  -2,   0,   3,   2,  -2,  -2,   1,   0,  -2,   0,   3,   1,  -2,  -1,   1,
+     0,  -2,   0,   2,   1,  -2,  -2,   1,   0,  -1,   0,   2,   1,  -2,  -1,   1,
+  ], [
+     0,   1,   2,   2,   3,   3,   2,   2,   0,   1,   1,   2,   3,   3,   2,   1,
+     0,   0,   1,   2,   2,   2,   2,   1,  -1,   0,   0,   1,   1,   1,   1,   1,
+    -1,  -1,   0,   0,   0,   0,   0,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
+    -2,  -2,  -2,  -2,  -2,  -2,  -2,  -1,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -1,
+  ], [
+     0,   0,  -1,  -2,  -1,   0,   3,   5,   0,   0,  -1,  -1,  -1,   0,   2,   4,
+     1,   1,   0,   0,  -1,  -1,   1,   2,   1,   2,   1,   1,   0,  -1,  -1,   0,
+     0,   1,   2,   1,   0,  -1,  -2,  -2,  -1,   0,   1,   2,   1,   0,  -3,  -3,
+    -2,  -1,   1,   2,   2,   0,  -2,  -4,  -2,  -1,   0,   2,   2,   1,  -1,  -3,
+  ], [
+     0,   0,   0,   0,   0,   0,  -1,  -1,   0,   0,  -1,   0,   0,   0,   0,   0,
+    -1,  -1,  -1,  -1,   0,   0,   0,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,   0,  -1,   0,   0,   0,   0,  -1,  -1,   0,
+     0,   0,   1,   1,   0,   0,   0,   1,   3,   3,   3,   4,   3,   3,   3,   3,
+  ], [
+     5,   1,  -2,  -2,   0,   0,   0,  -1,   4,  -1,  -3,  -1,   0,   0,   0,  -1,
+     3,  -1,  -1,   0,   1,   1,   0,  -1,   2,   0,   0,   1,   1,   1,   0,  -2,
+     1,   0,   0,   1,   1,   1,   0,  -2,   0,  -1,  -1,  -1,   0,   0,   0,  -1,
+     0,  -1,  -1,  -1,  -1,   0,   0,  -1,   2,   1,   0,   0,   0,   1,   0,   0,
+  ], [
+     1,   0,   1,   1,   1,   1,   0,   0,   1,   0,   0,   1,   1,   0,   0,   0,
+     1,  -1,  -1,   0,   0,   0,   0,   0,   2,   0,  -1,  -1,  -1,  -1,  -1,   0,
+     3,   1,  -1,  -1,  -2,  -2,  -2,  -1,   4,   2,   1,   0,  -1,  -2,  -2,  -1,
+     2,   1,   0,   0,  -1,  -1,   0,   0,   0,  -1,  -1,  -1,  -1,   0,   1,   1,
+  ], [
+     0,   1,   2,   2,   2,   1,  -1,  -3,   0,   0,   1,   1,   1,   0,  -1,  -2,
+     0,   0,   0,   0,   0,   0,  -1,  -1,   0,   0,  -1,   0,   0,   1,   1,   0,
+     0,   0,  -1,   0,   1,   1,   1,   1,   0,   0,   0,   0,   1,   1,   1,   0,
+     0,   0,   1,   1,   2,   1,  -1,  -3,   0,   0,   0,   1,   1,  -1,  -4,  -5,
+  ], [
+    -2,  -2,  -2,  -1,   0,   2,   2,   2,   0,   0,   0,   0,   1,   1,   1,   0,
+     1,   1,   1,   1,   1,   0,  -2,  -3,   0,   0,   1,   1,   0,  -1,  -3,  -4,
+    -1,  -1,   0,   1,   0,   0,  -2,  -3,  -1,  -1,   0,   1,   1,   1,   0,  -1,
+     0,   0,   0,   1,   1,   1,   1,   0,   1,   1,   1,   1,   0,   0,   0,   0,
+  ], [
+     0,   1,   0,   0,   1,   1,   1,   2,   1,   2,   0,   0,   0,   0,  -1,   1,
+     0,   2,   0,  -1,   1,   0,  -1,   0,   0,   1,   0,   0,   2,   1,   0,   1,
+     0,   1,  -1,   0,   2,   2,   0,   1,  -1,   0,  -1,  -1,   2,   1,   1,   2,
+    -2,  -2,  -3,  -2,   0,   1,   1,   1,  -2,  -2,  -3,  -3,  -1,  -1,  -1,   0,
+  ], [
+    -3,  -1,   0,   1,   2,   1,   1,   0,  -3,  -1,   0,   1,   2,   1,   1,   1,
+    -2,   0,   0,   1,   1,   1,   1,   1,  -1,   0,   0,   0,   0,   0,   0,   0,
+    -2,   0,   0,   0,   0,  -1,  -1,   0,  -2,   0,   0,   0,   0,   0,  -1,  -1,
+    -3,   0,   1,   1,   1,   1,   0,   1,  -5,  -2,   0,   1,   2,   2,   1,   2,
+  ], [
+    -2,  -1,  -1,   0,   0,   1,   2,   3,   0,   0,   1,   1,   0,   0,   1,   2,
+     0,   0,   1,   0,  -1,  -1,   0,   1,  -1,  -1,  -1,  -1,  -2,  -2,  -1,   0,
+    -2,  -2,  -2,  -2,  -2,  -1,   0,   1,   0,   0,   0,  -1,   0,   1,   2,   2,
+     2,   1,   0,   0,   0,   1,   2,   2,   2,   1,   0,  -1,  -1,  -1,   0,   0,
+  ], [
+     0,   1,   1,   1,   1,   1,  -1,  -4,  -1,  -1,   0,   1,   1,   1,   0,  -3,
+    -2,  -1,   0,   0,   1,   2,   2,  -2,  -1,   0,   0,   0,   0,   2,   3,  -1,
+    -1,   0,   0,   0,   0,   1,   2,   0,   0,   0,  -1,  -2,  -1,   1,   1,   0,
+     0,   0,  -1,  -2,  -2,   0,   2,   1,   0,   0,  -1,  -2,  -1,   1,   2,   2,
+  ], [
+     1,   0,   0,   0,  -2,  -3,  -2,  -3,   0,   0,   1,   0,  -2,  -2,  -1,  -1,
+     0,  -1,   1,   1,  -1,  -1,   0,   0,   0,  -1,   1,   1,  -1,  -1,   0,   0,
+     0,   1,   2,   1,  -1,  -1,   0,   1,   1,   2,   3,   2,   0,   0,   1,   2,
+    -1,   0,   2,   1,   0,   0,   2,   3,  -2,  -1,   0,   0,  -1,   0,   1,   2,
+  ], [
+     1,   1,   0,  -1,  -2,  -2,  -1,   1,   1,   1,   1,  -1,  -2,  -2,   0,   2,
+     1,   1,   1,  -1,  -1,  -1,   0,   2,   0,   0,   0,   0,   0,   0,   1,   2,
+    -1,  -1,  -1,   0,   0,   0,   1,   2,  -1,  -2,  -1,   1,   1,   1,   0,   0,
+    -1,  -2,  -1,   1,   2,   2,   0,  -1,  -1,  -2,  -1,   2,   2,   2,   0,  -1,
+  ], [
+    -1,  -1,  -1,  -2,  -1,  -1,   0,   1,   0,   0,  -1,  -1,  -1,   0,   1,   2,
+     1,   0,   0,   0,   0,   1,   1,   2,   1,   1,   0,   0,   1,   1,   1,   1,
+     1,   1,   0,   1,   1,   0,   1,   1,   1,   1,   1,   1,   0,  -1,  -1,  -1,
+     1,   2,   1,   0,  -1,  -2,  -2,  -3,   2,   2,   1,   0,  -2,  -3,  -4,  -4,
+  ], [
+    -4,  -2,   1,   1,   1,   1,   0,   0,  -2,   0,   1,   0,   0,   0,   0,   0,
+     0,   1,   1,  -2,  -2,  -1,   0,   1,   2,   2,   1,  -2,  -2,  -1,   1,   2,
+     1,   2,   1,  -2,  -2,  -1,   1,   2,  -1,   1,   1,  -1,  -1,  -1,   0,   1,
+    -2,   0,   1,   1,   0,  -1,  -1,   0,  -2,   0,   2,   2,   1,  -1,  -1,   0,
+  ], [
+     1,   1,   0,   0,   0,   1,   0,   0,  -2,  -3,  -3,  -2,  -2,  -1,   0,   0,
+    -3,  -4,  -3,  -2,  -1,   0,   0,   0,  -1,  -1,   0,   1,   2,   3,   2,   1,
+     0,   1,   2,   3,   3,   3,   2,   1,   1,   1,   1,   2,   1,   0,   0,  -1,
+     0,   0,   0,   0,  -1,  -1,  -1,  -1,   0,  -1,  -1,   0,   0,   0,   0,   0,
+  ], [
+     1,   1,   0,   0,  -1,  -1,   0,   2,   0,   0,   1,   0,  -1,  -1,   1,   1,
+    -2,  -1,   0,   1,   1,   1,   1,   1,  -3,  -3,   0,   2,   2,   1,   1,   0,
+    -2,  -2,   0,   1,   1,   1,   0,   0,   1,   0,   0,   0,   0,   0,  -1,  -1,
+     3,   1,  -1,  -3,  -2,  -1,   0,   1,   4,   2,  -1,  -3,  -3,  -1,   1,   2,
+  ], [
+     0,   0,   0,  -1,  -1,  -1,  -1,  -1,   1,   2,   1,   0,   0,   0,  -1,  -1,
+     2,   3,   3,   2,   1,   0,  -1,  -1,   3,   4,   4,   2,   1,   0,  -1,  -2,
+     3,   3,   2,   1,   0,  -1,  -2,  -2,   1,   1,   0,  -1,  -1,  -2,  -2,  -3,
+     0,   0,   0,  -1,  -1,  -2,  -2,  -2,  -1,  -1,  -1,  -1,  -1,  -2,  -2,  -1,
+  ], [
+     1,   2,   2,   2,   2,   1,   2,   2,   0,   1,   1,   1,   1,   0,   0,   0,
+     0,   0,   0,   1,   1,   0,  -1,  -2,   0,   0,   0,   0,   1,   0,  -1,  -4,
+     1,   0,   0,   0,   0,   0,  -2,  -5,   1,   0,   0,   0,   0,   0,  -1,  -4,
+     1,   0,  -1,   0,   0,   0,  -1,  -3,   0,  -1,  -1,   0,   1,   1,   1,  -1,
+  ], [
+    -2,  -1,   0,   0,  -1,  -1,  -1,  -2,  -1,   0,   0,   0,  -1,  -1,  -2,  -2,
+     0,   1,   1,   0,  -1,  -1,  -1,  -2,   0,   1,   1,   0,   0,   0,  -1,  -1,
+     0,   1,   0,   0,   1,   1,   1,   0,   1,   1,   0,   0,   1,   2,   2,   1,
+     1,   1,   0,   0,   1,   2,   2,   1,   1,   1,   0,  -1,   0,   1,   1,   0,
+  ], [
+     4,   2,   1,   0,   0,   1,   1,   1,   4,   2,   1,   0,   0,   0,   0,   1,
+     3,   1,   0,   0,  -1,  -1,  -1,   0,   1,   0,   0,  -1,  -1,  -2,  -1,   0,
+     0,   0,   0,   0,  -1,  -1,  -1,   0,  -1,  -1,   0,   0,  -1,  -1,   0,   1,
+    -2,  -1,   0,  -1,  -1,   0,   0,   1,  -2,  -2,  -1,  -2,  -1,   0,   0,   1,
+  ], [
+     0,   1,   1,   1,   2,   1,   0,  -1,  -1,  -1,  -1,   0,   0,  -1,  -2,  -2,
+    -1,   0,  -1,   0,   0,  -1,  -2,  -1,   0,   0,   0,   0,   0,   0,   1,   2,
+     0,   0,   0,   0,   0,   0,   2,   3,  -1,   0,  -1,  -1,  -1,  -1,   0,   3,
+    -1,   0,   0,  -1,  -1,  -2,   0,   3,   0,   0,   0,   0,  -1,  -1,   1,   4,
+  ], [
+     2,   2,   0,   0,   0,   0,   0,   1,   1,   1,  -1,  -2,  -1,  -2,  -1,   1,
+    -1,  -1,  -2,  -2,  -2,  -3,  -2,   0,  -1,   0,  -1,  -1,  -1,  -2,  -1,   1,
+     1,   1,   0,   0,   1,   0,   0,   1,   2,   2,   0,   0,   1,   0,   0,   1,
+     2,   2,   0,   0,   0,   0,  -1,  -1,   2,   2,   0,   0,   1,   0,  -1,  -1,
+  ], [
+    -1,   0,   1,   1,   0,  -1,  -1,  -1,   1,   2,   3,   2,   1,   0,   0,   0,
+     0,   1,   1,   1,   0,  -1,   0,   0,  -2,  -2,  -1,   0,   1,   0,   0,   0,
+    -2,  -2,  -1,   2,   2,   2,   1,   0,  -2,  -1,   0,   1,   1,   0,   0,  -1,
+    -1,  -1,   0,   0,  -1,  -2,  -1,  -2,   0,   1,   1,   1,   0,   0,   1,   1,
+  ], [
+    -3,  -3,  -3,  -2,  -1,  -1,  -2,  -2,  -1,  -1,   0,   1,   2,   1,   0,   0,
+     1,   1,   1,   2,   2,   1,   0,   0,   1,   1,   1,   1,   1,   0,  -1,   1,
+     1,   0,  -1,  -1,   0,   0,  -1,   1,   0,  -1,  -1,  -1,   0,  -1,  -1,   1,
+     1,   0,  -1,   0,   0,  -1,   0,   2,   2,   0,  -1,   0,   0,   0,   0,   2,
+  ], [
+     1,   0,  -2,  -1,   0,   1,   1,   0,   2,   0,  -1,  -1,   0,   1,   1,   0,
+     1,   0,  -2,  -1,   0,   1,   0,  -1,   1,   0,  -1,  -1,   0,   1,   0,  -1,
+     0,   1,   1,   0,   1,   1,   0,   0,  -2,   1,   2,   1,   0,   0,   0,   1,
+    -5,   0,   2,   1,   0,  -1,   0,   1,  -6,  -1,   2,   1,   0,  -1,   0,   0,
+  ], [
+     5,   3,   0,  -1,  -2,  -1,  -1,  -1,   1,   1,   0,  -1,  -1,   0,  -1,  -1,
+    -1,   0,   1,   1,   2,   2,   1,   0,  -2,  -1,   0,   1,   2,   1,   1,   1,
+    -2,  -1,  -1,  -1,   0,  -1,   0,   1,   0,   1,   0,   0,  -1,  -1,   0,   0,
+     0,   1,   1,   1,   1,   0,   0,   0,  -3,  -2,   0,   1,   1,   0,   0,  -1,
+  ], [
+    -1,   0,   1,   0,  -1,   0,   2,   3,  -1,   0,   0,  -2,  -4,  -2,  -1,   0,
+     0,   1,   1,   0,  -2,  -1,   0,  -1,   1,   2,   3,   1,   0,   1,   1,   0,
+    -1,   0,   1,   1,   1,   1,   1,   0,  -2,  -3,  -2,   0,   0,   0,   1,   0,
+    -1,  -2,  -2,   0,   1,   0,   0,  -1,   3,   1,   0,   0,   1,   0,  -1,  -1,
+  ], [
+    -2,  -1,   0,   0,  -1,  -1,   0,   0,  -1,   0,   0,   0,   0,   1,   1,   1,
+    -1,  -1,  -1,   0,   1,   1,   1,   1,   0,  -2,  -3,  -1,   1,   0,   0,   0,
+     1,  -1,  -3,  -1,   1,   1,   0,  -1,   3,   1,  -1,   1,   2,   2,   0,  -1,
+     3,   1,   0,   1,   2,   1,   1,   0,   0,  -2,  -2,  -1,  -1,   0,   0,   0,
+  ], [
+     1,   0,  -1,  -1,   1,   2,   1,   0,   0,  -1,  -2,  -1,   1,   2,   2,   1,
+    -1,  -1,  -1,   0,   0,   1,   2,   0,  -2,   0,   0,   0,   0,   0,   1,  -1,
+    -1,   0,   1,   0,  -1,  -1,  -1,  -1,   0,   1,   1,   2,   0,  -2,  -1,   0,
+     1,   2,   2,   2,   1,  -1,  -1,   0,   0,   1,   1,   1,   0,  -2,  -2,  -1,
+  ], [
+     0,   0,  -1,  -1,  -1,  -1,  -2,  -2,   0,   0,  -1,   0,   1,   2,   2,   1,
+     0,   0,  -1,  -1,   0,   1,   2,   2,   1,   1,  -1,  -2,  -1,  -1,  -1,  -1,
+     2,   2,   1,   0,   0,  -1,  -2,  -2,   1,   2,   2,   1,   0,   0,  -2,  -2,
+     0,   0,   0,   0,   1,   1,   0,  -1,   0,  -1,  -1,  -1,   2,   3,   2,   1,
+  ], [
+     0,  -2,   1,   2,  -1,   0,   0,   1,  -1,  -2,   2,   3,  -1,   0,   0,   0,
+     0,  -2,   2,   3,  -1,  -1,   0,   0,   0,  -1,   3,   2,  -2,   0,   1,   0,
+     0,  -1,   3,   1,  -2,   0,   1,   0,   0,  -1,   2,   1,  -1,   1,   0,  -1,
+     0,   0,   1,  -1,  -2,   0,   0,  -1,   1,   0,   0,  -2,  -2,  -1,  -1,  -1,
+  ], [
+     1,   1,   1,   1,   1,  -1,  -1,  -2,   0,   0,   0,   1,   1,   1,   1,   1,
+     0,   0,   0,   1,   1,   1,   2,   3,   1,   0,   0,  -1,   0,   0,   1,   2,
+     0,  -1,  -1,  -2,  -1,   0,   1,   2,  -2,  -2,  -2,  -2,  -1,   0,   1,   1,
+    -1,  -1,  -1,  -1,   0,   0,   0,  -1,   2,   2,   2,   0,  -1,  -1,  -2,  -4,
+  ], [
+    -1,  -2,  -1,  -1,   0,   1,   2,   3,  -1,  -1,  -1,  -1,   0,   1,   2,   3,
+     1,   0,  -1,   0,  -1,   0,   1,   2,   1,   0,   0,   0,  -1,   0,   2,   2,
+     1,   0,  -1,  -1,  -2,   0,   1,   2,   0,  -2,  -2,  -2,  -3,  -1,   0,   1,
+     0,  -2,  -2,  -2,  -2,  -1,   1,   1,   0,   0,   0,   0,   0,   1,   2,   2,
+  ]
+];
+
+pub const SVQ_INTRA_CB_8X4: [[i8; 32]; 96] = [
+  [
+     5,   6,   6,   6,   7,   7,   8,   8,   0,   0,   0,   0,   0,   1,   2,   3,
+    -3,  -4,  -4,  -5,  -5,  -4,  -3,  -2,  -4,  -4,  -4,  -5,  -4,  -4,  -3,  -3,
+  ], [
+     1,   2,   2,   2,   2,   3,   3,   3,   2,   3,   3,   4,   4,   5,   5,   5,
+    -1,   0,   1,   1,   2,   3,   4,   4,  -9, -10,  -9,  -9,  -8,  -7,  -6,  -5,
+  ], [
+    -4,  -4,  -5,  -6,  -6,  -7,  -7,  -7,   0,  -1,  -2,  -2,  -3,  -3,  -4,  -4,
+     4,   4,   3,   3,   2,   1,   1,   0,   7,   7,   7,   6,   6,   5,   4,   4,
+  ], [
+     2,   4,   5,   6,   4,   1,  -3,  -6,   3,   4,   5,   5,   4,   0,  -5,  -8,
+     2,   3,   4,   4,   2,  -2,  -7, -10,   2,   2,   2,   1,   0,  -4,  -9, -12,
+  ], [
+    -9,  -7,  -3,   1,   4,   4,   3,   3, -10,  -7,  -2,   3,   5,   5,   3,   3,
+    -9,  -6,  -2,   3,   6,   5,   4,   3,  -8,  -6,  -1,   3,   4,   4,   3,   2,
+  ], [
+    -5,  -5,  -5,  -5,  -3,   1,   4,   7,  -5,  -5,  -5,  -4,  -2,   1,   6,   8,
+    -4,  -5,  -4,  -3,  -1,   3,   8,  10,  -3,  -4,  -3,  -2,   1,   5,   9,  11,
+  ], [
+    -2,  -2,  -2,  -2,  -2,  -2,  -2,  -2,  -4,  -5,  -5,  -5,  -5,  -5,  -5,  -4,
+    -3,  -4,  -4,  -4,  -4,  -4,  -4,  -3,   9,  10,  10,  11,  11,  11,  10,  10,
+  ], [
+     7,   4,   1,  -2,  -4,  -6,  -9, -10,   9,   7,   3,   0,  -2,  -4,  -8,  -9,
+    11,   8,   4,   2,   0,  -3,  -6,  -8,  11,   9,   5,   3,   1,  -2,  -5,  -7,
+  ], [
+   -13, -13, -13, -12, -11, -10,  -8,  -8,   0,   1,   2,   3,   4,   4,   4,   3,
+     3,   4,   5,   6,   6,   6,   5,   4,   3,   4,   4,   4,   3,   3,   3,   2,
+  ], [
+    10,  10,  11,  10,   9,   9,   8,   7,   6,   6,   6,   6,   5,   4,   3,   2,
+     0,   0,   0,  -1,  -2,  -3,  -4,  -4, -10, -10, -11, -12, -13, -14, -14, -14,
+  ], [
+    16,  16,  17,  16,  15,  13,  12,  11,  -1,  -2,  -3,  -4,  -4,  -4,  -4,  -3,
+    -4,  -5,  -6,  -6,  -6,  -6,  -6,  -6,  -5,  -6,  -6,  -6,  -6,  -6,  -5,  -5,
+  ], [
+   -13, -13, -13, -12, -11, -10,  -8,  -6,  -9,  -8,  -7,  -6,  -4,  -2,   0,   1,
+    -2,  -1,   1,   3,   5,   7,   8,   9,   5,   7,   9,  11,  13,  14,  15,  15,
+  ], [
+    16,  14,  11,   7,   2,  -3,  -7,  -9,  14,  12,   8,   3,  -1,  -6,  -9, -11,
+    11,   9,   4,   0,  -4,  -8, -11, -13,   8,   5,   1,  -3,  -6, -10, -12, -14,
+  ], [
+   -18, -15,  -9,  -3,   1,   6,   9,  11, -17, -13,  -7,  -1,   3,   7,  11,  12,
+   -15, -11,  -5,   1,   5,   9,  12,  13, -13,  -9,  -3,   2,   5,   9,  11,  13,
+  ], [
+    22,  21,  19,  15,  10,   3,  -4,  -9,  20,  18,  15,   9,   2,  -5, -12, -17,
+    16,  13,   8,   1,  -7, -14, -20, -24,  10,   6,  -1,  -8, -15, -21, -25, -27,
+  ], [
+   -25, -23, -20, -14,  -7,   1,   9,  14, -23, -21, -16,  -9,   0,   9,  16,  21,
+   -20, -16, -10,  -1,   8,  16,  22,  25, -15, -11,  -3,   6,  14,  20,  25,  27,
+  ], [
+    -4,  -2,   0,   1,   2,   2,   2,   2,  -5,  -2,   0,   2,   3,   3,   3,   3,
+    -6,  -4,  -1,   1,   2,   3,   3,   3,  -7,  -5,  -2,   0,   1,   1,   2,   2,
+  ], [
+     2,   1,   1,   1,   1,   0,  -2,  -3,   3,   3,   2,   1,   0,  -1,  -3,  -4,
+     4,   3,   2,   1,   0,  -2,  -4,  -6,   5,   4,   3,   1,  -1,  -3,  -5,  -6,
+  ], [
+     5,   6,   6,   4,   2,   0,  -2,  -3,   3,   4,   4,   4,   3,   1,   0,  -1,
+    -2,  -2,  -1,  -1,  -1,  -1,  -2,  -2,  -5,  -4,  -3,  -2,  -2,  -2,  -3,  -3,
+  ], [
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -3,  -4,  -4,  -4,  -3,  -3,  -3,  -3,
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -2,   5,   6,   6,   6,   6,   5,   4,   3,
+  ], [
+     4,   4,   4,   4,   4,   5,   6,   7,   0,  -1,  -1,  -1,  -1,   0,   1,   2,
+    -2,  -3,  -3,  -3,  -3,  -2,  -1,   0,  -3,  -3,  -4,  -4,  -4,  -3,  -2,  -1,
+  ], [
+     0,  -2,  -4,  -4,  -2,   0,   2,   3,   0,  -2,  -3,  -3,  -1,   2,   4,   5,
+    -1,  -2,  -4,  -3,   0,   3,   5,   6,  -2,  -3,  -4,  -3,  -1,   2,   4,   5,
+  ], [
+     9,   4,   0,  -3,  -3,  -1,   0,   1,   8,   4,  -1,  -4,  -3,  -1,   1,   2,
+     6,   2,  -3,  -5,  -4,  -2,   0,   1,   5,   1,  -3,  -4,  -4,  -2,   0,   1,
+  ], [
+     5,   3,   1,  -1,  -4,  -8, -10, -10,   3,   3,   2,   1,   0,  -2,  -3,  -4,
+     1,   1,   1,   2,   3,   2,   1,   0,  -1,   0,   1,   2,   3,   4,   3,   2,
+  ], [
+     0,   1,   2,   2,   1,  -1,  -3,  -3,   0,   1,   1,   1,  -1,  -2,  -4,  -3,
+    -3,  -3,  -3,  -3,  -3,  -3,  -1,   2,  -4,  -4,  -3,   0,   3,   7,  12,  14,
+  ], [
+    -5,  -5,  -6,  -6,  -6,  -6,  -6,  -5,   2,   2,   2,   1,   0,   0,   0,   0,
+     4,   4,   3,   2,   1,   0,   0,   0,   6,   6,   5,   4,   2,   2,   1,   1,
+  ], [
+    -7,  -7,  -6,  -3,   0,   4,   7,   8,  -1,  -2,  -3,  -3,  -2,  -1,   1,   2,
+     3,   3,   1,  -1,  -2,  -2,  -2,  -1,   6,   6,   4,   2,   0,  -2,  -2,  -2,
+  ], [
+    -6,  -5,  -2,   2,   5,   9,  11,  12,  -4,  -4,  -2,   0,   2,   4,   5,   6,
+    -3,  -2,  -2,  -2,  -2,  -1,   0,   1,  -2,  -2,  -2,  -3,  -3,  -3,  -3,  -2,
+  ], [
+    -7,  -3,   1,   3,   3,   0,  -3,  -5,  -6,  -2,   3,   5,   4,   1,  -3,  -5,
+    -5,  -1,   4,   6,   5,   2,  -3,  -4,  -4,   0,   5,   7,   6,   3,  -1,  -3,
+  ], [
+     0,   0,   0,   0,   0,   0,   0,   0,  -2,  -2,  -3,  -3,  -3,  -3,  -2,  -1,
+     6,   7,   8,   9,   9,   8,   7,   6,  -4,  -4,  -5,  -5,  -6,  -6,  -5,  -4,
+  ], [
+    -9,  -8,  -6,  -4,   0,   3,   6,   6,  -5,  -4,  -1,   3,   5,   6,   5,   3,
+     1,   3,   6,   6,   4,   1,  -2,  -5,   6,   7,   5,   1,  -3,  -7, -10, -11,
+  ], [
+    10,   9,   5,   1,  -3,  -6,  -6,  -4,   5,   3,  -1,  -5,  -6,  -5,  -2,   2,
+    -2,  -4,  -6,  -6,  -4,   1,   6,  10,  -6,  -7,  -7,  -4,   1,   7,  11,  12,
+  ], [
+     6,   5,   3,   2,   0,   0,   0,   0,   2,   1,  -1,  -2,  -3,  -2,  -1,  -1,
+     0,  -1,  -2,  -4,  -4,  -2,  -1,   1,   0,   0,  -1,  -2,  -1,   0,   2,   3,
+  ], [
+     0,  -1,  -2,  -2,  -2,  -2,  -1,  -1,   5,   4,   2,   1,   0,   0,   0,   0,
+     6,   5,   3,   1,   0,   0,   0,   0,   2,   0,  -2,  -4,  -4,  -3,  -2,  -2,
+  ], [
+    -7,  -4,   0,   2,   2,   2,   2,   1,  -7,  -3,   0,   0,   0,   0,   0,   0,
+    -4,  -1,   1,   1,   0,   0,   0,   1,  -1,   1,   2,   2,   2,   2,   3,   3,
+  ], [
+    -2,   0,   2,   2,   1,   1,   1,   1,  -1,   1,   2,   2,   1,   0,   0,  -1,
+     0,   2,   4,   2,   0,  -1,  -2,  -3,   1,   2,   3,   1,  -2,  -4,  -6,  -6,
+  ], [
+     1,   2,   2,   4,   5,   6,   4,   1,   0,  -1,  -1,  -1,   0,   0,  -2,  -4,
+     0,   0,  -1,  -2,  -2,  -2,  -4,  -6,   2,   1,   0,   0,   1,   1,  -1,  -3,
+  ], [
+     1,   1,   1,   1,   1,   2,   3,   3,   0,   0,   1,   0,   1,   2,   4,   4,
+    -1,  -1,  -1,  -1,   0,   1,   2,   3,  -4,  -4,  -5,  -5,  -5,  -3,  -1,   0,
+  ], [
+    -6,  -5,  -5,  -4,  -3,  -2,  -1,  -1,  -1,   0,   0,   1,   1,   2,   3,   3,
+     0,   1,   1,   1,   2,   2,   3,   4,   0,   0,  -1,  -1,   0,   1,   2,   3,
+  ], [
+     0,   1,   1,   1,   0,   0,  -1,  -1,   1,   3,   3,   2,   1,  -1,  -2,  -2,
+    -2,   0,   2,   2,   2,   2,   1,   1,  -9,  -8,  -4,  -2,   1,   3,   3,   3,
+  ], [
+    -1,  -1,  -1,  -2,  -3,  -3,  -3,  -4,   0,   0,   0,  -1,  -2,  -2,  -3,  -3,
+     2,   2,   2,   0,  -1,  -1,  -1,  -1,   5,   5,   4,   3,   2,   2,   2,   2,
+  ], [
+     6,   3,  -1,  -4,  -3,  -1,   1,   1,   2,  -1,  -3,  -4,  -1,   2,   2,   0,
+    -1,  -2,  -2,   1,   4,   4,   1,  -3,  -2,  -1,   1,   4,   6,   3,  -3,  -8,
+  ], [
+     3,   3,   2,   1,  -1,  -2,  -2,  -2,  -4,  -4,  -2,  -1,   1,   3,   4,   4,
+    -4,  -5,  -5,  -4,  -2,   0,   2,   2,   7,   7,   4,   1,  -1,  -2,  -3,  -2,
+  ], [
+    -1,   1,   3,   0,  -4,  -6,   0,   6,  -2,   1,   4,   1,  -4,  -6,  -1,   7,
+    -3,   1,   4,   2,  -3,  -6,  -1,   6,  -2,   0,   3,   2,  -2,  -5,  -1,   4,
+  ], [
+     1,  -1,  -2,   1,   4,   4,  -1,  -7,   1,  -1,  -4,  -1,   5,   6,   0,  -6,
+     3,   0,  -4,  -3,   3,   6,   2,  -4,   3,   0,  -5,  -4,   1,   4,   1,  -3,
+  ], [
+     2,   2,   3,   3,   3,   3,   2,   2,  -4,  -5,  -6,  -7,  -7,  -7,  -7,  -6,
+     1,   2,   3,   3,   3,   3,   2,   2,   0,   0,   1,   1,   1,   2,   2,   1,
+  ], [
+     3,  -3,  -3,   3,   4,  -2,  -2,   2,   3,  -4,  -4,   4,   4,  -4,  -4,   2,
+     4,  -4,  -4,   4,   4,  -4,  -3,   3,   3,  -3,  -4,   3,   3,  -3,  -3,   3,
+  ], [
+    -2,  -2,  -2,  -2,  -2,  -2,  -1,  -1,   6,   7,   8,   8,   8,   7,   6,   5,
+    -5,  -6,  -7,  -7,  -8,  -7,  -6,  -5,   1,   1,   2,   2,   2,   2,   1,   1,
+  ], [
+     0,   0,   0,   0,   0,  -1,   0,   0,  -1,   0,   0,   0,   0,  -1,   0,   0,
+    -2,  -3,  -2,  -2,  -2,  -3,  -3,  -3,   2,   3,   5,   6,   4,   2,   1,   0,
+  ], [
+     8,   6,   2,   0,   0,   0,   0,   0,   4,   1,   0,   0,   0,  -1,  -1,  -1,
+     1,  -1,   0,   0,   0,  -1,  -2,  -3,  -2,  -2,  -1,   0,   0,  -2,  -4,  -5,
+  ], [
+     3,   1,  -1,  -2,  -3,  -4,  -5,  -5,   2,   1,   0,   0,   1,   1,   0,   0,
+     0,  -1,  -1,   0,   2,   2,   2,   2,  -1,  -2,  -1,   1,   2,   2,   2,   2,
+  ], [
+     0,  -1,  -2,  -1,  -1,  -1,  -1,   0,  -1,  -2,  -2,  -1,  -1,   0,   0,   1,
+     2,   1,   1,   2,   2,   1,   1,   0,   6,   5,   3,   1,   0,  -2,  -4,  -4,
+  ], [
+    -3,  -2,  -1,   0,   1,   1,   0,  -1,   0,   1,   3,   4,   5,   5,   3,   1,
+    -1,  -1,  -1,   0,   1,   0,  -1,  -2,  -2,  -2,  -2,  -1,   0,  -1,  -2,  -3,
+  ], [
+     0,  -1,  -2,  -2,  -1,  -1,   0,   2,   1,  -1,  -2,  -1,  -1,  -1,   0,   2,
+     1,   0,  -2,  -2,  -2,  -2,   1,   5,   1,  -1,  -2,  -2,  -2,   0,   5,  10,
+  ], [
+     0,   0,   0,   0,   0,  -1,  -1,  -1,  -1,  -1,  -1,   0,   0,   0,   1,   2,
+     1,   2,   2,   3,   4,   4,   6,   5,  -3,  -3,  -3,  -2,  -2,  -3,  -3,  -3,
+  ], [
+     1,  -1,  -2,  -2,   0,   3,   5,   7,   2,   0,  -2,  -3,  -2,   0,   2,   3,
+     3,   1,  -2,  -3,  -3,  -2,  -1,  -1,   3,   1,   0,  -1,  -1,  -1,  -1,  -1,
+  ], [
+     1,   3,   5,   4,   2,  -1,  -3,  -4,  -3,  -2,   1,   2,   1,   0,  -1,  -2,
+    -5,  -3,   0,   2,   2,   1,   0,   0,  -3,  -1,   1,   2,   2,   1,   0,   0,
+  ], [
+     0,  -1,  -1,  -1,   1,   2,   3,   4,  -3,  -4,  -4,  -3,  -1,   0,   0,   1,
+    -2,  -3,  -2,  -1,   1,   1,   1,   1,  -2,  -2,   0,   3,   4,   4,   3,   2,
+  ], [
+    -4,  -4,  -3,  -2,  -1,   1,   2,   3,   0,   1,   1,   1,  -1,  -2,  -3,  -3,
+     3,   4,   5,   4,   2,  -1,  -3,  -3,  -2,  -2,   0,   2,   2,   2,   1,   0,
+  ], [
+    -4,   0,   5,   7,   4,  -1,  -4,  -4,  -1,   2,   4,   3,   0,  -3,  -3,  -2,
+     2,   1,   0,  -1,  -2,  -2,   0,   1,   0,   0,  -1,  -2,  -2,  -1,   1,   2,
+  ], [
+    -4,  -3,  -2,  -1,   0,   1,   2,   2,  10,   9,   5,   0,  -3,  -4,  -3,  -2,
+     1,  -1,  -2,  -2,  -1,   0,   0,   0,  -2,  -2,  -1,   1,   1,   1,   0,  -1,
+  ], [
+    -5,  -3,   0,   3,   4,   2,   0,  -2,  -2,  -1,   0,   1,   1,   0,  -1,  -1,
+     3,   2,  -1,  -2,  -2,  -1,   1,   1,   7,   5,  -1,  -5,  -6,  -2,   2,   4,
+  ], [
+    -2,   3,   3,  -3,  -4,   1,   2,  -2,  -3,   3,   4,  -3,  -4,   2,   3,  -2,
+    -3,   3,   4,  -3,  -4,   2,   3,  -2,  -4,   2,   4,  -2,  -3,   1,   2,  -1,
+  ], [
+     4,   3,  -1,  -3,  -3,  -1,   1,   2,  -4,  -6,  -4,   0,   4,   5,   4,   1,
+     0,   2,   5,   6,   2,  -3,  -5,  -4,   1,   1,  -1,  -3,  -5,  -2,   2,   4,
+  ], [
+    -1,   0,   1,   2,   2,   3,   3,   4,  -1,   0,   1,   1,   0,  -1,  -1,  -1,
+    -1,   0,   1,   2,   2,   1,  -1,  -2,  -3,  -2,  -1,   0,   0,  -1,  -2,  -3,
+  ], [
+     1,   1,   1,   1,   0,   0,   1,   2,   1,   0,  -1,   0,   0,   1,   1,   0,
+     1,  -2,  -4,  -1,   1,   2,   1,   0,   1,  -4,  -7,  -3,   1,   3,   2,   1,
+  ], [
+     1,   1,   1,   1,   1,   1,   0,  -1,   1,   1,   1,   0,   1,   2,   2,   0,
+     1,   1,   0,   0,   0,   2,   0,  -3,   3,   2,   0,  -1,  -1,  -2,  -6,  -9,
+  ], [
+     0,   0,   0,   1,   0,   0,   1,   2,   1,   0,   0,   0,  -1,  -1,   0,   2,
+     0,   1,   1,   1,  -1,  -3,  -2,   0,  -7,  -5,   1,   6,   6,   2,  -1,  -1,
+  ], [
+     3,   1,  -1,  -3,  -4,  -2,   1,   4,   2,   0,  -2,  -3,  -4,  -3,  -1,   2,
+     2,   2,   1,   1,   1,   0,   0,   1,   1,   1,   0,   0,   0,   0,   0,   1,
+  ], [
+    -1,   1,   1,  -2,  -5,  -6,  -4,  -1,  -1,   1,   4,   3,   2,   0,   1,   2,
+    -1,   0,   2,   3,   1,   0,   0,   1,  -1,   0,   1,   0,   0,  -1,  -1,   0,
+  ], [
+     0,   1,   2,   2,   0,  -2,  -1,   1,  -2,  -1,  -1,  -2,  -1,   2,   6,   8,
+    -1,  -1,  -2,  -3,  -2,   0,   1,   2,  -1,   0,   0,  -1,  -1,   0,  -1,  -1,
+  ], [
+     2,   1,   1,   1,   1,   0,   0,   0,   0,   0,   1,   1,   1,  -1,  -1,   1,
+    -1,   0,   2,   2,  -1,  -3,  -2,   3,   0,   2,   3,   0,  -5,  -7,  -2,   4,
+  ], [
+    -1,   0,   0,   0,  -1,  -2,  -3,  -3,  -1,   0,  -1,  -2,  -2,  -2,  -2,  -2,
+     1,   1,   0,   0,   1,   2,   0,  -1,   1,   2,   1,   2,   5,   6,   2,   0,
+  ], [
+    -2,  -4,  -3,   0,   2,   2,   0,  -3,   3,   1,   0,   1,   2,   1,  -2,  -3,
+     3,   1,   0,   0,   0,   0,   0,  -1,   1,  -1,  -2,  -2,  -1,   1,   3,   3,
+  ], [
+     3,   2,   1,   2,   4,   3,   1,  -2,  -2,  -4,  -4,  -3,  -1,   0,  -2,  -3,
+     1,   0,  -1,  -1,   0,   1,   0,  -1,   3,   2,   0,   0,   0,   1,   1,   0,
+  ], [
+     1,   1,   0,   0,   0,   0,   0,   0,   2,   3,   3,   2,   2,   2,   1,   1,
+     0,  -1,  -2,  -3,  -5,  -5,  -5,  -4,   1,   1,   0,  -1,   0,   1,   3,   3,
+  ], [
+    -9,  -6,  -2,   0,   1,   1,   2,   2,  -6,  -2,   1,   2,   1,   1,   0,   1,
+    -2,   1,   2,   2,   1,   1,   1,   1,   0,   2,   2,   1,   0,   1,   1,   1,
+  ], [
+     1,   0,   0,   0,   0,   0,  -1,   0,   0,   0,   0,   0,  -1,  -3,  -2,   0,
+    -3,  -3,  -3,  -2,  -1,   3,   7,   9,   1,   2,   2,   2,   0,  -2,  -4,  -3,
+  ], [
+     2,   0,  -2,  -1,   3,   4,  -1,  -6,   1,   0,  -2,  -3,  -1,   3,   3,   0,
+     0,   3,   3,   0,  -2,  -1,   1,   1,  -6,  -1,   3,   2,  -1,  -2,   0,   1,
+  ], [
+     5,   3,   0,  -2,  -3,   0,   2,   1,   1,   1,   2,   2,   0,  -2,  -4,  -7,
+    -3,  -2,   1,   2,   2,   1,  -1,  -4,   2,   2,   0,  -2,  -2,   0,   2,   2,
+  ], [
+     0,   0,  -2,  -3,  -2,  -1,   0,   0,   0,   0,   0,   0,   0,   0,   2,   2,
+    -2,  -1,   0,   1,   0,   1,   2,   3,  -4,  -2,   0,   0,  -1,   0,   2,   3,
+  ], [
+    -2,  -2,  -2,  -1,  -1,   0,   2,   4,   0,   0,   0,   0,  -1,  -1,   0,   1,
+     0,  -1,  -1,  -1,  -1,  -1,   0,   0,   6,   4,   2,   0,  -1,  -2,  -1,  -1,
+  ], [
+     0,   1,   1,   1,   1,  -1,  -5, -10,   1,   1,   1,   1,   1,   1,   0,  -4,
+     1,   0,   1,   1,   1,   1,   1,  -1,   2,   1,   1,   1,   0,   0,   0,   0,
+  ], [
+    -3,   1,   4,   3,   3,   1,  -1,   0,  -4,   0,   1,   0,  -1,   0,   0,   0,
+    -5,   0,   2,   1,   1,   1,   0,  -1,  -1,   2,   1,  -2,  -2,  -1,   0,  -1,
+  ], [
+     2,   4,   5,   3,   0,  -1,   1,   2,   0,   0,   1,   0,  -2,  -2,  -1,  -1,
+    -2,  -2,  -2,  -2,  -3,  -2,  -1,   0,   0,   0,   1,   0,   0,   0,   1,   2,
+  ], [
+     0,  -2,  -2,  -3,  -1,   2,   2,  -1,   1,   0,   0,   0,   1,   5,   3,  -2,
+    -1,  -1,   0,  -1,   0,   2,   0,  -5,  -1,   0,   1,   0,   0,   2,   2,  -2,
+  ], [
+     3,   1,  -1,  -1,   0,   1,   1,   2,   1,   0,   0,   1,   1,   1,   1,   1,
+   -10,  -8,  -2,   1,   2,   1,   1,   1,  -1,   1,   2,   1,   0,   0,   0,   0,
+  ], [
+    -1,  -1,   0,   1,   2,   2,   2,   1,  -1,  -1,  -1,   0,  -1,  -3,  -5,  -4,
+     1,   1,   2,   1,   1,   0,   0,   2,  -1,  -2,  -1,  -1,  -1,   0,   2,   4,
+  ], [
+    -3,  -7,  -5,   0,   2,   0,   0,   0,   3,  -1,  -2,   1,   2,   1,   1,   2,
+     1,  -2,  -1,   1,   2,   1,   0,   1,   0,  -1,   0,   3,   2,  -1,  -1,  -1,
+  ], [
+     2,   1,   1,   0,   0,   0,   0,   0,  -9,  -7,  -2,   3,   3,   2,   1,   1,
+     3,   2,   0,  -2,  -2,  -1,   1,   1,   0,  -1,   0,   0,   1,   1,   0,   0,
+  ], [
+    -2,  -1,   1,   1,   1,   0,   0,   0,   1,   2,   1,  -2,  -4,  -3,   1,   2,
+     1,   2,   1,  -2,  -3,   0,   3,   1,  -1,  -1,   0,   0,   1,   3,   0,  -4,
+  ], [
+     2,   0,  -1,   1,   2,  -2,  -2,   3,   2,   0,  -1,   2,   3,  -2,  -4,   1,
+     0,   1,   1,   1,   2,  -2,  -6,  -2,  -1,   0,   0,   0,   2,   0,  -2,  -1,
+  ], [
+    -1,  -1,   1,   2,   1,  -2,  -3,  -2,   3,  -1,  -2,  -1,  -1,   0,   1,   2,
+    10,   4,   0,   0,  -1,  -2,  -2,  -1,   3,  -1,  -2,  -1,   0,  -1,  -1,   0,
+  ], [
+    -5,   2,   7,   1,  -4,  -2,   1,   0,  -2,   2,   3,  -1,  -3,   0,   2,   0,
+     2,   1,   0,   0,   1,   1,  -1,  -2,   1,  -2,  -2,  -1,  -1,  -2,   0,   0,
+  ], [
+     0,   3,  -2,  -7,  -1,   3,   0,   0,   1,   3,  -3,  -5,   2,   3,  -1,   0,
+     0,   2,  -2,  -2,   4,   2,  -2,   0,  -1,   1,  -1,   0,   2,  -1,  -2,   1,
+  ], [
+     4,   0,  -3,  -4,  -2,   1,   2,   1,   0,   0,   3,   5,   3,   1,  -1,  -2,
+     1,   1,   1,  -1,  -3,  -1,   1,   1,   1,  -1,  -2,  -2,   0,   0,  -1,  -2,
+  ]
+];
+
+pub const SVQ_INTRA_CB_4X4: [[i8; 16]; 96] = [
+  [
+   -11,  -3,   3,   6, -10,  -1,   5,   7,  -9,  -1,   6,   7,  -9,  -1,   4,   6,
+  ], [
+     5,   7,   0, -14,   6,   9,   2, -15,   6,   9,   2, -15,   4,   6,   0, -14,
+  ], [
+    16,   3,  -5,  -6,  16,   1,  -8,  -8,  14,  -1,  -9,  -9,  12,   0,  -8,  -8,
+  ], [
+     8,  12,  16,  17,  -2,   2,   6,   9, -10,  -8,  -4,   0, -15, -14, -11,  -7,
+  ], [
+    -7, -10,  -2,  16,  -7, -11,  -3,  18,  -7, -11,  -1,  20,  -6,  -8,   1,  19,
+  ], [
+    -9, -13, -16, -17,   2,  -2,  -7,  -9,  11,   8,   4,  -1,  16,  15,  11,   7,
+  ], [
+   -22,  -2,  13,  15, -24,  -2,  14,  16, -25,  -4,  13,  15, -25,  -6,  10,  13,
+  ], [
+    26,  26,  22,  16,  17,  15,   9,   3,  -2,  -6, -11, -14, -20, -25, -28, -28,
+  ], [
+   -27, -27, -25, -21, -16, -15, -11,  -7,   3,   8,  12,  13,  23,  28,  31,  30,
+  ], [
+    20,  16,  -7, -33,  22,  19,  -6, -35,  22,  19,  -6, -34,  20,  17,  -6, -32,
+  ], [
+   -20, -20,   2,  38, -21, -22,   2,  40, -21, -22,   2,  40, -20, -20,   3,  38,
+  ], [
+   -47,  -4,  24,  26, -50,  -3,  26,  27, -50,  -3,  26,  27, -47,  -4,  24,  26,
+  ], [
+    45,   6, -23, -27,  48,   5, -25, -28,  48,   5, -26, -28,  44,   6, -24, -27,
+  ], [
+   -30, -36, -10,  76, -31, -37, -11,  78, -31, -37, -11,  78, -31, -36, -10,  77,
+  ], [
+   -53, -32,  35,  52, -54, -34,  36,  52, -54, -34,  36,  52, -53, -33,  34,  51,
+  ], [
+   -93, -34,  62,  65, -93, -34,  62,  66, -93, -34,  62,  65, -93, -34,  60,  64,
+  ], [
+    -7,   0,   2,   2,  -8,  -1,   3,   3,  -8,   0,   4,   5,  -6,   1,   5,   5,
+  ], [
+     3,   7,  11,  11,   2,   2,   3,   3,   1,  -2,  -6,  -7,   1,  -5, -11, -13,
+  ], [
+     3,  -2,  -4,  -3,   7,   0,  -5,  -5,  12,   4,  -5,  -7,  14,   6,  -4,  -7,
+  ], [
+    18,  14,   3,  -2,   6,   4,   0,  -3,  -8,  -5,  -2,   0, -16, -11,  -2,   2,
+  ], [
+    -8,  -6,   7,  18,  -7,  -8,   2,  13,  -4,  -6,  -2,   6,   0,  -4,  -3,   1,
+  ], [
+     1,  -3, -13, -18,   0,  -1,  -5,  -7,  -1,   1,   6,   7,  -2,   4,  15,  17,
+  ], [
+   -15, -14,  -7,  -2,  -6,  -5,  -1,   0,   6,   6,   3,   1,  15,  13,   6,   1,
+  ], [
+     2,  -2, -11,  10,   2,  -1, -12,  11,   3,  -1, -12,  11,   2,  -2, -11,  11,
+  ], [
+    -9,  14,  -1,  -5,  -9,  15,  -2,  -5,  -8,  16,  -2,  -5,  -7,  15,  -1,  -4,
+  ], [
+     2,   6,   8,   8,  -2,   3,   9,  12, -11,  -5,   4,  10, -19, -16,  -8,   0,
+  ], [
+    14,   8,  -7, -15,  12,   7,  -7, -14,   8,   5,  -4,  -9,   5,   3,  -1,  -4,
+  ], [
+    12, -14,  -2,   2,  13, -15,  -1,   3,  14, -15,  -1,   3,  13, -14,  -1,   3,
+  ], [
+     0,   6,  10, -13,   0,   6,  10, -15,   0,   7,   9, -17,   1,   6,   8, -16,
+  ], [
+    -8,  -5,  15,  -2,  -8,  -6,  17,  -2,  -8,  -6,  16,  -3,  -8,  -5,  15,  -2,
+  ], [
+    -9, -11, -11, -10,   9,  10,   9,   8,   8,  10,  10,   9,  -8,  -9,  -8,  -7,
+  ], [
+     9,  10,   9,   7,  -8, -10, -10, -10,  -7, -10, -11, -11,  11,  12,  11,   8,
+  ], [
+     0,  10,   7,   0,   0,   7,   0,  -6,   0,   2,  -5,  -6,  -2,  -1,  -4,  -1,
+  ], [
+     5,   0,  -6,  -9,   2,   2,   2,   1,  -2,   0,   5,   7,  -6,  -5,   1,   4,
+  ], [
+     3,  -8,   2,  -1,   4,  -9,   3,   0,   5,  -7,   3,   0,   7,  -5,   3,   0,
+  ], [
+    -5,  -3,   2,   9,  -6,  -3,   1,   8,  -6,  -3,   1,   7,  -5,  -2,   0,   4,
+  ], [
+    13,   8,   3,   1,  -3,  -5,  -4,  -1,  -8,  -7,  -3,   0,  -1,   1,   3,   2,
+  ], [
+     3,   2,  -5, -12,   4,   3,  -2,  -9,   3,   4,   1,  -4,   3,   5,   4,  -1,
+  ], [
+    -9,  -8,  -4,   0,   8,   6,   2,   0,  10,   8,   3,   0,  -6,  -5,  -3,  -1,
+  ], [
+    -3,  -9, -12,  -5,   0,  -3,  -5,   0,   2,   3,   2,   4,   5,   8,   7,   6,
+  ], [
+    -1,  -2,   5,  12,  -1,  -1,   5,   9,   2,   1,  -1,  -2,   2,  -1, -11, -17,
+  ], [
+    -7,   3,   3,  -1,  -9,   3,   4,  -1, -10,   4,   6,  -1,  -9,   5,   7,   0,
+  ], [
+   -18,  -7,   2,   2,  -8,   1,   5,   3,   3,   4,   1,   0,   9,   5,  -2,  -3,
+  ], [
+    -2,   0,   6,   8,  -4,  -5,  -5,  -3,   1,  -2,  -6,  -8,  10,   9,   3,  -1,
+  ], [
+     0,  -2,  -2,   0,   0,  -4,  -5,   0,  -2,  -8,  -4,   8,  -5,  -7,   6,  24,
+  ], [
+     9,   1,  -7,   1,   9,   1,  -8,   1,   8,   0, -10,   1,   8,  -1, -11,  -1,
+  ], [
+     8,   8,   6,   3,   5,   4,   3,   2,  -2,  -3,  -1,   0, -10, -13,  -8,  -4,
+  ], [
+     0,   4,   2,  -3,   0,   6,   3,  -5,   3,  10,   2, -12,   5,  10,  -4, -22,
+  ], [
+     0,  -4,  -1,   3,   1,  -4,  -1,   5,   1,  -5,   0,   8,  -1,  -6,  -2,   7,
+  ], [
+    -1,  -1,  -2,  -4,  -1,  -2,  -4,  -6,  -1,  -1,  -1,  -2,   1,   5,  10,   9,
+  ], [
+    10,   3,   0,  -2,   6,  -1,  -2,  -5,   3,  -1,  -2,  -6,   2,   0,   0,  -5,
+  ], [
+     6,   3,   0,   0,   6,   3,   1,   1,   4,  -2,  -2,   1,   0,  -9,  -9,  -2,
+  ], [
+   -11,  -3,   1,   2,  -6,   2,   4,   5,  -3,   2,   3,   4,  -2,   1,   1,   2,
+  ], [
+    -6,  -4,  -1,  -2,   2,  -1,  -1,  -2,  10,   2,  -2,  -2,  11,   2,  -4,  -1,
+  ], [
+     6,   0,  -2,   2,   3,   3,   0,   0,  -6,   3,   3,   0, -17,  -1,   5,   0,
+  ], [
+    -1,   4,  10,  11,  -3,  -2,   0,   1,  -3,  -4,  -5,  -3,  -1,  -2,  -2,  -1,
+  ], [
+     2,  -3,  -9, -12,   3,   3,   3,   2,   2,   2,   4,   4,   2,   1,  -1,  -2,
+  ], [
+    -2,   9,   5, -10,  -3,   5,   5,  -5,  -2,   1,   2,   0,  -1,  -2,  -2,   1,
+  ], [
+    -2,  -3,   7,  -2,  -1,  -3,   7,  -3,  -1,  -2,   8,  -4,  -2,  -2,   7,  -3,
+  ], [
+     1,  -8,  -3,  12,   2,  -2,  -2,   4,   1,   3,   0,  -5,  -1,   5,   2,  -7,
+  ], [
+    -1,   3,   1,  -5,  -7,  -2,   3,   1,  -2,  -7,  -2,   2,  20,   3,  -5,  -1,
+  ], [
+     5,   0,  -3,  -2,  -7,  -7,   0,   6,  -6,   0,   7,   6,   2,   6,   0,  -7,
+  ], [
+    -2,   6,  -7,   1,  -2,   7,  -8,   3,  -2,   7,  -7,   3,  -1,   7,  -6,   2,
+  ], [
+    -5,  -2,   5,   7,   4,   1,  -4,  -8,   6,   3,  -2,  -5,  -7,  -5,   3,   7,
+  ], [
+    -1,  -1,   6,   5,   0,  -1,   1,  -4,   2,   1,   0,  -7,   1,   0,   0,  -4,
+  ], [
+    -8,   0,   3,   1,  -2,   1,  -1,  -1,   1,  -1,  -3,   1,   1,  -2,   1,   9,
+  ], [
+     5,   2,  -3,  -4,  -1,   0,  -1,  -3,  -3,   1,   3,   1,  -4,   0,   4,   2,
+  ], [
+     2,  -2,  -2,  12,   0,  -2,  -5,   3,  -1,   0,  -3,   1,  -3,  -1,  -2,   1,
+  ], [
+     1,   5,   3,   0,  -6,  -4,  -2,   1,   0,  -2,  -2,   2,   6,   1,  -4,  -1,
+  ], [
+    -3,  -5,  -5,  -1,   3,   5,   5,   4,   0,   3,   1,  -1,  -2,   1,  -2,  -3,
+  ], [
+     2,  -4,  -5,  -3,   4,  -2,  -3,  -2,   6,   0,  -1,  -1,   7,   1,   0,   0,
+  ], [
+    -3,  -2,  -2,   0,  -2,  -3,  -5,  -1,  -2,   2,   0,  -1,  -1,  11,   9,  -1,
+  ], [
+     0,   1,  -1, -10,  -1,   1,   0,  -6,   1,   0,   1,   4,   2,  -5,  -1,  13,
+  ], [
+    -2,   4,   5,   0,  -5,   1,   6,   3,  -6,  -2,   3,   2,  -5,  -2,   0,  -2,
+  ], [
+    -1,   1,   1,  -2,  -1,  -2,   0,   2,   5,   5,   5,   7,   0,  -4,  -8,  -7,
+  ], [
+     0,   2,  -1,  -5,  -1,   2,   2,  -3,   0,   5,   3,  -5,   3,   8,   2, -12,
+  ], [
+     8,   4,   0,  -2,  10,  -1,  -4,  -1,   3,  -6,  -3,   0,  -4,  -5,   0,   0,
+  ], [
+     0, -10,  -4,   2,  -1,  -6,   3,   5,  -1,  -3,   6,   4,   0,  -2,   4,   2,
+  ], [
+     0,   8,   1,  -1,   0,  11,   1,  -3,  -1,   6,  -2,  -4,  -3,  -2,  -7,  -4,
+  ], [
+     0,  -1,  -1,  -1,   4,   5,   6,   5,  -5,  -9,  -8,  -5,   2,   2,   3,   2,
+  ], [
+     0,   2,   6,   1,   2,   0,   3,   0,   1,  -2,  -1,  -2,   0,  -1,  -3,  -6,
+  ], [
+     0,   0,   2,   0,   4,   0,   2,   1,   5,  -2,   0,   0,  -2,  -9,  -1,   2,
+  ], [
+     0,   1,   0, -10,  -1,   1,   8,   0,  -1,  -2,   4,   0,   1,  -1,   2,  -1,
+  ], [
+    -3,  -2,   2,  -1,  -3,  -1,   2,  -3,   0,  -1,   1,   0,   8,   1,  -1,   3,
+  ], [
+     0,   1,   1,   2,   0,  -4,  -2,   0,  -1,  -5,   1,  -1,  -2,  -1,  11,   2,
+  ], [
+     1,   5,  -2,  -2,   0,   2,  -4,   0,  -2,   1,  -5,   1,   0,   5,   0,   1,
+  ], [
+    -5,  -3,   0,   6,  -4,   2,   0,   0,  -3,   5,   1,   0,  -3,   3,   0,   0,
+  ], [
+     3,  -2,  -3,   1,   1,  -4,   0,   8,  -2,  -3,  -2,   3,   1,   2,  -1,  -1,
+  ], [
+     1,   1,   0,   2,   2,   0,   1,   6,   1,  -1,   2,   1,   0,   3,   0, -19,
+  ], [
+     1,  -3,  -2,   2,   6,   5,  -2,  -7,  -3,   1,   3,   1,  -1,  -1,   0,   2,
+  ], [
+    -8,  -1,  -1,  -4,   1,   1,  -1,   2,   4,   3,   2,   3,  -5,   1,   3,   0,
+  ], [
+     0,   2,  -1,   1,  -3,   0,   0,   5,  -5,  -2,   0,   8,  -4,  -4,  -4,   6,
+  ], [
+     1,   2,   1,   2,   2,   2,  -3,   2,   4,   0,  -9,   0,   7,   0, -11,   1,
+  ], [
+     0,   0,   0,  -2,   3,   3,  -1,  -6,   4,   3,  -3, -10,  -1,   2,   6,   2,
+  ], [
+     7,  -2,  -3,   5,  -4,   0,   3,  -1,  -4,   2,   1,  -7,   2,  -1,  -1,   3,
+  ], [
+     3,   2,   2,   2,  -5,  -7,  -7,  -5,   5,   6,   4,   2,  -2,  -1,   0,   1,
+  ]
+];
+
+pub const SVQ_INTRA_CB_4X2: [[i8; 8]; 96] = [
+  [
+    12,  13,  13,  11,  -7, -10, -15, -17,
+  ], [
+   -16, -15, -12, -10,  11,  15,  15,  12,
+  ], [
+     2,  17,  20,  15, -45, -24,   2,  13,
+  ], [
+    21,  20,  -6, -36,  12,  16,  -1, -27,
+  ], [
+   -18, -21,  10,  45, -11, -20,  -7,  21,
+  ], [
+    43,  -8, -28,   0,  33, -16, -28,   3,
+  ], [
+   -12, -18, -18,  -6, -20, -10,  28,  55,
+  ], [
+    -5, -18, -21, -18,  56,  30,  -6, -20,
+  ], [
+   -34,  27,  29, -22, -30,  29,  26, -25,
+  ], [
+    30,  34,  33,  26, -25, -31, -35, -33,
+  ], [
+   -31, -35, -36, -32,  29,  36,  37,  31,
+  ], [
+   -71, -12,  38,  34, -63,  -1,  42,  33,
+  ], [
+    58,  37, -31, -60,  55,  34, -33, -61,
+  ], [
+   -57, -57,  22,  93, -57, -58,  21,  93,
+  ], [
+    59,  69,  70,  62, -63, -68, -68, -60,
+  ], [
+   -64, -71, -71, -64,  63,  73,  72,  62,
+  ], [
+    -2,   0,   7,  15, -11, -10,  -3,   5,
+  ], [
+    -5,  -8, -10, -10,   1,   9,  14,   9,
+  ], [
+    15,   8,  -4, -11,  12,   2, -11, -12,
+  ], [
+    -8,   0,  19,  28,   4,  -1, -15, -26,
+  ], [
+   -15,  27,   2, -14, -14,  22,   1,  -9,
+  ], [
+    -4,  -6, -13, -10,  -6, -14,   6,  47,
+  ], [
+   -35, -20,   6,  23,   6,   9,   6,   4,
+  ], [
+    -6,   2,  23, -22,  -7,   4,  28, -21,
+  ], [
+    20, -22,  -2,   6,  22, -28,  -5,   8,
+  ], [
+   -10, -18, -16, -12,  36,  19,   2,  -1,
+  ], [
+    -3,   0,   4,   8, -45, -10,  23,  23,
+  ], [
+    40,  15, -20, -35,  -4,  -1,   4,   1,
+  ], [
+     9,  -5, -33,  24,   8,   3, -26,  19,
+  ], [
+    -1,   4,   6,  -3,  32,  25, -13, -49,
+  ], [
+    24,  24,  15,   7, -17, -27, -19,  -7,
+  ], [
+   -47,   0,  39,  24, -21,  -6,   7,   4,
+  ], [
+    -1,   0, -10, -13,   1,   1,   5,  16,
+  ], [
+    20,   5,  -3,  -9,  -1,  -4,  -2,  -6,
+  ], [
+   -17,  -7,   1,   4,  12,   7,   0,   0,
+  ], [
+     3,   0,  12,  11,  -3,   1,   0, -23,
+  ], [
+     4,  17,  -6,   0,   6,   3, -25,   0,
+  ], [
+   -17,  10,   8,   5, -14,   4,   1,   4,
+  ], [
+    13,  10,   4,   2, -23,  -9,   1,   2,
+  ], [
+     3,  -3,   1,   7,   1, -23,  -7,  20,
+  ], [
+    -7, -18,   2,  12,  -5,  -4,  10,   9,
+  ], [
+     4,  10,   7, -24,   6,   3,   4, -10,
+  ], [
+    22, -14, -22,   6,   0,   5,   5,  -1,
+  ], [
+    -4,   3, -11,  -4,  -7,  31,   7, -14,
+  ], [
+    -5, -16,  -1,  42,  -4,  -2,  -9,  -5,
+  ], [
+     5,  -8,  -6,  -3,  42,  -4, -21,  -5,
+  ], [
+   -18,  12,  20, -12,  13, -13, -10,   7,
+  ], [
+    -8,  -9,  -2, -18, -16,   6,  40,   8,
+  ], [
+    10,  -1,   0,   4,  -3,   4,  -1, -13,
+  ], [
+    -2,   6,   1, -15,   5,   3,   1,   2,
+  ], [
+    -4,  -2,   1,   3,  15,   0,  -9,  -4,
+  ], [
+    -3,  -4,  -4,  -4,  -3,   5,  16,  -3,
+  ], [
+     2,  13,   3,   4,  -3,  -8, -10,   0,
+  ], [
+    -6,  -2,  -4,  -1,  -2,  -3,  -6,  23,
+  ], [
+     6,  -6,   7,   1,   4, -18,   5,   1,
+  ], [
+    -1,   1, -15,  14,  -5,   6,  -4,   4,
+  ], [
+     2,   2,   2,   6, -24,   2,   7,   3,
+  ], [
+   -26,   0,   3,   3,   5,   7,   1,   6,
+  ], [
+    14,  -2, -18,  -3,   7,   5,  -4,   2,
+  ], [
+    -6,   3,  32,   1,  -6,  -6,  -6, -12,
+  ], [
+     5, -36,   7,   6,   9,  -1,  11,   0,
+  ], [
+     4,   4,   5,   3,   4,  15,   3, -38,
+  ], [
+    10,  23,  -5, -42,   0,   4,   4,   4,
+  ], [
+    23,  17,  -6, -13, -13, -37,   1,  29,
+  ], [
+     5, -14,  -1,   1,   5,   0,   3,   1,
+  ], [
+     0,   4,  -5,   2,   8,   0,   0, -10,
+  ], [
+     4,   7,  -2,  -3, -10,   3,   1,   1,
+  ], [
+   -12,  -1,  13,   3,   0,  -1,   1,  -3,
+  ], [
+     0,  -1,   3,   1,  -6,  -9,   3,   9,
+  ], [
+    -6,   1,  -4,  -6,   8,  -1,   0,   8,
+  ], [
+    -3,  -3,   0,  18,  -5,  -1,  -4,  -1,
+  ], [
+    -8,  -2,   3,  -4,   0,  17,  -1,  -5,
+  ], [
+     5,  -2,   9, -10,   1,  -5,   6,  -5,
+  ], [
+     4,   2,   2,   3,  10, -14,  -8,   1,
+  ], [
+    -1,  -2, -18,  -1,  -1,  20,   1,   2,
+  ], [
+    -1,   1,  -9,   1,  -1,  -9,  22,  -4,
+  ], [
+     6,  -4,   8,  -3,  -1,   7, -19,   5,
+  ], [
+    -7,  31,  -4,  -4,  -6,   0,  -5,  -5,
+  ], [
+    -7,  -8, -19,  -4,   1,   1,   4,  32,
+  ], [
+    38,  -1,  -8,   4,  -7,  -8,  -6, -12,
+  ], [
+    -1,   0,  -7,   1,  -1,   9,  -1,   0,
+  ], [
+     9,  -1,  -1,   0,   2,  -6,   1,  -3,
+  ], [
+   -12,   0,   2,   1,   1,   1,   8,   0,
+  ], [
+     9,   1,   0,   2,  -2,   1, -11,   0,
+  ], [
+     0,   8,   2, -10,  -1,   2,  -1,   0,
+  ], [
+    -2,  -4,   0,  -5,  -2,  -1,  -1,  14,
+  ], [
+    -3,   7,  -1,   5,   0, -10,   1,   1,
+  ], [
+    -1,  -5,  14,  -1,  -2,   1,  -3,  -2,
+  ], [
+    -6,   0,   0,   6,   2,   3,  -9,   4,
+  ], [
+     4,  -5,  -1,  -1,  -7,   3,   8,  -1,
+  ], [
+     2,  -4,  -1, -11,  11,   2,   1,   0,
+  ], [
+    -1,   2,   3,   9,   0,   2,   0, -15,
+  ], [
+     3,   5, -20,   3,   3,  -1,   3,   3,
+  ], [
+     1,  -1,  16,   1,   2, -29,   9,   2,
+  ], [
+   -13,  -6,  -1,  -3,  36,  -1,  -8,  -3,
+  ], [
+     2,   5,   4,   2, -37,   9,  11,   3,
+  ]
+];
+
+pub const SVQ_INTER_CB_8X8: [[i8; 64]; 96] = [
+  [
+    -4,  -3,   4,   5,   2,   1,   1,   0,  -5,  -3,   5,   5,   2,   1,   0,   0,
+    -6,  -4,   5,   5,   2,   1,   0,   0,  -7,  -4,   4,   5,   2,   1,   0,   0,
+    -8,  -5,   3,   4,   2,   1,   0,   0,  -8,  -6,   3,   4,   1,   1,   1,   0,
+    -8,  -6,   2,   4,   2,   1,   1,   0,  -8,  -6,   2,   4,   1,   1,   1,   1,
+  ], [
+    -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -2,  -2,  -2,  -2,  -2,  -2,  -2,
+    -2,  -3,  -3,  -3,  -3,  -3,  -3,  -3,  -2,  -3,  -3,  -3,  -3,  -3,  -4,  -3,
+    -2,  -2,  -2,  -2,  -2,  -3,  -3,  -2,   1,   1,   1,   1,   1,   0,  -1,  -1,
+     4,   5,   5,   5,   4,   3,   3,   2,   7,   7,   8,   8,   8,   7,   6,   5,
+  ], [
+     2,   1,   2,   4,   4,   0,  -4,  -6,   1,   1,   2,   5,   5,   1,  -5,  -7,
+     1,   2,   1,   4,   5,   1,  -5,  -8,   1,   1,   1,   5,   5,   0,  -6,  -8,
+     0,   1,   1,   5,   6,   1,  -6,  -9,   0,   0,   1,   4,   5,   0,  -5,  -8,
+     0,   0,   1,   4,   5,   0,  -5,  -7,   0,   0,   1,   4,   4,   1,  -4,  -7,
+  ], [
+     1,   2,   3,   0,  -3,  -4,  -3,  -1,   1,   3,   4,   0,  -3,  -4,  -3,  -1,
+     2,   4,   5,   1,  -3,  -4,  -3,  -2,   2,   5,   6,   1,  -3,  -5,  -4,  -2,
+     3,   6,   6,   1,  -3,  -5,  -4,  -2,   3,   6,   6,   1,  -3,  -5,  -4,  -2,
+     3,   6,   6,   1,  -3,  -5,  -4,  -2,   3,   5,   5,   1,  -3,  -4,  -4,  -2,
+  ], [
+     2,   2,   2,   2,   1,   0,   0,  -1,   4,   4,   4,   3,   2,   1,   1,   0,
+     4,   5,   4,   4,   3,   3,   2,   1,   4,   4,   4,   4,   4,   3,   2,   2,
+     2,   3,   3,   3,   3,   3,   2,   1,  -1,  -1,  -1,  -1,   0,   0,   0,   0,
+    -5,  -6,  -6,  -5,  -5,  -4,  -3,  -3,  -7,  -9,  -9,  -8,  -7,  -6,  -6,  -5,
+  ], [
+     6,   6,   6,   6,   6,   5,   5,   4,   4,   4,   4,   3,   3,   3,   3,   2,
+     0,  -1,  -1,  -1,  -2,  -2,  -1,  -1,  -3,  -5,  -6,  -6,  -6,  -6,  -5,  -4,
+    -3,  -5,  -6,  -7,  -6,  -6,  -5,  -4,  -1,  -2,  -2,  -2,  -2,  -2,  -1,  -1,
+     0,   1,   1,   1,   1,   1,   1,   1,   3,   3,   3,   3,   3,   3,   3,   3,
+  ], [
+     2,   1,  -2,  -5,  -4,   0,   2,   5,   2,   1,  -2,  -6,  -5,   0,   3,   5,
+     2,   1,  -2,  -6,  -6,  -1,   3,   6,   3,   2,  -2,  -7,  -6,   0,   4,   7,
+     2,   1,  -2,  -7,  -5,   0,   5,   7,   2,   1,  -2,  -6,  -5,   0,   4,   7,
+     2,   1,  -2,  -6,  -4,   0,   4,   6,   1,   1,  -2,  -5,  -4,   0,   3,   6,
+  ], [
+   -10,  -9,  -6,  -4,  -1,   2,   3,   2, -10,  -9,  -5,  -3,   0,   4,   4,   3,
+    -9,  -7,  -3,  -1,   2,   5,   5,   3,  -7,  -5,  -2,   0,   3,   5,   5,   3,
+    -6,  -3,   0,   1,   4,   6,   5,   3,  -4,  -2,   1,   2,   3,   5,   4,   2,
+    -2,   0,   1,   2,   2,   4,   3,   1,  -1,   1,   2,   2,   2,   3,   3,   1,
+  ], [
+    -4,  -5,  -5,  -6,  -6,  -6,  -6,  -5,  -3,  -3,  -4,  -4,  -4,  -4,  -4,  -4,
+     0,   0,   0,   0,  -1,  -1,  -1,  -1,   5,   5,   6,   5,   5,   4,   3,   2,
+     5,   6,   7,   7,   7,   6,   5,   4,   3,   3,   4,   4,   4,   4,   3,   2,
+     0,  -1,   0,   0,  -1,  -1,   0,  -1,  -3,  -3,  -4,  -4,  -4,  -4,  -3,  -3,
+  ], [
+     1,  -2,  -5,   1,   5,   4,   2,   0,   1,  -3,  -6,   1,   6,   5,   2,   0,
+     0,  -4,  -7,   0,   6,   6,   2,   1,  -1,  -5,  -9,  -1,   6,   6,   3,   1,
+    -1,  -6, -10,  -2,   6,   6,   3,   1,  -1,  -6,  -9,  -2,   5,   6,   3,   1,
+    -2,  -6,  -9,  -2,   5,   5,   3,   1,  -2,  -6,  -7,  -2,   4,   4,   2,   1,
+  ], [
+    -5,  -7,  -8,  -9,  -9,  -8,  -7,  -6,  -5,  -6,  -6,  -7,  -7,  -6,  -6,  -5,
+    -3,  -3,  -3,  -4,  -5,  -5,  -4,  -4,  -1,   0,   0,  -1,  -1,  -1,  -1,  -1,
+     0,   1,   2,   2,   2,   2,   2,   1,   2,   3,   4,   5,   5,   5,   5,   4,
+     3,   4,   5,   6,   8,   8,   8,   7,   3,   4,   5,   6,   7,   7,   7,   6,
+  ], [
+     5,   6,   7,   8,   9,  10,  10,   9,   3,   4,   6,   7,   8,   9,   9,   8,
+     0,   1,   2,   3,   4,   5,   5,   5,  -1,  -2,  -1,  -1,   0,   1,   2,   2,
+    -2,  -3,  -3,  -3,  -3,  -2,  -1,   0,  -3,  -4,  -5,  -5,  -5,  -5,  -5,  -4,
+    -4,  -5,  -5,  -6,  -7,  -7,  -6,  -5,  -3,  -4,  -5,  -6,  -7,  -7,  -6,  -6,
+  ], [
+    13,   7,   0,  -3,  -3,  -4,  -4,  -5,  14,   7,   0,  -3,  -3,  -4,  -4,  -4,
+    15,   8,  -1,  -4,  -4,  -4,  -5,  -4,  15,   8,  -1,  -4,  -4,  -5,  -4,  -3,
+    15,   7,  -1,  -4,  -5,  -5,  -5,  -4,  14,   7,  -1,  -4,  -4,  -4,  -4,  -3,
+    12,   6,  -1,  -4,  -4,  -4,  -4,  -3,  11,   5,  -1,  -4,  -4,  -4,  -4,  -3,
+  ], [
+   -17,  -4,   5,   4,   4,   4,   3,   3, -18,  -5,   5,   4,   4,   4,   3,   3,
+   -19,  -5,   6,   4,   4,   4,   3,   2, -20,  -5,   6,   4,   4,   4,   3,   3,
+   -20,  -4,   6,   4,   4,   5,   3,   3, -19,  -5,   6,   4,   4,   5,   3,   3,
+   -18,  -4,   5,   4,   4,   4,   3,   2, -17,  -5,   4,   3,   4,   4,   3,   3,
+  ], [
+    -6,  -6,  -6,  -4,  -2,   1,   6,  11,  -6,  -7,  -7,  -4,  -2,   2,   8,  13,
+    -8,  -8,  -7,  -4,  -2,   3,   9,  14,  -8,  -8,  -7,  -5,  -1,   4,  10,  16,
+    -8,  -8,  -7,  -5,  -1,   4,  10,  17,  -8,  -8,  -7,  -4,   0,   5,  10,  16,
+    -8,  -8,  -6,  -3,   0,   4,   9,  15,  -7,  -7,  -5,  -3,   0,   4,   8,  12,
+  ], [
+     8,   7,   7,   5,   2,  -2,  -8, -14,   8,   8,   7,   5,   2,  -2,  -8, -15,
+     8,   8,   7,   5,   1,  -3,  -9, -16,   8,   8,   7,   5,   1,  -3, -10, -17,
+     8,   9,   8,   5,   1,  -3, -10, -17,   8,   8,   7,   4,   1,  -4, -10, -16,
+     7,   7,   7,   4,   1,  -3,  -9, -14,   6,   7,   6,   3,   0,  -3,  -9, -13,
+  ], [
+     5,   1,  -4,  -4,  -3,  -1,   0,   0,   7,   2,  -3,  -3,  -2,  -1,   1,   0,
+     7,   1,  -3,  -3,  -1,   0,   1,   1,   6,   1,  -3,  -2,  -1,   1,   1,   0,
+     6,   0,  -4,  -2,  -1,   0,   1,   0,   5,   0,  -4,  -3,  -1,   0,   0,  -1,
+     5,   0,  -3,  -1,   0,   0,   0,  -2,   4,   1,  -2,  -1,   0,   1,   0,  -1,
+  ], [
+     2,   2,   1,   1,  -2,  -6,  -8,  -8,   1,   1,   1,   1,  -2,  -5,  -8,  -8,
+     1,   1,   1,   0,  -1,  -3,  -5,  -5,   0,   0,   0,   0,  -1,  -1,  -1,  -2,
+     0,  -1,   0,   0,   0,   0,   1,   0,   1,   0,   0,   0,   1,   2,   3,   2,
+     2,   1,   1,   1,   2,   3,   4,   3,   3,   3,   3,   3,   4,   4,   5,   4,
+  ], [
+    -4,  -4,  -3,  -2,   0,   0,   1,   1,  -4,  -4,  -3,  -2,  -1,   0,   0,   1,
+    -2,  -2,  -2,  -1,  -1,  -1,   0,   0,   0,   1,   0,   0,   0,   0,   0,  -1,
+     2,   2,   2,   2,   2,   2,   1,   1,   3,   4,   4,   4,   4,   4,   4,   3,
+     1,   1,   1,   3,   3,   4,   3,   3,  -5,  -6,  -5,  -4,  -3,  -3,  -2,  -2,
+  ], [
+    -4,  -2,  -1,  -1,  -1,  -1,   0,   1,  -4,  -2,  -1,  -1,  -1,  -1,   0,   1,
+    -3,  -2,  -1,  -1,  -1,   0,   1,   2,  -4,  -3,  -2,  -1,  -1,   1,   3,   3,
+    -4,  -3,  -3,  -1,  -1,   1,   4,   5,  -4,  -3,  -2,  -2,  -1,   1,   4,   7,
+    -2,  -2,  -1,  -1,   0,   2,   6,   8,  -1,   0,   0,   1,   1,   4,   7,   8,
+  ], [
+    -3,  -3,  -3,  -2,  -2,  -1,  -1,   0,  -1,  -1,   0,   1,   2,   2,   3,   3,
+     0,   1,   2,   4,   5,   6,   6,   5,  -1,   0,   2,   3,   5,   6,   5,   3,
+    -1,  -1,   0,   2,   3,   3,   2,   1,  -2,  -2,  -1,   0,  -1,  -3,  -4,  -4,
+     0,   0,  -1,  -1,  -2,  -4,  -8,  -7,   1,   2,   1,   0,  -1,  -4,  -6,  -7,
+  ], [
+    -2,   4,   1,  -6,   0,   3,   0,   0,  -2,   5,   1,  -7,   0,   3,   0,   0,
+    -3,   5,   1,  -8,   0,   3,  -1,  -1,  -2,   6,   1,  -9,   0,   3,   0,  -1,
+    -2,   6,   2,  -8,   0,   4,   0,  -1,  -3,   5,   1,  -7,   1,   4,   0,   0,
+    -2,   4,   1,  -7,   0,   4,   1,   0,  -1,   4,   1,  -6,   0,   3,   1,   0,
+  ], [
+     0,   0,   0,   3,   4,   5,   4,   1,   1,   1,   1,   2,   3,   3,   2,   0,
+     2,   2,   1,   2,   2,   1,  -1,  -2,   4,   3,   1,   1,   0,  -1,  -3,  -5,
+     5,   3,   1,  -1,  -2,  -3,  -4,  -6,   5,   3,   0,  -2,  -3,  -5,  -6,  -7,
+     4,   3,   0,  -2,  -3,  -4,  -5,  -5,   4,   3,   0,  -1,  -2,  -2,  -3,  -3,
+  ], [
+     0,   0,   0,   0,  -1,  -5,  -2,   6,   0,   0,   0,   1,  -1,  -6,  -2,   8,
+     0,   0,   0,   2,   0,  -6,  -3,   9,   0,  -1,   0,   2,   0,  -7,  -2,  10,
+     0,  -1,   0,   2,  -1,  -8,  -3,  10,   0,  -1,  -1,   2,  -1,  -7,  -3,   9,
+     0,  -1,   0,   1,  -1,  -6,  -3,   8,   0,   0,   0,   1,   0,  -5,  -2,   7,
+  ], [
+     2,   3,   3,   2,   1,   0,  -1,  -1,   3,   4,   3,   2,   1,   0,  -1,  -2,
+     3,   4,   4,   2,   1,  -1,  -2,  -3,   2,   3,   3,   2,   0,  -1,  -2,  -3,
+    -1,   0,   1,   1,   0,  -1,  -2,  -2,  -5,  -4,  -3,  -1,   0,   1,   1,   1,
+    -8,  -8,  -5,  -1,   1,   3,   4,   3, -10,  -9,  -5,   0,   3,   5,   6,   5,
+  ], [
+    -5,  -1,   4,   5,   3,   1,   0,   0,  -6,  -1,   4,   5,   2,   0,  -1,  -2,
+    -6,  -1,   5,   4,   2,  -1,  -2,  -2,  -7,  -1,   4,   4,   1,  -2,  -3,  -3,
+    -6,  -1,   5,   4,   1,  -2,  -3,  -3,  -5,   0,   4,   4,   1,  -1,  -2,  -2,
+    -4,   0,   5,   4,   1,  -1,  -1,  -2,  -3,   1,   4,   3,   1,  -1,  -1,  -2,
+  ], [
+    -2,  -3,  -2,   1,   4,   6,   5,   3,  -3,  -4,  -4,   0,   3,   5,   4,   2,
+    -3,  -5,  -5,  -1,   2,   4,   3,   1,  -4,  -6,  -4,  -1,   2,   4,   2,  -1,
+    -2,  -4,  -3,   1,   2,   4,   2,  -1,  -2,  -4,  -2,   1,   3,   3,   1,  -2,
+    -2,  -3,  -2,   1,   3,   3,   1,  -2,  -2,  -2,  -1,   1,   3,   3,   0,  -2,
+  ], [
+    -4,  -4,  -3,  -2,  -1,   2,   5,   7,  -4,  -4,  -3,  -3,  -2,   1,   5,   7,
+    -2,  -3,  -2,  -3,  -3,  -1,   3,   5,  -1,  -1,   0,  -2,  -3,  -2,   2,   4,
+     1,   1,   1,  -1,  -4,  -3,   1,   3,   4,   3,   2,  -1,  -4,  -3,  -1,   1,
+     6,   4,   3,   0,  -3,  -3,  -2,   0,   6,   5,   3,   1,  -2,  -3,  -2,  -1,
+  ], [
+    12,  11,   8,   4,   0,  -2,  -2,  -1,  10,   9,   6,   2,  -1,  -2,  -1,   0,
+     4,   3,   2,   0,  -1,  -1,   0,   1,  -1,  -1,  -1,  -1,  -2,   0,   1,   2,
+    -3,  -5,  -4,  -2,  -2,   0,   2,   3,  -5,  -5,  -4,  -2,  -1,   0,   1,   2,
+    -5,  -5,  -4,  -2,  -1,   0,   1,   1,  -4,  -4,  -3,  -2,  -2,  -1,   0,   0,
+  ], [
+     3,   3,   2,  -1,  -3,  -4,  -3,  -2,   3,   2,   0,  -2,  -4,  -4,  -3,  -2,
+     2,   2,   1,  -1,  -3,  -5,  -4,  -3,   3,   3,   3,   1,  -2,  -3,  -3,  -3,
+     4,   4,   4,   3,   0,  -2,  -2,  -2,   5,   5,   5,   3,   0,  -1,  -2,  -2,
+     5,   5,   4,   2,  -1,  -2,  -3,  -2,   3,   3,   3,   0,  -2,  -4,  -4,  -4,
+  ], [
+    -1,  -1,   4,  -2,  -2,   6,   2,  -5,  -1,   0,   4,  -2,  -3,   6,   2,  -6,
+    -1,   0,   4,  -2,  -3,   7,   3,  -7,  -1,  -1,   4,  -3,  -4,   8,   3,  -7,
+     0,  -1,   4,  -3,  -4,   7,   3,  -6,  -1,  -1,   4,  -3,  -4,   7,   3,  -6,
+    -1,  -1,   3,  -3,  -4,   6,   3,  -6,  -1,   0,   3,  -2,  -3,   6,   3,  -5,
+  ], [
+     1,  -2,  -7,   2,   5,  -2,  -1,   1,   1,  -2,  -8,   3,   6,  -3,  -1,   2,
+     2,  -2,  -9,   4,   7,  -4,  -2,   2,   3,  -1,  -9,   5,   7,  -4,  -1,   3,
+     3,  -1,  -9,   4,   7,  -4,  -2,   2,   3,  -1,  -7,   4,   6,  -4,  -2,   1,
+     2,   0,  -6,   4,   6,  -4,  -1,   1,   2,   0,  -5,   3,   4,  -3,  -1,   1,
+  ], [
+    -2,   2,   2,   0,   0,  -1,  -3,  -4,  -2,   2,   2,   1,   1,   0,  -2,  -4,
+    -2,   2,   2,   2,   2,   1,  -1,  -2,  -3,   2,   3,   3,   4,   2,   0,  -2,
+    -3,   2,   3,   2,   4,   2,   0,  -3,  -4,   1,   2,   1,   2,   1,  -1,  -3,
+    -5,   0,   1,   0,   1,   1,  -2,  -3,  -4,   0,   0,   0,   1,   0,  -2,  -3,
+  ], [
+     0,   0,  -1,  -2,  -2,   2,   7,   8,   0,   0,  -1,  -3,  -2,   1,   6,   7,
+     0,   1,  -1,  -3,  -3,   0,   4,   5,   0,   1,   0,  -1,  -1,   0,   1,   3,
+     0,   2,   1,   1,   0,  -1,   0,   1,  -2,   0,   1,   2,   1,   0,  -1,  -1,
+    -5,  -2,   0,   1,   1,   0,  -3,  -3,  -6,  -4,  -1,   1,   1,  -1,  -3,  -4,
+  ], [
+    -4,  -2,   2,   5,   6,   4,   3,   2,  -5,  -3,   1,   4,   4,   2,   0,   0,
+    -4,  -2,   0,   2,   1,  -1,  -2,  -2,  -2,  -1,   0,   1,   0,  -2,  -3,  -2,
+    -2,   0,   0,   0,  -1,  -1,  -2,  -1,  -2,  -1,  -1,   0,   0,   0,   1,   2,
+    -2,  -2,  -1,  -1,   0,   1,   3,   4,  -2,  -3,  -2,  -1,   0,   2,   4,   5,
+  ], [
+     2,   1,  -2,  -2,  -1,   0,   1,   0,   1,   0,  -3,  -3,  -1,   0,   1,   0,
+     0,  -1,  -3,  -3,  -1,   1,   1,   1,   0,   0,  -3,  -1,   1,   2,   3,   3,
+     0,  -1,  -3,  -1,   1,   3,   3,   3,  -2,  -2,  -4,  -2,   1,   3,   4,   4,
+    -3,  -3,  -4,  -2,   1,   3,   3,   4,  -2,  -3,  -5,  -2,   1,   2,   3,   3,
+  ], [
+     4,   5,   3,   4,   4,   4,   4,   5,   3,   3,   1,   0,   0,   0,   0,   1,
+     1,   1,  -1,  -2,  -3,  -4,  -3,  -2,   2,   2,   0,  -2,  -2,  -4,  -3,  -2,
+     2,   3,   1,  -1,  -1,  -3,  -3,  -2,   1,   2,   0,   0,  -1,  -2,  -2,  -1,
+     0,   1,   0,  -1,  -1,  -3,  -2,  -1,   1,   1,   0,  -1,  -1,  -2,  -2,  -2,
+  ], [
+    -2,  -1,  -1,   0,   1,   2,   1,   0,   1,   2,   3,   5,   6,   5,   5,   3,
+     1,   2,   3,   4,   5,   5,   4,   3,  -2,  -2,  -3,  -3,  -2,  -1,   0,   0,
+    -3,  -3,  -4,  -5,  -4,  -3,  -2,  -1,  -1,  -1,  -2,  -2,  -2,  -1,   0,   0,
+     0,   1,   0,  -1,  -1,   0,   0,   1,  -1,   0,  -1,  -2,  -3,  -2,  -2,  -1,
+  ], [
+     7,   7,   6,   5,   4,   2,  -1,  -2,   3,   3,   2,   2,   1,   0,  -2,  -3,
+     0,  -1,  -1,  -1,   0,  -1,  -2,  -2,  -1,  -3,  -2,  -1,   0,   0,   0,   1,
+     0,  -2,  -2,  -1,  -1,   1,   2,   2,   3,   1,  -1,  -1,  -1,   1,   2,   2,
+     3,   1,  -2,  -3,  -2,  -1,   1,   2,   1,  -2,  -5,  -6,  -5,  -3,  -2,   0,
+  ], [
+     0,  -1,  -2,  -3,  -1,   0,  -2,  -2,   0,   0,  -1,  -1,   0,   1,  -1,  -2,
+     0,   0,  -2,  -1,   0,   0,   0,  -2,  -1,  -2,  -3,  -3,  -2,  -1,  -3,  -3,
+    -1,  -2,  -3,  -3,  -2,  -2,  -3,  -4,   2,   2,   0,   0,   0,   0,  -1,  -2,
+     5,   5,   3,   2,   2,   2,   0,  -1,   8,   8,   6,   5,   4,   4,   2,   1,
+  ], [
+    -7,  -8,  -6,  -3,  -1,  -1,  -2,  -1,  -5,  -5,  -3,   0,   2,   1,   0,   0,
+    -1,  -1,   0,   3,   4,   3,   1,   1,   2,   1,   1,   3,   4,   3,   2,   2,
+     3,   2,   0,   2,   3,   2,   1,   2,   4,   2,  -1,  -1,   0,   1,   1,   1,
+     3,   2,  -2,  -3,  -2,  -1,   0,   1,   3,   1,  -3,  -4,  -3,  -2,   0,   1,
+  ], [
+    -4,  -2,  -1,   2,   3,   3,   1,   0,  -7,  -5,  -4,  -2,   0,   0,  -1,  -2,
+    -6,  -5,  -5,  -4,  -2,  -2,  -2,  -3,  -1,   0,  -1,  -1,   0,   0,   0,  -1,
+     2,   3,   2,   2,   2,   2,   1,   0,   3,   5,   4,   3,   1,   0,   1,   0,
+     3,   4,   3,   2,   0,  -1,  -1,  -1,   5,   5,   3,   1,   0,  -1,  -1,  -1,
+  ], [
+     1,   1,   0,  -1,  -3,  -5,  -6,  -4,   1,   1,   0,   0,   0,  -3,  -3,  -1,
+     0,  -1,  -1,   0,   1,   0,   1,   3,  -2,  -2,  -3,  -1,   2,   2,   4,   7,
+    -2,  -2,  -2,   0,   2,   2,   3,   6,  -1,   0,   0,   1,   1,   0,   0,   3,
+     0,   3,   3,   3,   1,  -2,  -3,  -1,   1,   3,   4,   3,   0,  -3,  -5,  -4,
+  ], [
+     0,   2,   0,  -1,  -3,  -4,  -2,  -2,   1,   4,   2,   0,  -2,  -3,  -2,  -1,
+     3,   6,   3,   1,  -2,  -2,   0,  -1,   4,   7,   4,   1,  -2,  -3,  -1,   0,
+     3,   6,   3,   0,  -3,  -3,  -1,   0,   1,   3,   0,  -1,  -3,  -2,   1,   1,
+     0,   1,  -1,  -2,  -3,  -1,   2,   2,  -2,  -1,  -3,  -3,  -3,  -1,   1,   2,
+  ], [
+     3,   1,  -1,   0,   1,   0,   0,   0,   2,  -1,  -2,  -1,   1,   0,  -1,  -1,
+     1,  -1,  -2,   0,   1,   0,  -2,  -3,   0,  -2,  -1,   1,   3,   1,  -3,  -5,
+     0,  -2,  -1,   2,   5,   2,  -3,  -5,   0,  -2,  -1,   4,   6,   3,  -2,  -5,
+     0,  -2,   0,   4,   7,   4,  -2,  -4,   0,  -2,   0,   4,   6,   4,  -2,  -4,
+  ], [
+    -2,  -2,  -3,  -4,  -3,  -2,  -1,   0,   1,   1,   0,  -1,  -1,  -1,   0,   1,
+     3,   3,   2,   2,   1,   1,   1,   1,   2,   2,   2,   2,   1,   0,   0,   1,
+     0,   0,   0,   0,  -1,  -1,  -1,  -1,  -4,  -4,  -4,  -4,  -4,  -4,  -4,  -3,
+    -3,  -3,  -2,  -3,  -2,  -1,  -1,   0,   3,   4,   4,   5,   5,   6,   6,   7,
+  ], [
+    -1,  -2,   7,  -2,  -4,  -1,  -1,   0,  -1,  -2,   9,  -1,  -4,  -1,  -1,   0,
+    -1,  -3,  10,  -1,  -4,  -1,  -1,   1,  -1,  -3,  10,  -2,  -3,  -1,  -1,   2,
+    -1,  -2,  10,  -2,  -4,  -1,  -1,   2,  -1,  -2,   9,  -2,  -4,  -1,  -1,   2,
+    -1,  -2,   8,  -2,  -4,   0,  -1,   1,   0,  -2,   7,  -2,  -3,  -1,   0,   2,
+  ], [
+     3,  -4,   1,   3,  -3,  -2,   1,   0,   3,  -5,   1,   4,  -3,  -2,   1,   0,
+     3,  -6,   2,   5,  -3,  -1,   3,   0,   3,  -6,   2,   5,  -3,  -1,   2,   0,
+     3,  -6,   1,   5,  -4,  -2,   3,   0,   3,  -6,   1,   5,  -3,  -2,   2,   0,
+     2,  -6,   1,   4,  -3,  -1,   1,   0,   2,  -6,   1,   4,  -2,  -1,   1,   0,
+  ], [
+     0,   0,   1,   1,   1,   0,   0,   2,   0,  -1,   1,   1,   1,   0,   0,   2,
+     0,  -1,   0,   0,   0,   0,   0,   2,   0,  -1,   0,   0,   0,   0,  -1,   0,
+     1,   0,   1,   0,   0,  -1,  -2,  -1,   3,   1,   1,   0,   0,  -2,  -4,  -3,
+     5,   3,   2,   1,   0,  -3,  -5,  -4,   5,   4,   2,   0,  -1,  -4,  -5,  -5,
+  ], [
+     1,   0,  -1,  -2,  -2,  -3,  -6,  -9,   2,   0,  -1,  -1,   0,   0,  -3,  -6,
+     1,   0,   0,  -1,   0,   0,  -2,  -5,   2,   1,   1,   1,   1,   2,  -1,  -3,
+     1,   1,   2,   1,   2,   2,   1,  -1,   1,   1,   2,   1,   1,   1,   1,   1,
+     0,   0,   2,   1,   0,   0,   2,   2,   0,   1,   2,   2,   0,   0,   2,   2,
+  ], [
+    -4,  -3,   0,   1,   4,   6,   4,   3,  -3,  -2,   0,   0,   2,   4,   1,   0,
+    -1,  -1,   0,   0,   1,   1,  -2,  -3,   1,   1,   1,   0,   1,   1,  -3,  -5,
+     1,   1,   1,   0,   1,   1,  -3,  -5,  -1,   0,   0,  -1,   1,   1,  -2,  -4,
+    -1,   0,   0,  -1,   1,   2,   0,  -2,  -1,   0,   0,   0,   2,   3,   1,   0,
+  ], [
+    -1,   0,   3,   4,   0,  -4,  -5,  -5,   0,   0,   4,   5,   2,  -2,  -3,  -2,
+     0,  -1,   2,   4,   2,  -1,  -1,   0,   0,  -2,  -1,   1,   0,  -2,   0,   1,
+     1,  -2,  -2,   0,   0,  -1,  -1,   1,   1,  -2,  -3,   0,   1,   0,  -1,   0,
+     1,  -2,  -2,   1,   3,   1,   0,   0,   1,  -2,  -1,   2,   4,   2,   0,   0,
+  ], [
+     1,   2,   3,   2,   0,   2,   2,   1,  -1,   0,   1,   0,  -3,   1,   1,   1,
+    -1,   0,   0,  -2,  -4,   0,   2,   1,  -1,   2,   2,  -1,  -5,   0,   2,   1,
+    -1,   3,   4,  -1,  -5,   0,   2,   1,  -2,   2,   4,   0,  -4,  -1,   0,   0,
+    -4,   0,   2,   0,  -4,  -2,   0,   0,  -5,  -1,   2,   1,  -2,   1,   3,   2,
+  ], [
+     1,   0,   1,   0,   1,   2,  -1,  -2,   2,   0,  -1,  -2,   1,   3,   0,  -1,
+     3,   0,  -2,  -4,   0,   3,   1,   0,   5,   1,  -3,  -5,  -2,   2,   1,   1,
+     6,   1,  -2,  -5,  -2,   1,   0,   1,   5,   1,  -1,  -5,  -2,   0,  -1,   0,
+     3,   0,  -2,  -4,  -2,   0,  -1,   0,   1,  -1,   0,  -2,   0,   1,   0,   1,
+  ], [
+     1,   1,   2,   3,   2,   1,   1,   2,  -1,  -1,   0,   1,   1,   0,   1,   1,
+    -4,  -3,   0,   0,   1,   1,   1,   2,  -4,  -3,   0,   2,   2,   2,   3,   2,
+    -5,  -4,   0,   1,   1,   1,   1,   2,  -5,  -4,  -1,  -1,  -2,  -2,  -1,   0,
+    -3,  -2,   0,   0,  -2,  -3,  -2,  -1,   2,   3,   4,   4,   2,   0,   0,   0,
+  ], [
+    -4,  -2,   0,   1,   0,   0,   0,   0,  -3,  -1,   1,   1,   0,   0,   0,   0,
+    -2,   0,   2,   2,   0,   0,   0,   2,  -1,   1,   2,   1,  -1,   0,   3,   5,
+     0,   2,   1,  -1,  -2,   0,   5,   6,   0,   1,   0,  -3,  -3,   0,   4,   6,
+     1,   1,  -2,  -4,  -4,  -3,   1,   2,   1,   0,  -2,  -4,  -5,  -4,  -2,   0,
+  ], [
+    -1,  -3,  -3,  -3,  -3,  -2,  -1,  -1,   3,   2,   1,   0,   0,   1,   1,   1,
+     5,   4,   3,   2,   1,   1,   2,   2,   2,   1,   0,  -2,  -2,  -2,  -1,  -1,
+     0,   0,   0,  -1,  -2,  -2,  -2,  -2,   0,   1,   3,   3,   2,   1,  -1,  -1,
+     0,   1,   3,   4,   3,   2,   1,  -1,  -4,  -3,  -1,   1,   0,  -2,  -3,  -3,
+  ], [
+    -3,  -4,  -7,  -8,  -7,  -4,  -1,   2,   0,  -1,  -3,  -4,  -4,  -2,   0,   2,
+     1,   0,   0,  -1,  -3,  -2,   0,   2,   2,   1,   1,   0,  -1,  -1,   0,   2,
+     1,   1,   1,   1,   0,   0,   0,   1,   1,   1,   1,   1,   1,   1,   1,   1,
+     0,   0,   1,   2,   3,   3,   2,   2,   0,   0,   1,   3,   4,   4,   3,   2,
+  ], [
+     3,   3,   3,   0,  -1,   0,   1,   2,   1,   1,   1,  -1,  -2,  -1,  -1,   1,
+    -2,  -2,  -1,  -3,  -3,  -2,  -2,   0,  -4,  -4,  -2,  -2,  -2,  -2,  -3,   0,
+    -4,  -4,  -1,   1,   1,   0,  -1,   2,  -3,  -1,   2,   3,   4,   3,   3,   5,
+    -2,   0,   2,   3,   3,   3,   3,   3,  -2,  -2,   0,   0,   0,   0,   0,   1,
+  ], [
+     0,   2,   1,  -1,  -3,  -1,   3,  -2,  -1,   0,  -1,  -1,  -3,   0,   4,  -2,
+    -2,  -2,  -2,  -2,  -2,   1,   5,  -2,  -3,  -2,  -3,  -1,  -2,   1,   4,  -3,
+    -2,   0,  -1,   0,  -1,   0,   3,  -5,   1,   2,   1,   2,   0,   0,   2,  -5,
+     2,   4,   2,   3,   1,   1,   3,  -3,   1,   2,   1,   1,   0,   1,   4,  -2,
+  ], [
+     4,  -3,  -4,  -1,   3,   3,   1,   3,   4,  -4,  -4,  -1,   3,   2,   0,   2,
+     4,  -3,  -4,   0,   2,   2,  -1,   1,   4,  -3,  -2,   1,   2,   1,  -2,   0,
+     2,  -4,  -2,   1,   2,   0,  -3,   0,   2,  -3,  -2,   0,   1,   0,  -2,   2,
+     3,  -1,  -1,   0,   0,   0,   0,   3,   2,  -2,  -2,  -2,  -1,  -1,  -1,   2,
+  ], [
+     2,   2,   3,   4,   3,   1,   0,  -1,   1,   0,   1,   2,   1,  -1,  -2,  -2,
+     2,   1,   2,   1,   1,   0,  -1,  -1,   4,   3,   4,   3,   2,   1,   1,   1,
+     3,   2,   2,   2,   1,   1,   1,   1,  -1,  -2,  -1,   0,  -1,  -1,  -1,  -1,
+    -3,  -3,  -2,  -1,  -2,  -2,  -2,  -2,  -4,  -4,  -3,  -3,  -4,  -4,  -3,  -3,
+  ], [
+     2,   1,  -1,  -3,  -4,  -2,   3,   4,   2,   2,   1,  -1,  -3,  -2,   1,   2,
+     1,   2,   3,   3,   0,  -2,  -1,  -2,  -1,   0,   2,   4,   2,   0,  -1,  -3,
+    -2,  -2,   0,   3,   3,   2,   0,  -3,   0,  -2,  -3,  -1,   1,   2,   2,  -1,
+     3,  -1,  -4,  -5,  -3,   0,   2,   0,   6,   3,  -2,  -6,  -5,   0,   3,   1,
+  ], [
+    -2,   3,  -2,   0,   3,  -2,  -2,   1,  -3,   4,  -3,   0,   3,  -2,  -1,   2,
+    -3,   5,  -3,   0,   4,  -2,  -1,   2,  -2,   4,  -4,  -1,   3,  -3,  -2,   2,
+    -3,   4,  -3,   0,   3,  -3,  -1,   2,  -2,   5,  -2,   0,   3,  -3,  -1,   2,
+    -2,   4,  -3,   1,   3,  -2,  -1,   2,  -2,   3,  -2,   1,   3,  -2,   0,   2,
+  ], [
+     1,   0,   0,  -1,   1,   2,  -4,  -1,   2,   0,   0,  -1,   1,   2,  -4,  -2,
+     1,   1,   1,  -1,   2,   4,  -2,   0,   0,  -1,   1,  -1,   2,   5,  -1,   1,
+     0,  -1,   0,  -2,   1,   5,  -1,   1,   0,  -1,  -1,  -2,   0,   3,  -3,  -1,
+     1,   1,   0,  -2,   0,   3,  -3,  -1,   1,   1,   0,  -3,   0,   3,  -2,   0,
+  ], [
+     1,   0,  -1,   1,   1,   2,   4,   5,   1,   0,  -1,   1,   1,   1,   5,   7,
+     0,   0,  -2,  -1,  -1,   0,   3,   5,   0,  -1,  -2,  -1,  -1,  -1,   2,   3,
+     0,  -1,  -3,  -1,  -1,  -1,   1,   2,  -1,  -2,  -4,  -2,  -2,  -2,   0,   0,
+    -1,  -2,  -2,  -1,  -2,  -2,   0,   0,   0,  -1,  -1,   0,  -1,  -1,   0,   0,
+  ], [
+     3,   3,   0,  -1,  -1,   1,   4,   4,   2,   3,   0,  -2,  -2,   0,   1,   1,
+     2,   3,   1,  -1,  -1,   0,   1,   0,   1,   2,   0,  -1,  -1,  -1,   0,  -2,
+     0,   1,   0,  -1,  -2,  -1,   0,  -2,   0,   1,   0,  -1,  -2,  -1,   1,   0,
+     1,   1,  -1,  -3,  -4,  -3,   1,   3,   1,   2,  -1,  -3,  -5,  -4,   1,   3,
+  ], [
+    -3,  -2,   0,   1,   1,   1,   0,  -2,   0,   1,   1,   1,   0,   0,  -1,  -3,
+     1,   2,   1,   1,   0,  -1,  -1,  -2,   0,  -1,  -3,  -1,  -1,  -1,   0,  -1,
+     0,  -3,  -6,  -3,  -2,  -1,   1,   1,   2,  -1,  -4,  -3,  -2,   0,   2,   2,
+     5,   4,   1,   1,   0,   1,   3,   2,   5,   4,   2,   1,   0,  -1,   0,   1,
+  ], [
+    -2,   0,  -2,  -5,  -6,  -3,   0,   0,  -2,   0,   1,   0,  -1,   1,   2,   2,
+    -2,   0,   1,   3,   2,   2,   2,   1,  -2,   0,   2,   4,   3,   2,   1,   1,
+    -2,   0,   2,   3,   2,   0,  -1,   0,  -3,  -1,   1,   1,   0,  -1,  -1,   1,
+    -4,  -1,   1,   0,  -1,  -2,   0,   2,  -4,  -1,   0,  -1,  -1,  -2,   1,   4,
+  ], [
+    -3,   0,   0,  -1,   1,   1,   1,   0,  -3,   1,   0,  -1,   0,   0,  -1,  -1,
+    -1,   3,   3,   0,   1,   0,   0,   1,  -3,   2,   2,  -2,  -1,   0,   0,   1,
+    -5,   0,   0,  -2,  -1,   1,   0,   2,  -7,  -2,   1,   0,   1,   2,   2,   2,
+    -5,   0,   3,   2,   3,   3,   2,   2,  -3,   2,   4,   1,   0,   0,  -2,  -3,
+  ], [
+     5,   2,  -2,  -2,   0,  -1,  -1,  -1,   2,  -1,  -4,  -3,  -1,  -2,  -1,  -1,
+     0,  -2,  -2,   1,   2,  -1,   0,   1,  -1,  -2,  -1,   3,   3,  -1,   0,   2,
+     1,   0,   0,   3,   3,  -2,  -1,   2,   2,   1,   1,   3,   2,  -2,  -2,   0,
+     1,   0,  -1,   1,   1,  -3,  -3,  -2,   1,   0,   1,   2,   3,   0,   0,   0,
+  ], [
+    -4,  -5,  -3,   0,   1,  -1,  -2,  -1,  -2,  -3,  -1,   1,   2,   0,   0,   0,
+     1,   1,   2,   1,   2,   1,   1,   1,   3,   4,   3,   1,   0,  -2,  -1,  -1,
+     3,   3,   2,   0,  -2,  -3,  -3,  -2,   1,   1,   0,  -1,  -2,  -4,  -2,  -2,
+     2,   1,   0,   0,   0,  -1,   0,   1,   2,   1,   1,   1,   1,   1,   1,   3,
+  ], [
+     0,   0,   0,  -1,  -2,  -1,   1,   0,  -2,  -1,  -1,  -2,  -3,  -2,   0,   0,
+    -1,   0,   0,  -1,  -2,   0,   1,   1,   1,   1,   0,  -1,  -1,   1,   3,   1,
+     2,   2,   0,  -2,  -1,   2,   3,   0,   3,   1,  -1,  -1,   1,   4,   2,  -2,
+     2,   0,  -3,  -1,   3,   5,   0,  -5,   1,  -1,  -2,   0,   3,   3,  -1,  -6,
+  ], [
+    -1,   0,   3,   4,   2,   0,   1,   2,  -2,  -1,   0,   1,  -1,  -2,   0,   1,
+    -2,  -3,  -2,  -3,  -6,  -7,  -6,  -3,   2,   2,   3,   1,  -1,  -2,  -3,  -2,
+     2,   2,   3,   1,   0,   0,   0,   0,   2,   1,   1,   0,   1,   1,   0,   1,
+     1,   0,   0,   0,   0,   1,   1,   2,   1,   0,  -1,   0,   0,   2,   2,   1,
+  ], [
+     1,   1,   3,   1,  -1,  -1,  -1,   1,  -2,  -1,   0,   0,  -2,  -2,  -1,   2,
+    -2,  -2,   1,   1,   1,   0,   1,   3,  -2,  -2,   0,  -1,   0,  -1,   0,   2,
+     0,   0,   1,   0,  -1,  -1,  -2,   1,   3,   2,   2,   1,   0,  -2,  -2,   1,
+     5,   3,   3,   2,   1,   1,   1,   4,   0,  -3,  -4,  -5,  -4,  -3,  -1,   1,
+  ], [
+    -6,  -4,  -1,   2,   2,   0,   0,  -1,  -4,  -2,   1,   3,   3,   2,   2,   0,
+    -3,  -2,  -1,   2,   3,   3,   2,   0,  -3,  -2,  -2,   1,   2,   1,   1,  -1,
+    -2,  -2,  -2,   0,   2,   2,   1,  -1,  -1,  -1,  -1,   1,   2,   3,   2,   0,
+    -1,  -1,  -2,   1,   2,   2,   2,  -1,   0,  -1,  -2,   0,   2,   1,   0,  -1,
+  ], [
+     6,   4,   2,   1,   0,   0,   0,   1,   4,   2,  -1,  -2,  -2,  -2,  -1,  -1,
+     2,   1,  -1,  -2,  -2,  -2,  -2,  -1,   2,   2,   0,  -2,  -2,  -2,  -1,   0,
+     0,   0,  -1,  -2,  -2,  -1,   0,   1,  -3,  -3,  -2,  -1,  -1,  -2,  -1,   0,
+    -3,  -2,   2,   3,   2,   0,  -1,  -2,  -2,   0,   4,   5,   5,   2,   0,  -1,
+  ], [
+     5,   4,   2,   0,  -1,  -2,  -1,  -1,   4,   3,   2,   1,   0,  -1,   0,  -1,
+     1,   1,   0,   1,   1,   0,   1,  -1,  -2,  -1,  -1,   0,   0,  -2,  -2,  -3,
+    -1,   0,   0,   0,  -1,  -3,  -3,  -5,   0,   1,   1,  -1,  -1,  -2,  -2,  -3,
+    -1,  -1,  -1,  -2,  -1,   1,   3,   1,  -1,  -2,  -2,  -1,   2,   5,   6,   5,
+  ], [
+    -3,  -3,  -2,   1,   1,  -2,  -1,  -1,   1,   2,   3,   4,   1,  -3,  -1,  -3,
+     3,   2,   0,   1,  -1,  -3,  -1,  -3,   1,   0,  -1,   0,  -1,  -1,   1,   0,
+     1,   1,   0,   1,   2,   2,   5,   3,   1,   1,   1,   2,   2,   2,   3,   0,
+    -3,  -1,  -2,  -2,  -3,  -3,  -1,  -3,  -1,   1,   1,   0,  -1,  -1,   0,  -2,
+  ], [
+     2,   0,  -2,  -2,   2,   4,   1,  -2,   1,   0,  -2,  -1,   3,   5,   2,  -1,
+    -1,  -2,  -3,  -2,   1,   3,   1,  -2,  -1,  -2,  -1,  -1,   0,   2,   1,  -1,
+     0,   0,   1,   1,   1,   2,   2,   0,   0,   1,   4,   4,   2,   2,   3,   1,
+    -2,  -1,   2,   1,  -2,  -3,  -2,  -3,  -1,   0,   1,   0,  -3,  -4,  -4,  -5,
+  ], [
+     4,   0,  -3,  -4,  -4,  -4,  -2,  -1,   5,   0,  -1,   0,  -1,  -3,  -2,  -1,
+     4,   0,   0,   1,   1,   0,   0,   0,   0,  -3,  -2,  -1,   0,   0,   1,   0,
+     0,  -2,   0,   0,   1,   1,   2,   1,   2,   0,   0,   0,   1,   1,   1,   0,
+     2,   0,  -1,  -1,   1,   1,   1,   0,   1,  -1,  -2,  -2,   0,   2,   2,   2,
+  ], [
+    -3,  -5,  -2,   0,  -1,  -3,  -3,   0,   0,  -2,   0,   2,   2,   0,   0,   3,
+     2,  -1,  -2,   0,   0,  -1,  -1,   2,   5,   2,  -1,  -1,  -1,  -1,  -1,   2,
+     5,   2,   0,  -1,  -1,   0,  -1,   2,   2,   1,   0,   0,   0,   1,   0,   2,
+    -1,  -1,   1,   1,   2,   2,   1,   2,  -3,  -2,   0,   0,   0,   0,  -2,  -1,
+  ], [
+     0,   3,   2,   0,  -2,  -3,  -3,  -3,   0,   3,   3,   1,   0,   0,   1,   2,
+    -1,   0,  -1,  -2,  -1,  -1,   1,   3,  -1,   0,  -1,  -2,  -1,  -1,   0,   2,
+    -1,   0,  -1,  -2,   0,   0,  -1,   2,  -1,   0,  -1,  -2,  -1,  -1,  -2,   1,
+     0,   1,   0,  -3,  -1,  -1,  -1,   2,   5,   5,   2,  -1,  -1,  -1,   1,   3,
+  ], [
+     0,   0,   1,  -1,  -3,  -2,   0,   2,   1,   1,   3,   0,  -2,  -2,   0,   1,
+     1,   1,   3,   1,   0,   0,  -1,  -1,   0,  -1,   2,   1,   1,   0,  -1,  -3,
+    -1,  -2,   1,   1,   1,   0,  -2,  -4,  -1,   0,   2,   1,   1,   0,  -1,  -3,
+     1,   1,   3,   2,   1,   0,  -2,  -3,   2,   2,   4,   2,   1,  -1,  -2,  -4,
+  ], [
+     1,   2,   2,   2,   0,  -2,   0,   2,  -1,  -1,  -2,  -3,  -4,  -5,  -3,   1,
+     0,   1,   1,   0,  -1,  -1,  -1,   1,   0,   1,   1,   1,   0,   0,   0,   2,
+     0,   1,   1,   2,   1,   1,   1,   2,  -1,  -1,   0,   2,   2,   2,   2,   3,
+    -2,  -4,  -4,  -1,  -2,  -2,  -2,   0,   1,   0,   0,   1,   0,   0,   0,   1,
+  ], [
+     0,  -1,  -3,  -2,   0,   2,   2,   1,   0,  -1,  -2,  -3,   0,   1,   1,   2,
+     1,   0,  -2,  -3,  -1,   0,   0,   1,  -1,   0,  -1,  -2,   0,   0,  -1,   0,
+    -1,   1,   1,   0,   2,   2,   0,   0,   0,   2,   3,   1,   3,   5,   3,   2,
+    -1,   1,   1,  -2,   0,   3,   1,   1,  -1,   0,   0,  -4,  -4,  -1,  -1,  -1,
+  ], [
+    -1,   1,   1,   0,   1,   2,   1,   2,  -3,   0,   1,   0,   1,   1,   0,   2,
+    -5,  -3,  -1,  -1,   0,   1,   0,   1,  -4,  -3,  -2,  -3,  -2,  -1,  -1,   0,
+     0,   0,  -1,  -2,  -2,  -2,  -2,   0,   3,   4,   2,   0,   0,   0,   0,   1,
+     2,   1,   0,   0,   0,   0,  -1,   0,   0,   1,   2,   3,   4,   4,   3,   2,
+  ], [
+    -1,   4,   7,   4,   0,   0,   0,   0,  -1,   4,   6,   3,   0,   1,   1,   1,
+     0,   3,   4,   0,  -1,   0,   0,   1,   0,   1,   1,  -2,  -1,   0,  -1,  -1,
+    -1,   0,  -1,  -1,  -1,   0,   0,   0,  -1,  -1,  -1,   0,   0,   0,   0,   0,
+    -1,  -3,  -3,   0,   1,  -1,  -2,  -1,  -3,  -4,  -4,  -2,  -1,  -2,  -2,  -1,
+  ], [
+     2,   2,   1,   0,   1,   1,   0,  -3,  -2,  -1,   0,   0,   1,   1,   0,  -3,
+    -2,  -1,   0,   1,   2,   1,   1,  -2,   1,   2,   2,   2,   3,   3,   2,  -1,
+     1,   2,   1,   0,   1,   1,   2,  -1,   0,   1,  -2,  -4,  -2,   0,   1,  -1,
+     1,   1,  -1,  -3,  -2,   0,  -1,  -3,   1,   2,   0,  -1,   0,   1,  -1,  -4,
+  ], [
+    -1,  -1,  -2,  -2,   0,   3,   4,   3,   1,   1,  -1,  -3,  -2,   0,   0,   0,
+     2,   2,   2,   2,   2,   1,  -1,  -1,   1,   1,   1,   3,   3,   0,  -2,  -2,
+     0,  -1,  -1,  -1,   0,  -2,  -1,  -1,  -1,  -3,  -4,  -3,  -2,  -2,   0,   2,
+    -1,  -1,   0,   1,   2,   2,   3,   5,  -2,  -1,  -1,   0,   0,   0,   0,   1,
+  ], [
+    -2,  -3,   2,   0,   0,   1,   1,  -1,  -1,  -4,   1,  -2,  -1,   2,   2,   0,
+     1,  -4,   0,  -2,  -2,   1,   1,  -1,   2,  -3,   1,  -1,  -1,   1,   1,  -1,
+     3,  -2,   3,   1,   0,   1,   1,  -1,   1,  -3,   2,   1,   0,   1,   0,  -1,
+    -1,  -5,   1,   0,  -1,   0,   1,   1,   0,  -3,   3,   3,   1,   2,   3,   3,
+  ], [
+     0,  -1,  -2,   1,   5,   5,   2,  -1,   1,  -1,  -2,  -1,   1,   1,  -2,  -5,
+     1,   1,  -1,  -2,  -1,  -1,  -1,  -3,   1,   1,  -1,  -1,  -1,   2,   4,   3,
+    -1,  -1,  -1,  -1,  -1,   0,   4,   3,  -1,  -1,   0,   1,  -1,  -3,  -1,  -1,
+     0,   0,   0,   2,   2,   0,   0,  -1,   0,  -2,  -3,   0,   1,   1,   3,   2,
+  ], [
+     2,   3,   2,   1,   0,   0,  -2,  -2,   2,   3,   0,   1,   1,   3,   3,   2,
+     0,   0,  -3,  -1,  -1,   2,   2,   3,  -2,  -2,  -3,   1,   1,   2,   1,   1,
+    -2,  -1,  -2,   2,   1,   1,  -1,  -2,   0,   1,   0,   2,   0,   0,  -2,  -2,
+     0,   1,   0,   2,   0,   0,  -2,  -2,  -3,  -2,  -2,   0,  -1,  -2,  -2,  -3,
+  ], [
+     0,   1,  -1,   3,  -1,   1,   3,  -1,   0,   1,  -1,   3,  -1,  -1,   2,  -3,
+     1,   1,  -2,   3,  -1,  -3,   0,  -3,   2,   2,  -2,   3,   0,  -2,   1,  -2,
+     1,   1,  -3,   3,  -1,  -2,   1,  -3,   1,   1,  -3,   3,   0,  -1,   1,  -2,
+     1,   2,  -1,   4,   0,  -1,   1,  -2,   0,   1,  -1,   3,  -1,  -3,   0,  -3,
+  ], [
+    -3,  -3,  -1,   1,   2,   1,  -1,  -2,  -2,  -2,   0,   2,   1,   0,  -2,  -2,
+    -3,  -2,   1,   2,   1,  -1,  -2,  -1,  -3,  -2,   2,   4,   0,  -2,  -2,   1,
+    -3,  -1,   2,   4,   0,  -2,  -2,   2,  -1,   1,   4,   3,  -1,  -3,  -2,   2,
+     0,   2,   4,   2,  -1,  -2,  -1,   2,   0,   1,   2,   0,  -1,   0,   1,   3,
+  ], [
+     3,   0,  -5,   1,   4,   0,   0,   1,   1,  -2,  -5,   2,   5,  -1,  -2,   1,
+    -1,   0,   0,   3,   3,   1,   0,  -1,  -2,   3,   4,  -2,  -3,  -1,   0,  -2,
+    -3,   3,   5,  -3,  -3,   0,   0,  -2,  -1,   3,   2,  -2,  -2,   2,   2,  -1,
+     2,   0,   0,  -1,   0,   0,   0,   0,   0,  -3,  -2,   1,   3,   0,  -2,  -2,
+  ]
+];
+
+pub const SVQ_INTER_CB_8X4: [[i8; 32]; 96] = [
+  [
+     9,   8,   4,   0,  -3,  -4,  -4,  -3,   9,   8,   4,  -1,  -4,  -5,  -5,  -3,
+     8,   7,   3,  -2,  -5,  -5,  -5,  -4,   6,   4,   1,  -2,  -4,  -5,  -4,  -3,
+  ], [
+   -12, -14, -11,  -4,   1,   5,   6,   6,  -8, -10,  -7,  -5,  -2,   1,   1,   1,
+     5,   4,   3,   1,   0,   0,  -1,  -1,  13,  13,   9,   6,   3,   0,  -1,  -2,
+  ], [
+    -4,  -4,  -3,  -1,   1,   4,   8,  11,  -5,  -6,  -4,  -2,   0,   3,   8,  12,
+    -7,  -7,  -6,  -4,  -2,   2,   7,  10,  -7,  -7,  -5,  -4,  -2,   1,   5,   8,
+  ], [
+    -3,  -2,  -1,   1,   3,   6,   7,   6,   2,   3,   5,   7,   8,   8,   6,   4,
+     4,   5,   4,   3,   1,  -2,  -6,  -7,   1,   0,  -2,  -7, -10, -14, -17, -16,
+  ], [
+    -5,  -4,   1,   8,   9,   3,  -3,  -7,  -7,  -6,   1,  11,  12,   5,  -3,  -8,
+    -8,  -7,   0,   9,  11,   5,  -3,  -7,  -8,  -6,  -1,   5,   8,   4,  -2,  -6,
+  ], [
+    -4,  -5,  -7,  -8,  -9,  -9,  -8,  -6,  -4,  -5,  -6,  -7,  -7,  -6,  -4,  -2,
+     0,   1,   2,   3,   5,   8,  10,   9,   1,   2,   3,   6,   9,  12,  14,  13,
+  ], [
+     5,   6,   6,   5,   4,   3,   2,   1,   5,   6,   7,   7,   6,   6,   6,   4,
+    -1,   0,   1,   1,   3,   5,   5,   5, -13, -16, -17, -17, -14, -10,  -6,  -4,
+  ], [
+     9,  11,  13,  16,  15,  13,  12,  10,  -4,  -5,  -6,  -7,  -7,  -7,  -6,  -5,
+    -6,  -6,  -7,  -7,  -7,  -7,  -6,  -5,  -2,  -1,   0,   0,   0,   0,   0,  -1,
+  ], [
+   -11, -13, -15, -16, -16, -14, -12, -10,   2,   3,   4,   5,   4,   3,   3,   3,
+     6,   7,   8,   8,   8,   7,   6,   5,   3,   4,   3,   3,   3,   3,   3,   3,
+  ], [
+     3,   4,   4,   1,  -2,  -7, -13, -17,   5,   7,   7,   5,   1,  -5, -13, -19,
+     6,   8,   9,   8,   5,  -1,  -9, -16,   6,   8,  10,  10,   7,   2,  -4, -11,
+  ], [
+    18,   9,  -1, -10, -13,  -9,  -4,   0,  22,  12,  -1, -12, -15, -10,  -4,   2,
+    23,  13,   0, -10, -13,  -9,  -3,   2,  20,  12,   2,  -6,  -9,  -6,  -2,   2,
+  ], [
+    -6,  -6,  -6,  -7,  -7,  -7,  -7,  -6,  -6,  -7,  -8,  -8,  -9,  -9,  -9,  -8,
+    -3,  -3,  -3,  -3,  -3,  -3,  -3,  -3,  12,  15,  18,  21,  21,  19,  17,  14,
+  ], [
+    14,  16,  18,  18,  18,  16,  15,  13,   5,   6,   6,   5,   5,   4,   4,   3,
+    -6,  -7,  -9, -10, -10, -10,  -9,  -7, -10, -11, -13, -14, -14, -13, -12, -10,
+  ], [
+   -27, -17,  -4,   5,   9,  10,  10,   7, -32, -19,  -3,   7,  11,  12,  11,   8,
+   -30, -16,  -2,   8,  12,  12,  10,   7, -23, -12,   0,   7,  10,  11,   9,   6,
+  ], [
+    16,  17,  16,  12,   6,  -1,  -8, -12,  17,  18,  15,  10,   1,  -8, -15, -18,
+    15,  14,  10,   4,  -5, -14, -20, -23,  10,   8,   4,  -1,  -9, -16, -21, -22,
+  ], [
+   -10, -12, -12, -11,  -5,   4,  14,  20, -11, -13, -15, -12,  -4,   7,  19,  27,
+   -11, -13, -14, -11,  -3,   8,  21,  28, -10, -11, -12,  -9,  -2,   8,  18,  25,
+  ], [
+    -1,  -1,  -1,   1,   4,   6,   6,   5,   0,   0,   0,   2,   4,   3,   1,  -2,
+     0,   0,   2,   4,   4,  -1,  -7, -10,   0,   0,   3,   5,   3,  -3, -11, -15,
+  ], [
+   -14, -13,  -8,  -1,   3,   3,  -1,  -4,  -5,  -4,  -1,   4,   8,   8,   3,   0,
+     3,   2,   2,   3,   4,   5,   3,   1,   5,   3,   0,  -2,  -2,  -1,  -1,  -1,
+  ], [
+     9,   1,  -6,  -6,  -5,  -3,  -2,  -1,  12,   1,  -6,  -6,  -4,  -2,  -1,   0,
+    14,   4,  -4,  -4,  -2,  -2,  -1,  -1,  14,   6,  -1,  -1,  -1,  -1,  -1,  -1,
+  ], [
+     4,   6,   8,  10,  11,   9,   7,   5,  -1,  -1,  -1,   0,   0,  -1,  -1,  -2,
+    -2,  -4,  -4,  -5,  -5,  -5,  -5,  -4,  -2,  -3,  -3,  -4,  -4,  -3,  -2,  -1,
+  ], [
+     2,   3,   4,   4,   3,   1,   0,   0,  -1,   1,   4,   5,   6,   5,   4,   3,
+    -8,  -6,  -2,   2,   3,   4,   4,   3, -14, -13,  -9,  -5,  -2,  -1,   0,   0,
+  ], [
+    -3,  -4,  -5,  -4,   0,   7,  12,  13,  -3,  -4,  -5,  -5,  -2,   4,   9,  10,
+    -2,  -3,  -4,  -5,  -4,  -1,   3,   4,  -1,  -1,  -2,  -3,  -3,  -2,   0,   1,
+  ], [
+     9,   5,  -2,  -8, -11, -10,  -7,  -4,  12,  10,   6,   2,   0,  -1,   0,   0,
+     2,   2,   3,   4,   3,   1,   1,   1,  -9,  -8,  -4,   0,   1,   2,   1,   0,
+  ], [
+     6,   8,   8,   5,   1,  -5, -11, -13,   0,   1,   2,   2,  -1,  -4,  -8, -11,
+    -3,  -2,   1,   3,   3,   1,  -1,  -4,  -2,  -1,   2,   5,   6,   6,   4,   1,
+  ], [
+     3,   4,   5,   5,   4,   1,  -3,  -6,   5,   6,   4,   2,   2,   2,   0,  -3,
+     6,   5,   0,  -5,  -5,  -2,  -1,  -2,   7,   4,  -3, -11, -12,  -7,  -3,  -2,
+  ], [
+     1,   0,  -1,  -1,  -1,   0,   0,   0,   2,   3,   4,   4,   5,   5,   4,   3,
+    -7,  -9,  -9, -10, -10,  -9,  -7,  -6,   3,   4,   5,   6,   5,   5,   5,   5,
+  ], [
+    -7,  -7,  -7,  -7,  -6,  -6,  -5,  -4,  -5,  -4,  -3,  -1,  -1,  -1,   0,   0,
+    -3,  -2,   1,   4,   5,   5,   5,   5,  -2,  -1,   3,   6,   9,  10,  10,   9,
+  ], [
+   -14,   1,  10,   3,  -2,   0,   1,   1, -16,   2,  13,   3,  -3,  -1,   1,   0,
+   -15,   2,  12,   3,  -4,  -2,   1,   1, -10,   3,  10,   2,  -3,  -1,   1,   1,
+  ], [
+     0,   1,   4,   2,  -5, -10,  -3,  11,  -1,   1,   4,   2,  -6, -13,  -2,  15,
+    -1,   0,   3,   1,  -6, -12,  -1,  15,  -1,   1,   2,   1,  -4,  -8,   0,  11,
+  ], [
+    10,   5,  -2,  -2,   2,   5,   1,  -4,   7,   0,  -8,  -6,   1,   5,   2,  -4,
+     2,  -5, -12,  -7,   2,   7,   4,  -1,  -1,  -7, -10,  -4,   4,   9,   7,   2,
+  ], [
+    -5,  -5,  -4,  -6,  -6,  -5,  -5,  -3,  -1,  -2,  -2,  -4,  -5,  -6,  -5,  -4,
+     6,   7,   7,   4,   0,  -2,  -3,  -3,  13,  14,  13,  10,   5,   1,  -1,  -2,
+  ], [
+     1,   1,   2,   2,   2,   2,   2,   2,  -5,  -6,  -8,  -9,  -9,  -8,  -7,  -6,
+     7,   9,  10,  11,  11,   9,   7,   5,  -1,  -2,  -3,  -3,  -4,  -4,  -4,  -3,
+  ], [
+    -1,  -1,   0,   0,   0,   0,  -1,  -1,  -3,  -3,  -4,  -5,  -4,  -3,  -3,  -2,
+     2,   1,  -1,  -3,  -3,  -2,  -1,   0,  12,  12,   8,   3,   1,   0,   0,   1,
+  ], [
+    -6,  -8,  -8,  -6,  -2,   2,   6,   8,   1,   1,  -1,  -2,   0,   3,   5,   7,
+     3,   3,   1,  -1,  -1,   0,   0,   2,   0,   1,   0,  -1,  -1,  -1,  -2,  -1,
+  ], [
+     1,   0,   0,   0,   0,   0,   2,   4,   2,   1,   3,   4,   3,   1,   0,   2,
+     2,   1,   0,   0,  -1,  -1,   0,   3,   5,   1,  -6, -12, -13,  -8,  -1,   4,
+  ], [
+    -2,   0,  -1,  -2,  -1,   0,   2,   3,  -6,  -3,  -2,   0,   1,   1,   1,   1,
+    -9,  -5,   0,   4,   5,   3,   1,   0,  -8,  -3,   3,   7,   8,   4,   1,   0,
+  ], [
+     1,   2,   2,   3,   3,   1,  -1,  -3,   4,   5,   5,   6,   6,   5,   2,   0,
+     0,   0,   0,   0,   1,   0,  -2,  -4,  -3,  -3,  -4,  -3,  -3,  -4,  -7,  -8,
+  ], [
+    14,  12,   6,  -1,  -3,  -3,   0,   0,   7,   5,   1,  -3,  -5,  -4,  -2,  -1,
+    -2,  -2,  -2,  -2,  -2,  -2,  -1,  -1,  -6,  -4,  -1,   1,   1,   1,   0,  -1,
+  ], [
+     2,   2,   1,  -3,  -6,  -7,  -6,  -3,   1,   0,  -1,  -3,  -2,   1,   4,   6,
+     0,   0,   1,   2,   4,   7,   8,   7,   0,   0,   0,   0,  -1,  -4,  -7,  -8,
+  ], [
+     0,   2,   1,  -2,  -3,  -3,  -2,  -1,  -1,   1,   0,  -3,  -5,  -2,   0,   2,
+    -2,  -1,  -2,  -5,  -4,   1,   6,   9,  -3,  -2,  -3,  -4,  -2,   5,  11,  13,
+  ], [
+    -4,  -2,   2,   6,   4,  -3, -10, -14,  -2,  -1,   1,   4,   4,   1,  -1,  -2,
+     0,   0,  -1,  -2,  -2,   0,   4,   6,   2,   2,   0,  -3,  -3,   0,   5,   9,
+  ], [
+    -4,  -4,  -2,   1,   6,   9,   3,  -7,  -2,  -2,  -2,  -1,   4,   8,   0, -11,
+     1,   1,   0,   0,   2,   6,  -1, -10,   2,   2,   1,   0,   2,   4,   0,  -7,
+  ], [
+    -1,  -2,  -3,  -6,  -7,  -8,  -8,  -8,   2,   3,   3,   1,  -1,  -2,  -3,  -4,
+     5,   5,   5,   4,   3,   2,   0,  -1,   3,   3,   3,   3,   2,   2,   1,   1,
+  ], [
+     3,   3,   2,  -2,  -3,   0,   7,  10,   1,   2,   2,  -2,  -5,  -4,   0,   3,
+     0,   3,   4,   2,  -3,  -5,  -6,  -4,   0,   2,   4,   4,   1,  -4,  -7,  -7,
+  ], [
+     2,   4,   5,   5,   5,   5,   6,   6,  -4,  -4,  -3,  -5,  -5,  -3,  -3,  -2,
+    -3,  -4,  -4,  -5,  -4,  -2,  -2,  -2,   1,   1,   0,   0,   2,   4,   5,   4,
+  ], [
+    -2,   0,   3,   4,   4,   3,   2,   2,  -9,  -7,  -4,   0,   3,   6,   6,   6,
+    -5,  -5,  -3,  -2,   0,   1,   3,   4,   5,   5,   2,  -2,  -4,  -6,  -5,  -3,
+  ], [
+     1,  -6,  -4,   7,   5,  -2,  -2,   1,   5,  -5,  -4,   6,   4,  -5,  -4,   1,
+     5,  -5,  -4,   6,   4,  -5,  -3,   1,   1,  -7,  -3,   8,   7,  -1,  -3,   1,
+  ], [
+    -8,  -7,  -4,   0,   2,   4,   5,   5,   5,   6,   5,   2,  -1,  -5,  -7,  -7,
+     5,   6,   4,   1,  -3,  -5,  -6,  -5,  -7,  -7,  -5,  -2,   1,   6,   9,  10,
+  ], [
+     6,   3,   0,   1,   3,   0,  -8, -14,   3,   0,  -1,   1,   4,   3,   0,  -4,
+     1,   0,   0,   1,   2,   1,   1,   1,  -1,  -1,   1,   2,   1,  -1,  -1,   0,
+  ], [
+     1,   1,   1,   1,   0,  -2,  -3,   0,   1,   2,   1,   0,  -2,  -8,  -9,  -4,
+     1,   3,   3,   2,   1,  -3,  -3,   1,   0,   1,   1,   1,   1,   1,   4,   8,
+  ], [
+     2,   5,   9,   7,   2,  -1,  -1,   1,  -4,  -1,   1,   0,  -3,  -4,  -1,   2,
+    -3,   0,   3,   3,   0,  -1,   0,   2,  -4,  -1,   1,   1,  -2,  -4,  -5,  -4,
+  ], [
+     1,  -1,  -2,  -2,  -1,   2,   4,   5,   2,   1,   1,   0,  -1,  -1,   0,   0,
+     2,   3,   4,   5,   4,   2,   1,   0,  -9,  -9,  -6,  -3,  -1,  -1,  -1,  -1,
+  ], [
+    -6,  -6,   4,   7,   0,  -2,  -1,  -2,  -1,  -2,   5,   6,  -1,  -2,   0,  -1,
+     4,  -1,   1,   0,  -4,  -2,   0,  -2,   7,   1,  -1,  -2,  -3,   1,   3,   1,
+  ], [
+     4,   2,   1,   3,   3,   1,   1,   2,   2,  -2,  -4,   0,   3,   1,   0,   0,
+     1,  -4,  -8,  -4,   1,   2,   1,   0,   2,  -3,  -9,  -6,   0,   3,   3,   2,
+  ], [
+    -1,  -1,   0,  -1,  -1,   0,   1,   2,   3,   1,  -4,  -8,  -7,  -3,   1,   2,
+     2,  -1,  -3,  -2,  -1,   0,   1,   0,  -1,   0,   5,  11,   9,   3,  -1,  -3,
+  ], [
+    -1,  -2,  -2,  -1,   1,   1,   1,   1,   0,  -1,   0,   3,   6,   6,   5,   5,
+     2,   1,  -1,  -1,  -2,  -5,  -6,  -4,   2,   2,   2,   1,  -1,  -4,  -5,  -5,
+  ], [
+    -1,  -3,  -6,  -7,  -6,  -4,  -1,   1,   5,   5,   3,   4,   4,   3,   4,   5,
+    -1,  -2,  -3,  -2,  -2,  -2,   0,   1,   0,   0,   0,   0,   0,   1,   2,   3,
+  ], [
+    -6,  -6,  -4,  -1,   2,   2,   2,   2,  -6,  -7,  -5,  -2,   0,  -1,  -1,   0,
+     2,   2,   2,   4,   4,   3,   3,   4,   2,   1,   0,  -1,   0,   0,   2,   4,
+  ], [
+    12,   5,  -5,  -8,  -5,   0,   2,   2,   2,  -3,  -6,  -3,   0,   0,  -1,  -2,
+    -2,  -3,  -1,   3,   4,   1,  -2,  -3,   2,   2,   3,   4,   3,   1,  -1,  -1,
+  ], [
+     3,   2,   1,   0,   1,   4,   3,   0,   4,   3,   0,  -5,  -6,   0,   3,   3,
+     2,   3,   1,  -7, -12,  -6,   1,   3,   1,   3,   4,  -1,  -6,  -4,   0,   1,
+  ], [
+    -9,  -4,   2,   6,   7,   4,   1,   0,  -7,  -1,   4,   6,   4,   0,  -3,  -3,
+    -6,   0,   4,   4,   1,  -2,  -3,  -2,  -4,   1,   3,   2,   0,  -2,  -1,   0,
+  ], [
+     0,   5,   2,  -5,  -3,   3,   1,  -4,  -2,   4,   2,  -6,  -3,   6,   4,  -3,
+    -1,   5,   3,  -5,  -1,   7,   3,  -4,  -1,   2,   0,  -6,  -3,   5,   3,  -3,
+  ], [
+    -8,  -3,   3,   5,   3,   1,  -2,  -2,   2,   4,   4,  -2,  -4,  -3,   1,   3,
+     2,   1,  -3,  -5,  -3,   3,   4,   3,  -5,  -6,  -5,   3,  10,   8,  -1,  -5,
+  ], [
+     0,   3,   2,  -4,  -9,  -7,   0,   6,  -5,  -1,   5,   7,   4,  -1,  -3,  -3,
+    -5,  -5,  -2,   3,   6,   5,  -1,  -4,   9,   6,   0,  -4,  -2,   1,   1,  -1,
+  ], [
+    -1,  -1,  -1,   1,   1,   0,  -1,   0,  -1,   0,   0,   0,   0,  -1,  -1,   0,
+     2,   1,  -2,  -1,   1,   1,   0,   0,  12,   8,   2,  -1,  -1,  -4,  -7,  -7,
+  ], [
+     2,   1,   3,   6,   7,   4,   2,   0,   1,   0,  -1,   0,  -1,  -4,  -7,  -8,
+     0,   0,  -1,   0,   0,   0,  -1,  -3,   0,   0,   0,   0,   1,   1,   0,  -2,
+  ], [
+    -1,   0,   1,   1,   0,   0,  -1,  -2,   0,   0,  -1,  -3,  -4,  -3,  -1,   1,
+    -1,   0,   0,   0,   1,   4,  10,  12,  -1,   0,  -2,  -2,  -3,  -3,  -1,   1,
+  ], [
+    -3,  -1,  -2,  -4,   2,   9,   9,   7,  -3,   0,  -1,  -3,   0,   2,  -1,   1,
+    -1,   1,  -2,  -3,   0,  -1,  -3,   0,   0,   0,  -3,  -2,   0,  -1,  -1,   1,
+  ], [
+    -1,  -2,  -1,  -1,  -2,  -1,  -1,  -2,   2,  -1,  -2,  -1,   0,   1,   0,  -2,
+     3,  -1,  -2,   2,   5,   3,  -1,  -3,   1,  -5,  -5,   1,   6,   6,   2,   0,
+  ], [
+     1,   2,   0,  -1,   0,   1,   0,  -2,  -5,  -3,  -1,   0,   1,   2,   1,  -2,
+    -7,  -5,  -2,  -2,  -2,  -2,   0,   1,  -1,   0,   1,   1,   0,   3,   9,  12,
+  ], [
+     0,   6,   5,   1,  -2,  -3,   0,   3,   0,   6,   5,   1,   1,   1,   2,   3,
+    -5,  -2,  -2,  -3,   0,   0,   0,   0,  -6,  -3,  -3,  -2,   0,   0,  -1,  -2,
+  ], [
+     4,   4,   2,   1,   0,  -1,  -1,   0,  -2,  -2,   0,   1,   2,   1,   1,   0,
+     2,   2,   1,  -1,  -3,  -5,  -9, -10,   2,   1,  -1,  -1,   1,   4,   4,   1,
+  ], [
+     4,   0,  -2,  -2,  -2,  -2,  -1,   0,   7,   1,  -4,  -3,  -2,   0,   1,   1,
+    10,   5,  -1,  -2,   0,   1,   1,   0,   5,   1,  -3,  -4,  -3,  -1,  -1,  -2,
+  ], [
+     2,   1,  -1,  -3,  -3,   1,   1,  -1,  -2,  -1,   3,   0,  -1,   1,   1,   0,
+    -3,   1,   7,   2,  -3,  -2,  -1,   0,  -2,   4,   8,  -1,  -8,  -5,   0,   2,
+  ], [
+    -4,  -1,   1,   2,   1,  -3,  -4,  -2,  -5,  -3,  -2,   1,   4,   4,   4,   6,
+    -3,  -2,  -4,  -3,   0,   1,   1,   2,   2,   2,   2,   1,   2,   1,  -1,  -1,
+  ], [
+    -4,  -1,   0,  -1,  -3,  -3,  -1,  -1,   1,   4,   4,   2,   0,  -1,  -2,  -3,
+     4,   6,   5,   3,   2,   1,  -2,  -4,   0,   1,   1,   1,   1,  -1,  -4,  -6,
+  ], [
+     1,   2,   2,  -1,  -6,  -5,  -1,   2,  -3,  -2,   1,   1,  -4,  -3,   2,   5,
+    -2,  -1,   2,   2,  -3,  -4,   0,   3,  -2,  -2,   2,   6,   5,   2,   1,   2,
+  ], [
+     2,  -3,  -3,   0,   0,   2,   3,   1,   3,  -1,   1,   3,   1,   2,  -1,  -5,
+    -5,  -7,  -4,  -2,   1,   8,   8,   1,  -1,   0,   2,   0,  -3,   0,   1,  -3,
+  ], [
+    -2,  -5,  -5,  -2,  -3,  -1,   0,  -2,  -1,  -4,   0,   4,   0,   2,   4,   0,
+     0,   0,   8,  10,   2,   1,   3,  -1,  -4,  -3,   2,   3,  -3,  -3,   1,  -1,
+  ], [
+     1,  -2,  -4,   2,   7,   3,  -2,  -1,   6,   4,  -2,  -1,   2,   0,  -1,   3,
+     1,   1,  -2,  -2,  -2,  -5,  -3,   4,  -6,  -2,   1,   1,  -1,  -4,  -2,   4,
+  ], [
+    -2,  -1,  -2,  -2,   0,   1,   0,  -2,  -1,   1,   0,  -1,   0,   0,  -1,  -3,
+     0,   1,  -2,  -4,  -3,  -1,   0,   0,   6,   8,   5,   0,   0,   1,   2,   3,
+  ], [
+    -2,  -2,   2,   5,   2,   0,   0,   1,   2,  -2,  -2,  -1,  -1,   1,   2,   4,
+     2,  -1,   0,   1,   0,   0,   0,   1,  -8,  -7,  -1,   1,  -1,  -1,   1,   3,
+  ], [
+     0,   3,   6,   2,  -2,   1,   2,   0, -10,  -7,  -1,   0,  -3,  -1,   2,   1,
+     0,   0,   2,   2,   1,   1,   1,  -1,   3,   0,  -2,  -2,   0,   2,   1,   0,
+  ], [
+     8,   1,   0,   0,  -2,  -3,  -1,   0,   2,  -2,   2,   5,   1,  -2,  -1,   1,
+    -3,  -6,  -3,  -1,  -3,  -3,  -1,   2,   2,   0,   1,   2,   2,   1,   0,   0,
+  ], [
+     1,  -1,  -1,  -2,  -1,   0,   1,   0,  15,   9,   2,  -1,  -2,  -3,  -3,  -3,
+     0,  -3,  -2,   0,   0,  -1,  -1,  -1,   1,   0,   1,   0,   0,  -1,  -1,  -1,
+  ], [
+     0,   2,   2,  -2,  -3,  -3,  -7,  -8,   0,   2,   2,   0,   1,   2,   1,   1,
+     1,   2,   2,   2,   3,   1,   0,   3,   1,   0,  -1,  -2,  -1,  -2,   0,   5,
+  ], [
+   -11,  -6,  -1,   1,   2,   3,   1,  -3,   1,   4,   3,  -1,  -2,   1,   2,  -1,
+     2,   2,   1,  -1,  -2,   0,   1,  -1,   0,   0,  -1,  -1,   0,   2,   3,   2,
+  ], [
+     1,   1,   2,   1,  -1,   1,   0,  -4,   0,   0,   0,  -2,  -2,   2,   4,  -2,
+    -2,  -3,   0,   0,  -1,   2,   1,  -6,   0,   2,   5,   5,   3,   2,  -1,  -7,
+  ], [
+     4,   2,   0,   0,   3,   3,   1,  -1,   0,  -1,  -1,   3,   6,   4,   1,  -1,
+    -2,  -2,   0,   2,   2,   0,  -2,  -2,  -1,   0,  -1,  -5,  -7,  -5,  -1,   1,
+  ], [
+     5,  -1,  -2,   0,   2,   4,   2,  -5,   0,  -5,  -2,   2,   1,   2,   0,  -6,
+     6,   1,   0,   1,  -2,  -1,   4,   2,   2,  -3,  -3,   0,  -1,  -2,   0,   0,
+  ], [
+     1,  -1,   0,   2,   0,   0,   6,  11,   2,  -1,  -1,   0,  -3,  -2,   3,   5,
+     0,  -2,  -1,   0,  -1,   0,   0,  -3,   1,  -1,  -1,  -1,  -2,  -1,  -3,  -7,
+  ], [
+     1,   1,  -2,  -2,   1,   3,   1,  -2,  -1,   2,   0,  -1,  -1,   1,   0,   0,
+    -4,   2,   3,  -1,  -2,  -2,   0,   1, -11,  -2,   4,   5,   6,   2,  -1,  -2,
+  ], [
+    -6,  -2,   1,  -1,  -3,  -4,   1,   9,  -3,   0,   3,   3,   2,  -3,  -3,   3,
+     1,   1,   0,   0,   1,  -1,  -2,   3,   2,   0,  -3,  -3,   0,  -1,  -1,   3,
+  ], [
+     1,  -1,  -3,   1,   2,  -6,  -4,   6,   0,  -2,  -5,  -2,   0,  -3,  -2,   3,
+     2,   2,   1,  -2,  -2,   1,   2,  -1,  -1,   1,   1,  -2,  -1,   6,   7,  -1,
+  ], [
+     1,   0,  -4,  -2,   1,  -2,  -3,   1,  -4,   0,  -3,  -2,   2,   0,  -3,   0,
+    -3,   4,   3,   1,   8,   7,   0,  -1,  -3,   4,   1,  -4,   2,   3,  -2,  -3,
+  ], [
+    -3,   6,   1,  -4,   1,   1,  -1,  -1,  -2,   4,  -3,  -3,   3,   0,  -1,  -1,
+     1,   2,  -4,   2,   4,  -3,  -1,   2,   3,  -1,  -4,   5,   4,  -6,  -3,   2,
+  ]
+];
+
+pub const SVQ_INTER_CB_4X4: [[i8; 16]; 96] = [
+  [
+     4,   0,  -6,  -7,  -4,  -8, -13,  -9,  -8,  -8,  -1,   6,  -2,   5,  22,  27,
+  ], [
+   -16,  -7,  11,  10, -18,  -7,  13,  10, -15,  -4,  12,   8,  -9,  -1,   9,   5,
+  ], [
+    -2,   2,  15, -16,  -3,   2,  19, -19,  -3,   2,  19, -19,  -2,   3,  15, -14,
+  ], [
+    17,  22,  22,  16,  -6,  -7,  -5,  -2, -12, -16, -16, -12,   1,   1,  -1,  -3,
+  ], [
+    11, -17,   0,   8,  14, -21,  -1,   9,  14, -21,  -2,   8,  11, -16,  -2,   6,
+  ], [
+     7,  -2, -16,  11,   9,  -2, -21,  14,  10,  -1, -22,  14,   8,  -1, -18,  10,
+  ], [
+   -10,  16,   3,  -9, -13,  20,   4, -11, -14,  21,   4, -10, -11,  16,   3,  -8,
+  ], [
+    11,   4,  -9,  -9,  15,   6, -12, -14,  17,   8, -12, -14,  16,  10,  -7, -11,
+  ], [
+     4,  10,  14,  13,  -1,   7,  15,  16, -12,  -7,   3,   8, -20, -23, -18, -10,
+  ], [
+   -10, -18, -26, -25,   4,   1,  -6, -11,  13,  15,  11,   3,  12,  15,  13,   8,
+  ], [
+   -16, -19, -16, -11,   7,  12,  15,  11,  11,  16,  16,  11,  -6,  -9, -11, -10,
+  ], [
+    18,  19,  12,   5,  18,  16,   5,  -4,   6,   0, -10, -15,  -9, -17, -23, -22,
+  ], [
+   -10, -14,  -1,  21, -11, -17,   0,  29, -11, -16,   1,  30, -10, -14,   0,  23,
+  ], [
+   -16, -17, -12,  -6, -19, -19, -14,  -7,  -3,  -1,   1,   2,  27,  35,  29,  19,
+  ], [
+   -37,  -8,  23,  23, -42,  -9,  28,  29, -43, -10,  26,  28, -38, -11,  19,  22,
+  ], [
+    32,  16, -16, -33,  39,  20, -18, -37,  38,  19, -19, -38,  32,  15, -17, -34,
+  ], [
+    24,   9,  -6,  -4,  -1, -10,  -6,   3,  -8,  -9,  -1,   3,   3,   7,   2,  -6,
+  ], [
+    -1,  -3,  -1,   0,  -1,   4,   2,  -7,  -3,  11,   3, -16,   1,  20,   9, -18,
+  ], [
+    -3,  -8,   6,  12,  -5, -10,   7,  13,  -6,  -9,   5,   7,  -5,  -5,   2,  -1,
+  ], [
+    -8,  12,  -3,  -1, -10,  15,  -3,   1, -11,  13,  -4,   1, -11,   8,  -3,   2,
+  ], [
+     9,   6,  -5, -12,   3,   0,  -8, -13,  -4,  -4,  -1,  -1,  -4,   1,  15,  18,
+  ], [
+     9,  13,  14,  12,   4,   3,  -1,  -2,  -2,  -5,  -8,  -5,  -7, -11,  -9,  -4,
+  ], [
+     7,  -5,  -7,  -4,  14,  -2,  -7,  -4,  17,   0,  -8,  -5,  15,   1,  -7,  -5,
+  ], [
+   -10,  -1,   6,   4, -15,  -9,   2,   4,   2,  -1,  -3,   0,  25,  13,  -8, -10,
+  ], [
+     7,  11,  -3, -16,   7,  11,  -3, -15,   6,   7,  -2,  -9,   4,   2,  -3,  -5,
+  ], [
+    -7,  -1,  -1,   0,  -9,  -2,   2,   6, -12,  -4,   6,  14, -13,  -6,   8,  19,
+  ], [
+   -18, -18, -11,  -5,  -3,   0,   3,   4,   6,   8,   6,   6,   6,   6,   6,   6,
+  ], [
+    -5,   3,  13, -10,  -6,   1,  15,  -9,  -6,  -3,  15,  -6,  -6,  -6,  10,  -3,
+  ], [
+     9,   1,  -9,  -9,  11,   9,   6,   5,   0,   3,   8,   7, -15, -14,  -6,  -5,
+  ], [
+   -11,  -6,  11,  19,  -2,  -5,  -9,  -8,   6,   2,  -9, -10,   6,   5,   4,   5,
+  ], [
+    -7,  -3,   8,  15,  -1,   3,  10,  15,   5,   5,  -1,  -2,   4,  -2, -21, -25,
+  ], [
+     6,  -6,  -6,   5,   8,  -9,  -7,   9,   8, -12,  -7,  13,   4, -14,  -7,  14,
+  ], [
+    -4,  -3,   1,   1,  -3,  -5,  -2,  -3,   7,   0,  -2,  -4,  20,   7,  -4,  -4,
+  ], [
+    -3, -20,  -6,  10,   6,   0,   0,   1,   5,   8,   5,  -1,  -3,   0,   0,  -2,
+  ], [
+    13,   6,  -1,   2,   5,   3,   2,   3,  -3,   0,   3,   0, -16,  -8,  -2,  -5,
+  ], [
+    -2,  -7,  -6,   0,  -3,  -6,  -3,   1,  -5,  -1,   2,  -1,  -1,  12,  16,   5,
+  ], [
+    -7,   1,   9,   8, -10,  -2,   5,   3,  -6,   2,   7,   3,  -4,   0,  -1,  -7,
+  ], [
+     3,   4,  -9, -24,   0,   2,   6,   3,  -1,  -1,   4,   7,   5,   3,  -1,  -2,
+  ], [
+     3,   6,  -9,   2,   1,   6, -13,   1,   1,   8, -10,   2,   1,   8,  -7,   1,
+  ], [
+    -3,  -3,   2,  22,  -2,  -3,  -5,  12,  -2,  -3, -10,   2,  -3,  -1,  -4,   2,
+  ], [
+    11,  12,   8,   2,  -5,  -5,  -5,  -8,  -6,  -4,   0,  -3,  -2,  -1,   3,   3,
+  ], [
+    12,  -6,  -2,  -1,  12,  -8,  -2,  -2,   9,  -7,   0,  -3,   4,  -6,   2,  -2,
+  ], [
+   -19,   1,  12,  -3,  -4,   4,   5,  -4,   6,   1,  -2,  -1,   4,  -4,  -2,   7,
+  ], [
+    -3,  -4,  -7,  -8,  -4,  -4,  -2,   0,  -1,   2,  14,  16,  -4,  -2,   4,   4,
+  ], [
+    -1,   7,   2,  -5,  -2,   0,  -1,   1,   4,  -3,  -1,  13,   6, -12, -14,   8,
+  ], [
+    -1,   5,   4,  -5,  -2,   5,   3,  -9,  -2,   7,   4, -12,  -1,   7,   4,  -9,
+  ], [
+    -6,  -3,   1,   1,  11,  11,   0,  -6,   6,   4,  -2,  -7, -12, -10,   3,  10,
+  ], [
+    -2,  -3,  -3,  -2,   6,  11,  14,  10,  -9, -11, -10, -10,   2,   2,   3,   2,
+  ], [
+    -7,  -5,  -7,  -1,  -1,   2,   0,   7,  -1,   1,   0,   9,   3,   4,  -5,  -1,
+  ], [
+    10,  -1, -15,  -1,   4,   1,  -5,   2,  -3,   1,  -1,   1,  -3,   1,   4,   4,
+  ], [
+     2,  -1,   4,  10,   6,   2,  -1,   0,   2,   2,  -7, -12,  -4,   2,   0,  -3,
+  ], [
+    -1,  -4,  -1,  -8,   3,  -1,   2,  -9,   4,   0,   5,  -5,   2,   0,   8,   3,
+  ], [
+     3,   2,   1,   1,   4,  -2,   0,   3,   2,  -1,   4,   1,   0,   6,  -1, -25,
+  ], [
+    -1,  -2,  -2,  -4,  -3,   0,  -1,  -4,  -1,  -1,  -4,   2,   0,  -6,   2,  25,
+  ], [
+   -11,  -1,   5,   0,   7,   0,  -2,   2,  10,  -1,  -3,   4,  -5,  -5,  -2,  -1,
+  ], [
+     0,   6,   3,  -1,  -2,  -1,  -1,   1,  -1,  -7, -12,  -5,   8,   6,   2,   4,
+  ], [
+     2,   6,  -1,  -6,   9,  10,  -1,  -4,   1,   0,  -4,   0,   3,  -2,  -9,  -5,
+  ], [
+    -4,   3,   4,   0,  -4,   3,   3,   0, -11,   0,   3,   2, -11,   3,   7,   2,
+  ], [
+     2,  -4,   7,   3,   1,  -8,   7,   1,  -1, -12,   4,   1,   3,  -9,   2,   2,
+  ], [
+     2,  -2,  -2,   9, -17,  -3,   3,   1,  -4,   7,   1,  -6,   5,   4,  -1,   3,
+  ], [
+    -1,   2,   0,  -4,  -7,   8,  12,  -1,  -2,   5,   4,  -5,   3,  -5,  -8,  -2,
+  ], [
+     0,   0,  -5,  -2,  -2,  -8,   3,  27,  -1,  -4,  -3,   6,  -3,   1,  -2,  -7,
+  ], [
+     4,   4,   1,  -1,  -7, -10,  -7,  -3,  10,  10,   5,   3,  -2,  -2,  -4,  -3,
+  ], [
+     0,   1,   5,   7,   4,  -2, -16, -20,   0,   4,   7,   8,   2,   0,  -2,  -1,
+  ], [
+    -2,   1,   3,  17,  -3,   1,  -2,  -1,  -1,  -2,  -1,  -2,  -1,  -5,  -1,   0,
+  ], [
+     5,  -3,   1,   0,   6,  -2,   0,   0,  -1,  -2,   0,  -3, -11,   1,   8,  -1,
+  ], [
+     3,   0,   0,   0,   0,   2,   4,   1,   2,   0,   6,   1,  -2, -18,  -3,   2,
+  ], [
+   -14,   0,   6,   1,  -5,  -2,  -1,   1,  -1,   1,   0,   1,   1,   7,   4,   0,
+  ], [
+    -1,   0,   1,  -4,   1,   8,   3,  -4,  -3,   4,   1,   3,  -6,   1,  -4,   1,
+  ], [
+     1, -12,   3,   3,  -1, -10,   0,  -1,   2,   0,   2,   1,   3,   2,   2,   4,
+  ], [
+     3,   0,   0,   3,   2,   0,  -2,   1,   5,   2,  -5,   0,   6,  -1, -14,  -1,
+  ], [
+    -2,  -6,  -3,  -3,   2,  -1,   4,   5,   6,  -1,  -2,   0,   4,   4,  -1,  -5,
+  ], [
+    -4,   1, -11,   0,  -1,   2,  -4,   1,   2,  -3,   3,  -1,   1,  -2,  15,   0,
+  ], [
+     1,  -1,   0,  -2,   1,  -4,  -7,   1,  -2,  -6,  -1,  21,  -2,   2,  -1,   1,
+  ], [
+    21,  -1,  -2,   0,  -1,  -3,   1,  -2,  -9,  -2,   2,  -1,   2,   1,  -4,  -1,
+  ], [
+     1,   8,   2,  -6, -10,  -1,   4,   0,  -4,  -3,   3,   3,   5,   0,  -1,  -1,
+  ], [
+     3,   2,   1,  -2,  -2,  -2,   4,   3,   5,   2,  -4, -17,   0,  -2,   4,   3,
+  ], [
+    -7,  -4,   0,   3,   9,   9,   2,  -1, -11,  -6,   0,  -1,   5,   1,   0,   1,
+  ], [
+     0,  17,   5, -11,   3,  -2,  -6,   0,   2,  -2,  -4,   1,  -4,   1,   2,  -1,
+  ], [
+    -5,  -1,  -5,  -3,  -3,   5,  -3,  -2,   4,  16,   2,  -5,  -2,   5,  -1,  -1,
+  ], [
+     0,   0,  -4,   1,  -1,   2,   5,  11,  -1,  -1,  -2,   1,  -4,  -2,  -3,  -1,
+  ], [
+    -5,  -1,  10,   0,   6,   1,   0,  -3,   0,  -4,   1,   0,  -2,  -4,   3,  -1,
+  ], [
+     6,   9,   3,   0,  -2,   1,  -2,   0,  -2,  -3,  -2,  -2,   1,   0,   1,  -6,
+  ], [
+     1,   0,   2,   1,  -1,   3,  -2,   1,   0,  -1, -15,   0,  -1,   5,   2,   6,
+  ], [
+     2,   0,   2,   2,   0, -12,  -4,   6,   0,   1,   4,  -1,   1,   2,   1,  -4,
+  ], [
+     1,  -2,  -7,   0,   0,   0,   0,  -1,  -5,   2,  11,   3,   1,   3,   0,  -6,
+  ], [
+     0,  -3,  -9,  -4,   1,   3,  -1,   0,   4,   1,  -2,   0,   7,  -3,  -1,   6,
+  ], [
+     1,  -2,   6,   2,   0,  -1,   3,  -2,  -2,   4,   0,   2,  -1,   2, -14,   2,
+  ], [
+     2,   2,   0,  -1,  -2,   3,  -3, -14,   0,   2,   3,  -3,   5,   1,   3,   2,
+  ], [
+     1,  -3,   4, -14,   1,  -2,  11,  -1,   0,  -1,   3,   0,  -1,   1,   0,   2,
+  ], [
+    -2,   3,  -3,   2,  -4,  -1,  -4,   3,  -1,   2,   1,   3,  -6,  -2,   2,   7,
+  ], [
+    -2,   1,   2,   0,  -2,   0,   0,  -1,  12,   5,  -1,   2,  -8,  -1,   1,  -7,
+  ], [
+     2,  -2,  -4,   2,  11,   0, -11,  -2,   3,   1,  -3,  -1,   0,   3,   1,  -1,
+  ], [
+     0,   3,   0,  -2,   0,  -6,  -1,  -3,  12,  -7,  -2,   0,   7,  -2,   1,   1,
+  ], [
+     1,   2,   2,   2,  -1,   2,   0,   2, -23,   0,   4,   0,   3,   2,   1,   3,
+  ], [
+    -4,  -5,  -1,   5,  -3,   5,  10,  -1,   0,   0,   3,  -4,   1,  -1,   2,  -5,
+  ]
+];
+
+pub const SVQ_INTER_CB_4X2: [[i8; 8]; 96] = [
+  [
+     7,   2,  -6,  -7,   7,   3,  -3,  -4,
+  ], [
+    -7,  -2,   7,   8,  -8,  -4,   3,   4,
+  ], [
+    19,  17,   9,   3, -14, -16, -12,  -8,
+  ], [
+   -18, -16,  -8,  -3,  11,  14,  12,   8,
+  ], [
+     7, -16, -10,  20,   7, -17, -10,  20,
+  ], [
+    -6,  18,   8, -21,  -7,  18,   9, -20,
+  ], [
+    25,   3, -20, -14,  29,   7, -18, -13,
+  ], [
+   -29,  -4,  21,  14, -31,  -6,  20,  14,
+  ], [
+   -19, -26, -28, -24,  31,  32,  22,  10,
+  ], [
+    15,  24,  31,  28, -32, -32, -22, -13,
+  ], [
+     2,  -8, -23, -26,  -9,   3,  27,  35,
+  ], [
+     3,  11,  21,  21,   8,  -4, -27, -34,
+  ], [
+   -30, -31,  12,  47, -29, -30,  13,  47,
+  ], [
+    38,  30, -17, -46,  34,  26, -19, -46,
+  ], [
+   -42, -50, -51, -43,  34,  48,  55,  48,
+  ], [
+    48,  54,  51,  42, -44, -52, -53, -47,
+  ], [
+     4,   5,   0,  -6,  -2,  -2,   0,   1,
+  ], [
+   -11,  -6,  -1,  -2,   1,   8,   9,   1,
+  ], [
+     0,   1,  -6,   5,   8,   1, -12,   2,
+  ], [
+     7, -14,  -7,   8,   5,  -8,   0,   8,
+  ], [
+     1,   4,  11,   8, -12,  -8,   0,  -5,
+  ], [
+    -1,   1,   0,   4, -15,  -8,   3,  16,
+  ], [
+    17,   8,  -4,  -6,   9,  -4, -13,  -8,
+  ], [
+     2,   6,   1, -18,  -1,  11,  11, -12,
+  ], [
+     6,   0,   2,   0,  14,   6,  -7, -21,
+  ], [
+     1,  -1, -13, -20,   1,   1,  10,  21,
+  ], [
+   -22,  -5,   7,  13, -11,  -1,   4,  12,
+  ], [
+    -7,   0,  14,  19,  -4,   3,  -5, -19,
+  ], [
+   -26, -14,  10,  15,  18,   4,  -6,  -2,
+  ], [
+    25,  19,  -5, -18, -20,  -7,   4,   2,
+  ], [
+   -13,  -6,  -1,  -4,  25,  37,  -2, -35,
+  ], [
+     5,   4,   1,   1, -21, -36,   2,  43,
+  ], [
+     2,  -2,  -1,   3,   8,  -2,  -6,  -1,
+  ], [
+    -2,  -3,   2,  12,  -5,  -2,  -2,  -1,
+  ], [
+    -3,  -1,  -1,  -5,  -1,   7,   8,  -2,
+  ], [
+     2,   7,   5,  -3,   1,   1,  -3,  -8,
+  ], [
+    -3,  -1,  -3,  -2,  -2,  -3,   2,  13,
+  ], [
+    15,   0, -11,  -6,   3,   0,   0,   0,
+  ], [
+    -6,  -9,  -5,  -4,  18,   4,   1,   3,
+  ], [
+    12,   3,   0,   4, -16,  -3,   3,  -3,
+  ], [
+   -17,   3,  18,   2,  -1,  -3,  -1,  -1,
+  ], [
+    -6,  16,  -8,   0,  -9,  14,  -7,   0,
+  ], [
+     3, -13,  14,  -5,   3, -13,  14,  -4,
+  ], [
+    -7,  20,  14, -23,   8,  -7,  -8,   4,
+  ], [
+     8, -15, -19,  16, -10,  13,  11,  -3,
+  ], [
+     9,  -1,   1,  26,   5, -15, -27,   2,
+  ], [
+   -20,   7,  16,  -4, -40,   9,  31,   1,
+  ], [
+    26, -12, -30,  -7,  40,  -2, -19,   4,
+  ], [
+     6,   0,   0,   0,  -6,  -2,   1,   2,
+  ], [
+     0,  -1,   0,  -6,   9,   0,  -2,  -1,
+  ], [
+    -7,   8,   2,  -3,  -1,   2,  -3,   2,
+  ], [
+     7,  -4,  -2,   4,   2,   0,   0,  -6,
+  ], [
+    -3,  -2,   9,   2,  -2,  -1,   0,  -4,
+  ], [
+    -3,  -3,   0,  -3,  -6,   2,  10,   4,
+  ], [
+     3,   0, -10,   8,   0,   0,  -4,   4,
+  ], [
+    -1,   1,   4,   2,   3,  -7,  -9,   7,
+  ], [
+     2,   1,  -9,  -4,  -1,  12,   0,   0,
+  ], [
+     3,  -1,   7,  -4,   3, -14,   4,   2,
+  ], [
+   -12,  -9,   1,  11,   2,   5,   1,   0,
+  ], [
+     3,   1,   0,   2,   0,   8,   6, -19,
+  ], [
+    -6, -10,  -7,  -4,   9,   7,   5,   7,
+  ], [
+     6,  21,   3,  -3, -11,  -9,  -5,  -2,
+  ], [
+    -4,  -9, -16,  -1,  -2,  -5,   1,  36,
+  ], [
+     8,  11,  19,   0,   2,   5,  -4, -41,
+  ], [
+    -1,  -1,  -2,  -1,  -2,  -2,   1,   6,
+  ], [
+     0,   4,   1,  -8,   1,   1,   1,   0,
+  ], [
+    -2,  -3,   4,   0,   2,  -1,   3,  -3,
+  ], [
+     1,   3,  -4,   1,  -1,   3,   0,  -5,
+  ], [
+     3,   4,   2,   3,  -2,  -3,  -6,  -1,
+  ], [
+    -2,  -3,  -2,   2,  -4,   8,   1,   0,
+  ], [
+    -7,   4,   2,   6,  -7,  -1,   1,   0,
+  ], [
+    -2,   2,  -4,   1,   8,  -6,   2,  -1,
+  ], [
+    -6,   2,   0,   2,   5,   4,  -8,  -1,
+  ], [
+    -1, -11,   0,   9,   0,  -2,   2,   2,
+  ], [
+    17,  -5,  -4,  -1,  -1,  -4,  -2,  -2,
+  ], [
+     0, -13,   9,  -3,  -1,  12,  -7,   2,
+  ], [
+     0,  -2,  -5,   2,  -7,  -5,  20,  -3,
+  ], [
+     7,   7,  -1, -30,   3,   5,   8,   1,
+  ], [
+    -6,   3,  -1,  -4,   2,  -2, -11,  18,
+  ], [
+     0,  -7,   3,  14,  20,  -3, -18,  -9,
+  ], [
+     7,  -2,   0,  -1,  -2,   0,   0,  -1,
+  ], [
+    -4,  -1,   1,   0,  -2,   2,   0,   4,
+  ], [
+     1,  -3,   2,   1,   3,   1,  -5,   1,
+  ], [
+    -3,   0,  -1,  -2,   7,   1,   0,  -3,
+  ], [
+     2,   5,   0,  -2,   2,  -5,  -1,   1,
+  ], [
+    -1,  -2,   4,  -1,   0,  -3,   5,   0,
+  ], [
+     0,   3,  -1,  -2,  -4,   1,   5,  -1,
+  ], [
+    -1,   0,  -1,   9,  -1,  -2,  -1,  -1,
+  ], [
+    -2,   5,   5,  -1,  -2,   2,  -3,  -2,
+  ], [
+     1,   2, -11,   1,   2,   1,   3,   2,
+  ], [
+     2, -10,  -1,  -2,   4,   2,   4,   1,
+  ], [
+     4,   5,  -5,   1,   0,   6, -11,   1,
+  ], [
+     1,   0,   6,   6,   0,   2,   1, -15,
+  ], [
+     7,   3,   5,   9, -30,   2,   2,   2,
+  ], [
+   -34,   1,   9,   2,   5,   8,   8,   2,
+  ], [
+     7,   2,   6,   6,   2, -27,   1,   4,
+  ]
+];
diff --git a/nihav-qt/src/codecs/svq3.rs b/nihav-qt/src/codecs/svq3.rs
new file mode 100644 (file)
index 0000000..6d65e65
--- /dev/null
@@ -0,0 +1,1323 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+use nihav_codec_support::codecs::*;
+use nihav_codec_support::codecs::blockdsp::*;
+use nihav_codec_support::data::GenericCache;
+
+use super::svq3dsp::*;
+
+struct SVQ3Header {
+    ftype:      FrameType,
+    ts:         u8,
+    quant:      u8,
+    dquant:     bool,
+}
+
+#[derive(Clone,Copy,Debug,PartialEq)]
+enum MCMode {
+    Pixel,
+    Halfpel,
+    Thirdpel
+}
+
+#[derive(Default)]
+struct SState {
+    q:          u8,
+    has_left:   bool,
+    has_top:    bool,
+    has_tl:     bool,
+    has_tr:     bool,
+    trb:        u8,
+    trd:        u8,
+}
+
+struct IntraModeState {
+    cache:      GenericCache<i8>,
+    i16_pred:   i8,
+}
+
+impl IntraModeState {
+    fn new(mb_w: usize) -> Self {
+        let stride = 1 + mb_w * 4 + 1;
+        IntraModeState { cache: GenericCache::new(4, stride, -1), i16_pred: 0 }
+    }
+    fn reset(&mut self) { self.cache.reset(); }
+    fn update(&mut self) { self.cache.update_row(); }
+    fn get_pos(&self, xpos: usize) -> usize {
+        self.cache.stride + 1 + xpos * 4
+    }
+    fn set_mb_x(&mut self, mb_x: usize) {
+        self.cache.xpos = self.get_pos(mb_x);
+    }
+    fn fill_block(&mut self, val: i8) {
+        let mut pos = self.cache.xpos;
+        for _ in 0..4 {
+            for j in 0..4 {
+                self.cache.data[pos + j] = val;
+            }
+            pos += self.cache.stride;
+        }
+    }
+    fn get_pred16_type(&self, has_top: bool, has_left: bool) -> PredType8x8 {
+        if !has_top && !has_left { return PredType8x8::DC128; }
+        let mut im = INTRA_PRED16[self.i16_pred as usize];
+        if !has_top {
+            im = match im {
+                    PredType8x8::Plane | PredType8x8::Ver => PredType8x8::Hor,
+                    PredType8x8::DC => PredType8x8::LeftDC,
+                    _   => im,
+                 };
+        } else if !has_left {
+            im = match im {
+                    PredType8x8::Plane | PredType8x8::Hor => PredType8x8::Ver,
+                    PredType8x8::DC => PredType8x8::TopDC,
+                    _   => im,
+                 };
+        }
+        im
+    }
+    fn get_pred8_type(&self, has_top: bool, has_left: bool) -> PredType8x8 {
+        if !has_top && !has_left { return PredType8x8::DC128; }
+        let mut im = PredType8x8::DC;
+        if !has_top {
+            im = match im {
+                    PredType8x8::Plane | PredType8x8::Ver => PredType8x8::Hor,
+                    PredType8x8::DC => PredType8x8::LeftDC,
+                    _   => im,
+                 };
+        } else if !has_left {
+            im = match im {
+                    PredType8x8::Plane | PredType8x8::Hor => PredType8x8::Ver,
+                    PredType8x8::DC => PredType8x8::TopDC,
+                    _   => im,
+                 };
+        }
+        im
+    }
+    fn get_pred4_type(&self, x: usize, y: usize, has_top: bool, has_left: bool) -> PredType4x4 {
+        let no_up = !has_top && (y == 0);
+        let no_left = !has_left && (x == 0);
+        if no_up && no_left { return PredType4x4::DC128; }
+
+        let mut im = INTRA_PRED4[self.cache.data[self.cache.xpos + x + y * self.cache.stride] as usize];
+
+        if no_up {
+            im = match im {
+                    PredType4x4::Ver => PredType4x4::Hor,
+                    PredType4x4::DC  => PredType4x4::LeftDC,
+                    _                => im,
+                 };
+        } else if no_left {
+            im = match im {
+                    PredType4x4::Hor            => PredType4x4::Ver,
+                    PredType4x4::DC             => PredType4x4::TopDC,
+                    _                           => im,
+                 };
+        }
+        im
+    }
+}
+
+struct MVInfo {
+    mv_b:   Vec<MV>,
+    mv_f:   Vec<MV>,
+    w:      usize,
+    h:      usize,
+    has_b:  Vec<bool>,
+    has_f:  Vec<bool>,
+}
+
+impl MVInfo {
+    fn new() -> Self {
+        Self { mv_b: Vec::new(), mv_f: Vec::new(), w: 0, h: 0, has_b: Vec::new(), has_f: Vec::new() }
+    }
+    fn resize(&mut self, mb_w: usize, mb_h: usize) {
+        self.w = mb_w * 4;
+        self.h = mb_h * 4;
+        self.reset();
+    }
+    fn reset(&mut self) {
+        let size = self.w * self.h;
+        self.mv_f.truncate(0);
+        self.mv_f.resize(size, ZERO_MV);
+        self.mv_b.truncate(0);
+        self.mv_b.resize(size, ZERO_MV);
+        self.has_f.truncate(0);
+        self.has_f.resize(size >> 4, false);
+        self.has_b.truncate(0);
+        self.has_b.resize(size >> 4, false);
+    }
+    fn fill(&mut self, mb_x: usize, mb_y: usize, fwd: bool, mv: MV) {
+        let idx = mb_x * 4 + mb_y * 4 * self.w;
+        let dst = if fwd { &mut self.mv_f[idx..] } else { &mut self.mv_b[idx..] };
+        for row in dst.chunks_mut(self.w).take(4) {
+            row[0] = mv;
+            row[1] = mv;
+            row[2] = mv;
+            row[3] = mv;
+        }
+    }
+    fn fill_part(&mut self, x: usize, y: usize, fwd: bool, bw: usize, bh: usize, mv: MV) {
+        let idx = x + y * self.w;
+        let dst = if fwd { &mut self.mv_f[idx..] } else { &mut self.mv_b[idx..] };
+        for row in dst.chunks_mut(self.w).take(bh) {
+            for el in row.iter_mut().take(bw) {
+                *el = mv;
+            }
+        }
+    }
+    fn get_mv_by_idx(&self, idx: usize, fwd: bool) -> MV {
+        if fwd { self.mv_f[idx] } else { self.mv_b[idx] }
+    }
+    fn pred_mv(&self, idx: usize, bw: usize, fwd: bool, has_top: bool, has_left: bool, has_tr: bool, has_tl: bool) -> MV {
+        if !has_top && !has_left { return ZERO_MV; }
+        let left_mv = if has_left { self.get_mv_by_idx(idx - 1, fwd) } else { ZERO_MV };
+        let top_mv  = if has_top  { self.get_mv_by_idx(idx - self.w, fwd) } else { left_mv };
+        let tr_mv;
+        if has_tr {
+            tr_mv = self.get_mv_by_idx(idx - self.w + bw, fwd);
+        } else if has_tl {
+            tr_mv = self.get_mv_by_idx(idx - self.w - 1, fwd);
+        } else {
+            tr_mv = left_mv;
+        }
+        MV::pred(left_mv, top_mv, tr_mv)
+    }
+    fn pred_mv_part(&self, x: usize, y: usize, bw: usize, fwd: bool, has_top: bool, has_left: bool, has_tr: bool, has_tl: bool) -> MV {
+        self.pred_mv(x + y * self.w, bw, fwd, has_top, has_left, has_tr, has_tl)
+    }
+    fn get_mv(&self, x: usize, y: usize, fwd: bool) -> MV {
+        let idx = x + y * self.w;
+        if fwd { self.mv_f[idx] }
+        else   { self.mv_b[idx] }
+    }
+}
+
+struct SVQ3Decoder {
+    info:       NACodecInfoRef,
+    width:      usize,
+    height:     usize,
+    ipbs:       IPBShuffler,
+    avg_buf:    NAVideoBufferRef<u8>,
+    imode:      IntraModeState,
+    mvi:        MVInfo,
+    ref_mvi:    MVInfo,
+    mbtypes:    Vec<u8>,
+    ebuf:       [u8; 32 * 18],
+
+    coeffs:     [[i16; 16]; 25],
+    coded:      [bool; 24],
+    dc_only:    [bool; 24],
+
+    use_hpel:   bool,
+    use_tpel:   bool,
+    no_bframes: bool,
+    protected:  bool,
+    slice_buf:  Vec<u8>,
+    mb_x:       usize,
+    mb_y:       usize,
+    mb_w:       usize,
+    mb_h:       usize,
+    ts_fwd:     u8,
+    ts_bwd:     u8,
+    pts_base:   u64,
+    ts_base:    u8,
+}
+
+const ZIGZAG4: &[usize; 16] = &[
+    0,  1,  4,  8,
+    5,  2,  3,  6,
+    9, 12, 13, 10,
+    7, 11, 14, 15
+];
+const ALT_SCAN: &[usize; 16] = &[
+     0,  1,  2,  6,
+    10,  3,  7, 11,
+     4,  8,  5,  9,
+    12, 13, 14, 15
+];
+
+const SVQ3_RUNLEVEL: [(usize, i16); 16] = [
+    ( 0, 0 ), ( 0, 1 ), ( 1, 1 ), ( 2, 1 ), ( 0, 2 ), ( 3, 1 ), ( 4, 1 ), ( 5, 1 ),
+    ( 0, 3 ), ( 1, 2 ), ( 2, 2 ), ( 6, 1 ), ( 7, 1 ), ( 8, 1 ), ( 9, 1 ), ( 0, 4 )
+];
+const SVQ3_RUNLEVEL_ALT: [(usize, i16); 16] = [
+    ( 0, 0 ), ( 0, 1 ), ( 1, 1 ), ( 0, 2 ), ( 2, 1 ), ( 0, 3 ), ( 0, 4 ), ( 0, 5 ),
+    ( 3, 1 ), ( 4, 1 ), ( 1, 2 ), ( 1, 3 ), ( 0, 6 ), ( 0, 7 ), ( 0, 8 ), ( 0, 9 )
+];
+const RUN_ADD: [i16; 16] = [ 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 ];
+const RUN_ADD_ALT: [i16; 8] = [ 8, 2, 0, 0, 0, -1, -1, -1 ];
+
+fn decode_alt_slice(br: &mut BitReader, blk: &mut [i16; 16], mut idx: usize, end: usize) -> DecoderResult<bool> {
+    let mut coded = false;
+    while idx < end {
+        let val                         = br.read_code(UintCodeType::Gamma)?;
+        if val == 0 { break; }
+        let sign = (val & 1) == 0;
+        let val = (val + 1) >> 1;
+        let (run, level) = if (val as usize) < SVQ3_RUNLEVEL.len() {
+                SVQ3_RUNLEVEL_ALT[val as usize]
+            } else {
+                let run = (val & 0x7) as usize;
+                (run, ((val >> 3) as i16) + RUN_ADD_ALT[(run as usize).min(RUN_ADD_ALT.len() - 1)])
+            };
+        idx += run;
+        validate!(idx < end);
+        blk[ALT_SCAN[idx]] = if sign { -level } else { level };
+        coded = true;
+        idx += 1;
+    }
+    if idx == end {
+        let val                         = br.read_code(UintCodeType::Gamma)?;
+        validate!(val == 0);
+    }
+    Ok(coded)
+}
+
+fn decode_block(br: &mut BitReader, blk: &mut [i16; 16], start: usize, alt: bool) -> DecoderResult<bool> {
+    let mut coded = false;
+    if !alt {
+        let mut idx = start;
+        while idx < blk.len() {
+            let val                     = br.read_code(UintCodeType::Gamma)?;
+            if val == 0 { break; }
+            let sign = (val & 1) == 0;
+            let val = (val + 1) >> 1;
+            let (run, level) = if (val as usize) < SVQ3_RUNLEVEL.len() {
+                    SVQ3_RUNLEVEL[val as usize]
+                } else {
+                    let run = (val & 0xF) as usize;
+                    (run, ((val >> 4) as i16) + RUN_ADD[(run as usize).min(RUN_ADD.len() - 1)])
+                };
+            idx += run;
+            validate!(idx < blk.len());
+            blk[ZIGZAG4[idx]] = if sign { -level } else { level };
+            coded = true;
+            idx += 1;
+        }
+        if idx == blk.len() {
+            let val                     = br.read_code(UintCodeType::Gamma)?;
+            validate!(val == 0);
+        }
+    } else {
+        coded  = decode_alt_slice(br, blk, start,  8)?;
+        coded |= decode_alt_slice(br, blk,     8, 16)?;
+    }
+    Ok(coded)
+}
+
+fn decode_chroma_dc(br: &mut BitReader) -> DecoderResult<[i16; 4]> {
+    let mut idx = 0;
+    let mut blk = [0i16; 4];
+    while idx < blk.len() {
+        let val                         = br.read_code(UintCodeType::Gamma)?;
+        if val == 0 { break; }
+        let sign = (val & 1) == 0;
+        let val = (val + 1) >> 1;
+        let (run, level) = if val < 3 {
+                (0, val as i16)
+            } else if val == 3 {
+                (1, 1)
+            } else {
+                ((val & 3) as usize, (((val + 9) >> 2) - (val & 3)) as i16)
+            };
+        idx += run;
+        validate!(idx < blk.len());
+        blk[idx] = if sign { -level } else { level };
+        idx += 1;
+    }
+    if idx == blk.len() {
+        let val                         = br.read_code(UintCodeType::Gamma)?;
+        validate!(val == 0);
+    }
+    Ok(blk)
+}
+
+fn read_mv(br: &mut BitReader) -> DecoderResult<MV> {
+    let y                               = br.read_code_signed(IntCodeType::Gamma)? as i16;
+    let x                               = br.read_code_signed(IntCodeType::Gamma)? as i16;
+    Ok(MV{ x, y })
+}
+
+fn div6(val: i16) -> i16 {
+    (((((i32::from(val) + (6 << 16)) as u32) / 6) as i32) - (1 << 16)) as i16
+}
+
+fn scale_mv(mv: MV, trb: u8, trd: u8) -> (MV, MV) {
+    let trb = i32::from(trb);
+    let trd = i32::from(trd);
+    let fx = (i32::from(mv.x * 2) * trb / trd + 1) >> 1;
+    let fy = (i32::from(mv.y * 2) * trb / trd + 1) >> 1;
+    let bx = (i32::from(mv.x * 2) * (trb - trd) / trd + 1) >> 1;
+    let by = (i32::from(mv.y * 2) * (trb - trd) / trd + 1) >> 1;
+    (MV { x: fx as i16, y: fy as i16 }, MV { x: bx as i16, y: by as i16 })
+}
+
+fn add_mv(pred_mv: MV, dmv: MV, mc_mode: MCMode) -> (MV, usize, &'static [BlkInterpFunc]) {
+    match mc_mode {
+        MCMode::Pixel => {
+            let x = div6(pred_mv.x + 3);
+            let y = div6(pred_mv.y + 3);
+            let mut mv = MV{ x, y } + dmv;
+            mv.x *= 6;
+            mv.y *= 6;
+            (mv, 0, HALFPEL_INTERP_FUNCS)
+        },
+        MCMode::Halfpel => {
+            let x = div6(pred_mv.x * 2 + 2);
+            let y = div6(pred_mv.y * 2 + 2);
+            let mut mv = MV{ x, y } + dmv;
+            let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize;
+            mv.x *= 3;
+            mv.y *= 3;
+            (mv, mode, HALFPEL_INTERP_FUNCS)
+        },
+        MCMode::Thirdpel => {
+            let x = (pred_mv.x + 1) >> 1;
+            let y = (pred_mv.y + 1) >> 1;
+            let mut mv = MV{ x, y } + dmv;
+            let mut mx = mv.x % 3;
+            if mx < 0 { mx += 3; }
+            let mut my = mv.y % 3;
+            if my < 0 { my += 3; }
+            let mode = (mx + my * 3) as usize;
+            mv.x <<= 1;
+            mv.y <<= 1;
+            (mv, mode, THIRDPEL_INTERP_FUNCS)
+       },
+    }
+}
+
+fn copy_block(dst: &mut NASimpleVideoFrame<u8>, src: NAVideoBufferRef<u8>, ebuf: &mut [u8; 32 * 18], comp: usize,
+              dx: usize, dy: usize, mv_x: i16, mv_y: i16, bw: usize, bh: usize,
+              preborder: usize, postborder: usize,
+              mode: usize, interp: &[BlkInterpFunc])
+{
+    let pre  = if mode != 0 { preborder  as isize } else { 0 };
+    let post = if mode != 0 { postborder as isize } else { 0 };
+    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 - pre < 0) || (sx + (bw as isize) + post > (w as isize)) ||
+       (sy - pre < 0) || (sy + (bh as isize) + post > (h as isize)) {
+        let ebuf_stride: usize = 32;
+
+        let dstride = dst.stride[comp];
+        let doff    = dst.offset[comp];
+        let edge = (pre + post) as usize;
+        edge_emu(&src, sx - pre, sy - pre, bw + edge, bh + edge,
+                 ebuf, ebuf_stride, comp, 4);
+        (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride,
+                       ebuf, ebuf_stride, bw, bh);
+    } 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 dstride = dst.stride[comp];
+        let doff    = dst.offset[comp];
+        let saddr = soff + ((sx - pre) as usize) + ((sy - pre) as usize) * sstride;
+        (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride,
+                       &sbuf[saddr..], sstride, bw, bh);
+    }
+}
+
+fn mc_part(dframe: &mut NASimpleVideoFrame<u8>, src: NAVideoBufferRef<u8>, ebuf: &mut [u8; 32 * 18], xoff: usize, yoff: usize, bw: usize, bh: usize, mv: MV, mode: usize, ifuncs: &[BlkInterpFunc]) {
+    let mx = div6(mv.x);
+    let my = div6(mv.y);
+    let cmx = (mx + if mx < 0 { 1 } else { 0 }) >> 1;
+    let cmy = (my + if my < 0 { 1 } else { 0 }) >> 1;
+    let post = if mode != 0 { 1 } else { 0 };
+
+    copy_block(dframe, src.clone(), ebuf, 0, xoff,     yoff,     mx,  my,  bw * 4, bh * 4, 0, post, mode, ifuncs);
+    copy_block(dframe, src.clone(), ebuf, 1, xoff / 2, yoff / 2, cmx, cmy, bw * 2, bh * 2, 0, post, mode, ifuncs);
+    copy_block(dframe, src.clone(), ebuf, 2, xoff / 2, yoff / 2, cmx, cmy, bw * 2, bh * 2, 0, post, mode, ifuncs);
+}
+
+impl SVQ3Decoder {
+    fn new() -> Self {
+        let tmp_vinfo = NAVideoInfo::new(16, 16, false, YUV420_FORMAT);
+        let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
+        let vb = vt.get_vbuf();
+        let avg_buf = vb.unwrap();
+
+        Self {
+            info:       NACodecInfoRef::default(),
+            width:      0,
+            height:     0,
+            ipbs:       IPBShuffler::new(),
+            avg_buf,
+            imode:      IntraModeState::new(0),
+            mvi:        MVInfo::new(),
+            ref_mvi:    MVInfo::new(),
+            mbtypes:    Vec::new(),
+            ebuf:       [0; 32 * 18],
+
+            coeffs:     [[0; 16]; 25],
+            coded:      [false; 24],
+            dc_only:    [false; 24],
+
+            use_hpel:   false,
+            use_tpel:   false,
+            no_bframes: false,
+            protected:  false,
+            slice_buf:  Vec::new(),
+            mb_x:       0,
+            mb_y:       0,
+            mb_w:       0,
+            mb_h:       0,
+            ts_fwd:     0,
+            ts_bwd:     0,
+            pts_base:   0,
+            ts_base:    0,
+        }
+    }
+    fn parse_sequence_header(&mut self, src: &[u8]) -> DecoderResult<()> {
+        let mut br = BitReader::new(src, BitReaderMode::BE);
+        let fcode                       = br.read(3)? as usize;
+        let (w, h) = if fcode < FRAME_SIZES.len() {
+                FRAME_SIZES[fcode]
+            } else {
+                let w                   = br.read(12)? as usize;
+                let h                   = br.read(12)? as usize;
+                validate!(w >= 16 && h >= 16);
+                (w, h)
+            };
+        self.width  = w;
+        self.height = h;
+        self.use_hpel                   = br.read_bool()?;
+        self.use_tpel                   = br.read_bool()?;
+                                          br.skip(1)?;
+                                          br.skip(1)?;
+                                          br.skip(1)?;
+                                          br.skip(1)?;
+        self.no_bframes                 = br.read_bool()?;
+                                          br.skip(1)?;
+        while br.read_bool()? {
+                                          br.skip(8)?;
+        }
+        self.protected                  = br.read_bool()?;
+//println!(" seq: {}x{} hpel {} tpel {} nob {}", w, h, self.use_hpel, self.use_tpel, self.no_bframes);
+        if self.protected {
+unimplemented!();
+        }
+        Ok(())
+    }
+    fn prepare_slice_buffer(&mut self, src: &[u8]) -> DecoderResult<usize> {
+        let llen = ((src[0] >> 5) & 3) as usize;
+        validate!(llen != 0);
+        validate!(src.len() > llen);
+        let length = match llen {
+                1 => src[1] as usize,
+                2 => (src[1] as usize) * 256 + (src[2] as usize),
+                3 => ((src[1] as usize) << 16) + ((src[2] as usize) << 8) + (src[3] as usize),
+                _ => unreachable!(),
+            };
+        let slice_len = length + llen + 1;
+        validate!(src.len() >= slice_len);
+        self.slice_buf.truncate(0);
+        if llen > 1 {
+            self.slice_buf.extend_from_slice(&src[slice_len - llen + 1..][..llen - 1]);
+        }
+        self.slice_buf.extend_from_slice(&src[llen + 1..][..slice_len - llen - 1]);
+        // todo unscramble
+        Ok(slice_len)
+    }
+    fn parse_slice_header(&self, br: &mut BitReader, slice_mode: u8) -> DecoderResult<SVQ3Header> {
+        let ftype_id                    = br.read_code(UintCodeType::Gamma)? as usize;
+        validate!(ftype_id < FRAME_TYPES.len());
+        let ftype = FRAME_TYPES[ftype_id];
+        if self.no_bframes {
+            validate!(ftype != FrameType::B);
+        }
+
+        if slice_mode == 1 {
+                                          br.skip(1)?;
+        } else {
+            let mbs = self.mb_w * self.mb_h;
+            let mb_bits = if mbs < 64 { 6 } else { 32 - (mbs - 1).leading_zeros() } as u8;
+            let _offset                 = br.read(mb_bits)?;
+println!("slice offset {}", _offset);
+        }
+        let ts                          = br.read(8)? as u8;
+        let quant                       = br.read(5)? as u8;
+        let dquant                      = br.read_bool()?;
+                                          br.skip(1)?;
+        if self.protected {
+                                          br.skip(1)?;
+        }
+                                          br.skip(1)?;
+                                          br.skip(2)?;
+        while br.read_bool()? {
+                                          br.skip(8)?;
+        }
+
+        Ok(SVQ3Header { ftype, ts, quant, dquant })
+    }
+    fn decode_intra_block(&mut self, br: &mut BitReader, mb_type: usize, sstate: &mut SState, hdr: &SVQ3Header) -> DecoderResult<()> {
+        const INTRA_CBP: [u8; 48] = [
+            47, 31, 15,  0, 23, 27, 29, 30,  7, 11, 13, 14, 39, 43, 45, 46,
+            16,  3,  5, 10, 12, 19, 21, 26, 28, 35, 37, 42, 44,  1,  2,  4,
+            8,  17, 18, 20, 24,  6,  9, 22, 25, 32, 33, 34, 36, 40, 38, 41
+        ];
+        let is_4x4 = mb_type == 8 || mb_type == 33;
+        let cbp;
+        if !is_4x4 {
+            let angle = SVQ3_INTRA_ANGLE[(mb_type - 9) & 3];
+                cbp   = SVQ3_INTRA_CBP[(mb_type - 9) / 4];
+            self.imode.i16_pred = angle;
+            self.imode.fill_block(2);
+        } else if mb_type == 8 {
+            for i in 0..8 {
+                let idx                 = br.read_code(UintCodeType::Gamma)? as usize;
+                validate!(idx < SVQ3_INTRA4_PAIRS.len());
+                let mut iidx = self.imode.cache.xpos;
+                if (i & 1) != 0 { iidx += self.imode.cache.stride; }
+                if (i & 2) != 0 { iidx += 2; }
+                if (i & 4) != 0 { iidx += self.imode.cache.stride * 2; }
+
+                let t0 = self.imode.cache.data[iidx     - self.imode.cache.stride];
+                let t1 = self.imode.cache.data[iidx + 1 - self.imode.cache.stride];
+                let l0 = self.imode.cache.data[iidx - 1];
+
+                let p = SVQ3_INTRA4_PAIRS[idx];
+                self.imode.cache.data[iidx] = SVQ3_INTRA4_CTX_PRED[(t0 + 1) as usize][(l0 + 1) as usize][p[0] as usize];
+                let l1 = self.imode.cache.data[iidx];
+                self.imode.cache.data[iidx + 1] = SVQ3_INTRA4_CTX_PRED[(t1 + 1) as usize][(l1 + 1) as usize][p[1] as usize];
+                validate!(self.imode.cache.data[iidx] != -1);
+                validate!(self.imode.cache.data[iidx + 1] != -1);
+            }
+            let idx                     = br.read_code(UintCodeType::Gamma)? as usize;
+            validate!(idx < INTRA_CBP.len());
+            cbp = INTRA_CBP[idx];
+            self.imode.i16_pred = 0;
+        } else {
+            self.imode.fill_block(2);
+            cbp = 0;
+        }
+
+        if !is_4x4 || (hdr.dquant && hdr.ftype != FrameType::I && cbp != 0) {
+            let dq                      = br.read_code_signed(IntCodeType::Gamma)?;
+            let new_q = i32::from(sstate.q) + dq;
+            validate!(new_q >= 0 && new_q < 32);
+            sstate.q = new_q as u8;
+        }
+        if !is_4x4 {
+            decode_block(br, &mut self.coeffs[24], 0, false)?;
+            idct_dc_coeffs(&mut self.coeffs[24], sstate.q);
+        }
+        let start = if is_4x4 { 0 } else { 1 };
+        let alt = sstate.q < 24 && is_4x4;
+        for sb in 0..4 {
+            if ((cbp >> sb) & 1) == 0 { continue; }
+            for b in 0..4 {
+                let blk_idx = if is_4x4 {
+                        (sb & 1) * 2 + (sb >> 1) * 8 + (b & 1) + (b >> 1) * 4
+                    } else {
+                        sb * 4 + b
+                    };
+                self.coded[blk_idx] = decode_block(br, &mut self.coeffs[blk_idx], start, alt)?;
+                if is_4x4 && self.coded[blk_idx] {
+                    idct_dc_coeffs(&mut self.coeffs[blk_idx], sstate.q);
+                }
+            }
+        }
+        if !is_4x4 {
+            for blk_idx in 0..16 {
+                self.coeffs[blk_idx][0] = self.coeffs[24][blk_idx];
+                self.dc_only[blk_idx] = self.coeffs[blk_idx][0] != 0;
+                idct(&mut self.coeffs[blk_idx], sstate.q, false);
+            }
+        }
+        if (cbp & 0x30) != 0 {
+            let mut u_dc = decode_chroma_dc(br)?;
+            let mut v_dc = decode_chroma_dc(br)?;
+            chroma_transform(&mut u_dc);
+            chroma_transform(&mut v_dc);
+
+            let cdcs = [u_dc, v_dc];
+            if (cbp & 0x20) != 0 {
+                for comp in 0..2 {
+                    for i in 0..4 {
+                        let blk_idx = 16 + comp * 4 + i;
+                        self.coded[blk_idx] = decode_block(br, &mut self.coeffs[blk_idx], 1, false)?;
+                    }
+                }
+            }
+            for comp in 0..2 {
+                for i in 0..4 {
+                    let blk_idx = 16 + comp * 4 + i;
+                    self.coeffs[blk_idx][0] = cdcs[comp][i];
+                    self.dc_only[blk_idx] = cdcs[comp][i] != 0;
+                    idct(&mut self.coeffs[blk_idx], SVQ3_CHROMA_QUANT[sstate.q as usize], true);
+                }
+            }
+        }
+        
+        Ok(())
+    }
+    fn do_mc_p(&mut self, br: &mut BitReader, mb_type: usize, sstate: &mut SState, dframe: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
+        if mb_type == 0 {
+            self.mvi.fill(self.mb_x, self.mb_y, true, ZERO_MV);
+            if let Some(ref_frm) = self.ipbs.get_lastref() {
+                mc_part(dframe, ref_frm, &mut self.ebuf, self.mb_x * 16, self.mb_y * 16, 4, 4, ZERO_MV, 0, HALFPEL_INTERP_FUNCS);
+            }
+            return Ok(());
+        }
+        let mc_mode = if self.use_tpel && br.read_bool()? != self.use_hpel {
+                MCMode::Thirdpel
+            } else if self.use_hpel && br.read_bool()? != self.use_tpel {
+                MCMode::Halfpel
+            } else {
+                MCMode::Pixel
+            };
+        let (bw, bh) = SVQ3_PART_SIZES[mb_type as usize];
+        let bw = (bw >> 2) as usize;
+        let bh = (bh >> 2) as usize;
+
+        let mut avail = [false; 6 * 5];
+        avail[0] = sstate.has_tl;
+        if sstate.has_top {
+            avail[1] = true;
+            avail[2] = true;
+            avail[3] = true;
+            avail[4] = true;
+        }
+        avail[5] = sstate.has_tr;
+        if sstate.has_left {
+            avail[6 * 1] = true;
+            avail[6 * 2] = true;
+            avail[6 * 3] = true;
+            avail[6 * 4] = true;
+        }
+
+        let dir = true; //forward
+        for y in (0..16).step_by(bh * 4) {
+            for x in (0..16).step_by(bw * 4) {
+                let mv_x = x >> 2;
+                let mv_y = y >> 2;
+                let xpos = self.mb_x * 16 + x;
+                let ypos = self.mb_y * 16 + y;
+
+                let avail_idx = mv_x + 1 + (mv_y + 1) * 6;
+                let mut pred_mv = self.mvi.pred_mv_part(self.mb_x * 4 + mv_x, self.mb_y * 4 + mv_y, bw, dir, avail[avail_idx - 6], avail[avail_idx - 1], avail[avail_idx - 6 + bw], avail[avail_idx - 6 - 1]);
+                pred_mv.x = pred_mv.x.max(-6 * (xpos as i16)).min(6 * ((((self.width  + 15) & !15) - xpos - bw * 4) as i16));
+                pred_mv.y = pred_mv.y.max(-6 * (ypos as i16)).min(6 * ((((self.height + 15) & !15) - ypos - bh * 4) as i16));
+
+                for j in 0..bh {
+                    for i in 0..bw {
+                        avail[avail_idx + i + j * 6] = true;
+                    }
+                }
+
+                let dmv = read_mv(br)?;
+                let (mv, mode, ifuncs) = add_mv(pred_mv, dmv, mc_mode);
+                self.mvi.fill_part(self.mb_x * 4 + mv_x, self.mb_y * 4 + mv_y, dir, bw, bh, mv);
+                if let Some(ref_frm) = self.ipbs.get_lastref() {
+                    mc_part(dframe, ref_frm, &mut self.ebuf, xpos, ypos, bw, bh, mv, mode, ifuncs);
+                }
+            }
+        }
+        Ok(())
+    }
+    fn do_mc_direct(&mut self, sstate: &mut SState, dframe: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
+        let mut ref_mbt = self.mbtypes[self.mb_x + self.mb_y * self.mb_w];
+        if ref_mbt >= 8 {
+            ref_mbt = 0;
+        }
+        let (bw, bh) = SVQ3_PART_SIZES[ref_mbt as usize];
+        let bw = (bw >> 2) as usize;
+        let bh = (bh >> 2) as usize;
+        let mut aframe = NASimpleVideoFrame::from_video_buf(&mut self.avg_buf).unwrap();
+        if let (Some(fwd_ref), Some(bwd_ref)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
+            for y in (0..16).step_by(bh * 4) {
+                for x in (0..16).step_by(bw * 4) {
+                    let mv = self.ref_mvi.get_mv(self.mb_x * 4 + x / 4, self.mb_y * 4 + y / 4, true);
+                    let (fwd_pred, bwd_pred) = scale_mv(mv, sstate.trb, sstate.trd);
+                    let (fmv, fmode, _) = add_mv(fwd_pred, ZERO_MV, MCMode::Halfpel);
+                    let (bmv, bmode, _) = add_mv(bwd_pred, ZERO_MV, MCMode::Halfpel);
+                    self.mvi.fill_part(self.mb_x * 4 + x / 4, self.mb_y * 4 + y / 4, true,  bw, bh, fmv);
+                    self.mvi.fill_part(self.mb_x * 4 + x / 4, self.mb_y * 4 + y / 4, false, bw, bh, bmv);
+
+                    let xoff = self.mb_x * 16 + x;
+                    let yoff = self.mb_y * 16 + y;
+                    mc_part(dframe, fwd_ref.clone(), &mut self.ebuf, xoff, yoff, bw, bh, fmv, fmode, HALFPEL_INTERP_FUNCS);
+
+                    let amv = MV { x: bmv.x + (xoff as i16) * 6, y: bmv.y + (yoff as i16) * 6 };
+                    mc_part(&mut aframe, bwd_ref.clone(), &mut self.ebuf, 0, 0, bw, bh, amv, bmode, HALFPEL_INTERP_FUNCS);
+
+                    let dstride = dframe.stride[0];
+                    let dst = &mut dframe.data[dframe.offset[0] + xoff + yoff * dstride..];
+                    let src = &aframe.data;
+                    let sstride = aframe.stride[0];
+                    avg(dst, dstride, src, sstride, bw * 4, bh * 4);
+
+                    let dstride = dframe.stride[1];
+                    let dst = &mut dframe.data[dframe.offset[1] + xoff / 2 + yoff / 2 * dstride..];
+                    let sstride = aframe.stride[1];
+                    avg(dst, dstride, &src[aframe.offset[1]..], sstride, bw * 2, bh * 2);
+
+                    let dstride = dframe.stride[2];
+                    let dst = &mut dframe.data[dframe.offset[2] + xoff / 2 + yoff / 2 * dstride..];
+                    let sstride = aframe.stride[2];
+                    avg(dst, dstride, &src[aframe.offset[2]..], sstride, bw * 2, bh * 2);
+                }
+            }
+        }
+        Ok(())
+    }
+    fn do_mc_b(&mut self, br: &mut BitReader, mb_type: usize, sstate: &mut SState, dframe: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
+        let mc_mode = if self.use_tpel && br.read_bool()? != self.use_hpel {
+                MCMode::Thirdpel
+            } else if self.use_hpel && br.read_bool()? != self.use_tpel {
+                MCMode::Halfpel
+            } else {
+                MCMode::Pixel
+            };
+        let fwd_pred = self.mvi.pred_mv_part(self.mb_x * 4, self.mb_y * 4, 4, true,  sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl);
+        let bwd_pred = self.mvi.pred_mv_part(self.mb_x * 4, self.mb_y * 4, 4, false, sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl);
+        let (fdmv, bdmv) = match mb_type {
+                1 => {
+                    let dmv             = read_mv(br)?;
+                    (dmv, ZERO_MV)
+                },
+                2 => {
+                    let dmv             = read_mv(br)?;
+                    (ZERO_MV, dmv)
+                },
+                3 => {
+                    let fdmv            = read_mv(br)?;
+                    let bdmv            = read_mv(br)?;
+                    (fdmv, bdmv)
+                },
+                _ => unreachable!(),
+            };
+        let (fmv, fmode, ifuncs) = add_mv(fwd_pred, fdmv, mc_mode);
+        let (bmv, bmode, _)      = add_mv(bwd_pred, bdmv, mc_mode);
+        let has_fwd = mb_type != 2;
+        let has_bwd = mb_type != 1;
+        if has_fwd {
+            self.mvi.fill(self.mb_x, self.mb_y, true, fmv);
+        }
+        if has_bwd {
+            self.mvi.fill(self.mb_x, self.mb_y, false, bmv);
+        }
+        let refframe = if has_fwd { self.ipbs.get_b_fwdref() } else { self.ipbs.get_b_bwdref() };
+        if let Some(ref_buf) = refframe {
+            let (mv, mode) = if has_fwd { (fmv, fmode) } else { (bmv, bmode) };
+            mc_part(dframe, ref_buf, &mut self.ebuf, self.mb_x * 16, self.mb_y * 16, 4, 4, mv, mode, ifuncs);
+        }
+        if let (Some(bwd_ref), true, true) = (self.ipbs.get_b_bwdref(), has_fwd, has_bwd) {
+            let mut aframe = NASimpleVideoFrame::from_video_buf(&mut self.avg_buf).unwrap();
+            let amv = MV { x: bmv.x + (self.mb_x as i16) * 16 * 6, y: bmv.y + (self.mb_y as i16) * 16 * 6 };
+            mc_part(&mut aframe, bwd_ref.clone(), &mut self.ebuf, 0, 0, 4, 4, amv, bmode, ifuncs);
+
+            let dstride = dframe.stride[0];
+            let dst = &mut dframe.data[dframe.offset[0] + self.mb_x * 16 + self.mb_y * 16 * dstride..];
+            let src = self.avg_buf.get_data();
+            let sstride = self.avg_buf.get_stride(0);
+            avg(dst, dstride, src, sstride, 16, 16);
+
+            let dstride = dframe.stride[1];
+            let dst = &mut dframe.data[dframe.offset[1] + self.mb_x * 8 + self.mb_y * 8 * dstride..];
+            let sstride = self.avg_buf.get_stride(1);
+            avg(dst, dstride, &src[self.avg_buf.get_offset(1)..], sstride, 8, 8);
+
+            let dstride = dframe.stride[2];
+            let dst = &mut dframe.data[dframe.offset[2] + self.mb_x * 8 + self.mb_y * 8 * dstride..];
+            let sstride = self.avg_buf.get_stride(2);
+            avg(dst, dstride, &src[self.avg_buf.get_offset(2)..], sstride, 8, 8);
+        }
+        Ok(())
+    }
+    fn decode_inter_block(&mut self, br: &mut BitReader, mb_type: usize, sstate: &mut SState, hdr: &SVQ3Header, dframe: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
+        const INTER_CBP: [u8; 48] = [
+             0, 16,  1,  2,  4,  8, 32,  3,  5, 10, 12, 15, 47,  7, 11, 13,
+            14,  6,  9, 31, 35, 37, 42, 44, 33, 34, 36, 40, 39, 43, 45, 46,
+            17, 18, 20, 24, 19, 21, 26, 28, 23, 27, 29, 30, 22, 25, 38, 41
+        ];
+        if hdr.ftype == FrameType::P {
+            self.do_mc_p(br, mb_type, sstate, dframe)?;
+            if mb_type == 0 {
+                return Ok(());
+            }
+        } else if mb_type != 0 {
+            self.do_mc_b(br, mb_type, sstate, dframe)?;
+        } else {
+            self.do_mc_direct(sstate, dframe)?;
+        }
+
+        let idx                     = br.read_code(UintCodeType::Gamma)? as usize;
+        validate!(idx < INTER_CBP.len());
+        let cbp = INTER_CBP[idx];
+
+        if hdr.dquant && cbp != 0 {
+            let dq                      = br.read_code_signed(IntCodeType::Gamma)?;
+            let new_q = i32::from(sstate.q) + dq;
+            validate!(new_q >= 0 && new_q < 32);
+            sstate.q = new_q as u8;
+        }
+        for sb in 0..4 {
+            if ((cbp >> sb) & 1) == 0 { continue; }
+            for b in 0..4 {
+                let blk_idx = (sb & 1) * 2 + (sb >> 1) * 8 + (b & 1) + (b >> 1) * 4;
+                self.coded[blk_idx] = decode_block(br, &mut self.coeffs[blk_idx], 0, false)?;
+                if self.coded[blk_idx] {
+                    idct_dc_coeffs(&mut self.coeffs[blk_idx], sstate.q);
+                }
+            }
+        }
+        if (cbp & 0x30) != 0 {
+            let mut u_dc = decode_chroma_dc(br)?;
+            let mut v_dc = decode_chroma_dc(br)?;
+            chroma_transform(&mut u_dc);
+            chroma_transform(&mut v_dc);
+
+            let cdcs = [u_dc, v_dc];
+            if (cbp & 0x20) != 0 {
+                for comp in 0..2 {
+                    for i in 0..4 {
+                        let blk_idx = 16 + comp * 4 + i;
+                        self.coded[blk_idx] = decode_block(br, &mut self.coeffs[blk_idx], 1, false)?;
+                    }
+                }
+            }
+            for comp in 0..2 {
+                for i in 0..4 {
+                    let blk_idx = 16 + comp * 4 + i;
+                    self.coeffs[blk_idx][0] = cdcs[comp][i];
+                    self.dc_only[blk_idx] = cdcs[comp][i] != 0;
+                    idct(&mut self.coeffs[blk_idx], SVQ3_CHROMA_QUANT[sstate.q as usize], true);
+                }
+            }
+        }
+
+        Ok(())
+    }
+    fn put_intra4x4(&self, dframe: &mut NASimpleVideoFrame<u8>, sstate: &SState) {
+        let dst = &mut dframe.data[0..];
+        let stride = dframe.stride[0];
+        let mut doff = dframe.offset[0] + self.mb_x * 16 + self.mb_y * 16 * stride;
+        for y in 0..4 {
+            for x in 0..4 {
+                let im = self.imode.get_pred4_type(x, y, sstate.has_top, sstate.has_left);
+                let noright = (self.mb_x == self.mb_w - 1) && (x == 3);
+                let has_top = sstate.has_top || (y > 0);
+                let topright: [u8; 4] = if (noright && sstate.has_top && y == 0) || (x == 3 && y > 0) {
+                        let i = doff + x * 4 - stride;
+                        [dst[i + 3], dst[i + 3], dst[i + 3], dst[i + 3]]
+                    } else if has_top {
+                        let i = doff + x * 4 - stride;
+                        [dst[i + 4], dst[i + 5], dst[i + 6], dst[i + 7]]
+                    } else {
+                        [0; 4]
+                    };
+                IPRED_FUNCS4X4[im as usize](dst, doff + x * 4, stride, &topright);
+                let blk_idx = x + y * 4;
+                if self.dc_only[blk_idx] || self.coded[blk_idx] {
+                    add_coeffs(dst, doff + x * 4, stride, &self.coeffs[blk_idx]);
+                }
+            }
+            doff += stride * 4;
+        }
+        let im8 = self.imode.get_pred8_type(sstate.has_top, sstate.has_left);
+        for comp in 1..3 {
+            let stride = dframe.stride[comp];
+            let mut doff = dframe.offset[comp] + self.mb_x * 8 + self.mb_y * 8 * stride;
+            IPRED_FUNCS8X8[im8 as usize](dst, doff, stride);
+            for y in 0..2 {
+                for x in 0..2 {
+                    let blk_idx = 16 + (comp - 1) * 4 + x + y * 2;
+                    if self.dc_only[blk_idx] || self.coded[blk_idx] {
+                        add_coeffs(dst, doff + x * 4, stride, &self.coeffs[blk_idx]);
+                    }
+                }
+                doff += stride * 4;
+            }
+        }
+    }
+    fn put_residue(&self, dframe: &mut NASimpleVideoFrame<u8>) {
+        let dst = &mut dframe.data[0..];
+        let stride = dframe.stride[0];
+        let mut doff = dframe.offset[0] + self.mb_x * 16 + self.mb_y * 16 * stride;
+        for y in 0..4 {
+            for x in 0..4 {
+                let blk_idx = x + y * 4;
+                if self.dc_only[blk_idx] || self.coded[blk_idx] {
+                    add_coeffs(dst, doff + x * 4, stride, &self.coeffs[blk_idx]);
+                }
+            }
+            doff += stride * 4;
+        }
+        for comp in 1..3 {
+            let stride = dframe.stride[comp];
+            let mut doff = dframe.offset[comp] + self.mb_x * 8 + self.mb_y * 8 * stride;
+            for y in 0..2 {
+                for x in 0..2 {
+                    let blk_idx = 16 + (comp - 1) * 4 + x + y * 2;
+                    if self.dc_only[blk_idx] || self.coded[blk_idx] {
+                        add_coeffs(dst, doff + x * 4, stride, &self.coeffs[blk_idx]);
+                    }
+                }
+                doff += stride * 4;
+            }
+        }
+    }
+    fn decode_slice(&mut self, br: &mut BitReader, hdr: &SVQ3Header, dframe: &mut NASimpleVideoFrame<u8>) -> DecoderResult<()> {
+        let mut mb_idx = self.mb_x + self.mb_y * self.mb_w;
+        let mbs = self.mb_w * self.mb_h;
+        let mut sstate = SState::default();
+        sstate.q = hdr.quant;
+        if hdr.ftype == FrameType::B {
+            sstate.trd = self.ts_bwd.wrapping_sub(self.ts_fwd).max(1);
+            sstate.trb = hdr.ts.wrapping_sub(self.ts_fwd).max(1);
+        }
+        let start_idx = mb_idx;
+        self.imode.reset();
+        while mb_idx < mbs {
+            sstate.has_top = mb_idx - start_idx >= self.mb_w;
+            if sstate.has_top {
+                sstate.has_tl = sstate.has_left && mb_idx - start_idx + 1 > self.mb_w;
+                sstate.has_tr = self.mb_x + 1 < self.mb_w && mb_idx - start_idx >= self.mb_w - 1;
+            } else {
+                sstate.has_tl = false;
+                sstate.has_tr = false;
+            }
+
+            if br.left() < 8 {
+                if (br.tell() & 7) == 0 && br.peek(8) == 0 {
+                    return Ok(());
+                }
+            }
+            let mut mb_type             = br.read_code(UintCodeType::Gamma)? as usize;
+            if hdr.ftype == FrameType::I {
+                mb_type += 8;
+            }
+            if hdr.ftype == FrameType::B && mb_type >= 4 {
+                mb_type += 4;
+            }
+            validate!(mb_type <= 33);
+            self.imode.set_mb_x(self.mb_x);
+            self.coeffs = [[0; 16]; 25];
+            self.coded = [false; 24];
+            self.dc_only = [false; 24];
+            if hdr.ftype != FrameType::B {
+                self.mbtypes[mb_idx] = mb_type as u8;
+            }
+            if mb_type < 8 {
+                validate!(hdr.ftype != FrameType::I);
+                self.imode.fill_block(2);
+                self.decode_inter_block(br, mb_type, &mut sstate, hdr, dframe)?;
+                self.put_residue(dframe);
+            } else {
+                self.decode_intra_block(br, mb_type, &mut sstate, hdr)?;
+                let is_4x4 = mb_type == 8 || mb_type == 33;
+                if is_4x4 {
+                    self.put_intra4x4(dframe, &sstate);
+                } else {
+                    let im16 = self.imode.get_pred16_type(sstate.has_top, sstate.has_left);
+                    let stride = dframe.stride[0];
+                    let doff = dframe.offset[0] + self.mb_x * 16 + self.mb_y * 16 * stride;
+                    IPRED_FUNCS16X16[im16 as usize](dframe.data, doff, stride);
+                    let im8 = self.imode.get_pred8_type(sstate.has_top, sstate.has_left);
+                    for comp in 1..3 {
+                        let stride = dframe.stride[comp];
+                        let doff = dframe.offset[comp] + self.mb_x * 8 + self.mb_y * 8 * stride;
+                        IPRED_FUNCS8X8[im8 as usize](dframe.data, doff, stride);
+                    }
+                    self.put_residue(dframe);
+                }
+                self.mvi.fill(self.mb_x, self.mb_y, true,  ZERO_MV);
+                self.mvi.fill(self.mb_x, self.mb_y, false, ZERO_MV);
+            }
+            sstate.has_left = true;
+            self.mb_x += 1;
+            if self.mb_x == self.mb_w {
+                self.mb_x = 0;
+                self.mb_y += 1;
+                sstate.has_left = false;
+                self.imode.update();
+            }
+            mb_idx += 1;
+        }
+        Ok(())
+    }
+}
+
+const FRAME_SIZES: [(usize, usize); 7] = [
+    (160, 120), (128,  96), (176, 144), (352, 288),
+    (704, 576), (240, 180), (320, 240)
+];
+const FRAME_TYPES: [FrameType; 3] = [ FrameType::P, FrameType::B, FrameType::I ];
+
+impl NADecoder for SVQ3Decoder {
+    fn init(&mut self, supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+            self.width  = vinfo.get_width();
+            self.height = vinfo.get_height();
+            if let Some(ref edata) = info.get_extradata() {
+                let mut start = edata.len();
+                for i in 0..edata.len() - 9 {
+                    if &edata[i..][..4] == b"SEQH" {
+                        let size = read_u32be(&edata[i + 4..])? as usize;
+                        validate!(i + 8 + size <= edata.len());
+                        start = i + 8;
+                        break;
+                    }
+                }
+                if start < edata.len() {
+                    self.parse_sequence_header(&edata[start..])?;
+                } else {
+                    return Err(DecoderError::InvalidData);
+                }
+            } else {
+                return Err(DecoderError::InvalidData);
+            }
+            let myinfo = NAVideoInfo::new(self.width, self.height, false, YUV420_FORMAT);
+            self.info = NACodecInfo::new_ref(info.get_name(), NACodecTypeInfo::Video(myinfo), info.get_extradata()).into_ref();
+            supp.pool_u8.set_dec_bufs(3);
+            supp.pool_u8.prealloc_video(myinfo, 4)?;
+
+            self.mb_w = (self.width  + 15) >> 4;
+            self.mb_h = (self.height + 15) >> 4;
+            self.imode = IntraModeState::new(self.mb_w);
+
+            Ok(())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let src = pkt.get_buffer();
+        validate!(src.len() > 0);
+
+        if src.len() == 1 {
+            validate!(src[0] == 0xFF);
+            let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::None);
+            frm.set_keyframe(false);
+            frm.set_frame_type(FrameType::Skip);
+            return Ok(frm.into_ref());
+        }
+
+        let slice_mode = src[0] & 0x9F;
+        validate!(slice_mode == 1 || slice_mode == 2);
+        let mut slice_len = self.prepare_slice_buffer(src.as_slice())?;
+
+        let mut br = BitReader::new(&self.slice_buf, BitReaderMode::BE);
+        let frame_hdr = self.parse_slice_header(&mut br, slice_mode)?;
+
+        let ret = supp.pool_u8.get_free();
+        if ret.is_none() {
+            return Err(DecoderError::AllocError);
+        }
+
+        let mut buf = ret.unwrap();
+        let mut dframe = NASimpleVideoFrame::from_video_buf(&mut buf).unwrap();
+
+        match frame_hdr.ftype {
+            FrameType::I => {
+            },
+            FrameType::P => {
+                if self.ipbs.get_lastref().is_none() {
+                    return Err(DecoderError::MissingReference);
+                }
+            },
+            FrameType::B => {
+                if self.ipbs.get_b_fwdref().is_none() || self.ipbs.get_b_bwdref().is_none() {
+                    return Err(DecoderError::MissingReference);
+                }
+            },
+
+            _ => unreachable!(),
+        }
+
+        self.mb_x = 0;
+        self.mb_y = 0;
+
+        self.mvi.resize(self.mb_w, self.mb_h);
+        if frame_hdr.ftype != FrameType::B {
+            self.mbtypes.resize(self.mb_w * self.mb_h, 0);
+        }
+
+        let mut slice_prepared = true;
+        let mut off = 0;
+        while off < src.len() {
+            if src[off] == 0xFF { break; }
+
+            let slice_mode = src[off] & 0x9F;
+            validate!(slice_mode == 1 || slice_mode == 2);
+            if !slice_prepared {
+                slice_len = self.prepare_slice_buffer(&src[off..])?;
+            }
+            let mut sbuf = Vec::new();
+            std::mem::swap(&mut sbuf, &mut self.slice_buf);
+            let mut br = BitReader::new(sbuf.as_slice(), BitReaderMode::BE);
+            let ret = self.parse_slice_header(&mut br, slice_mode);
+            if let Err(err) = ret {
+                std::mem::swap(&mut sbuf, &mut self.slice_buf);
+                return Err(err);
+            }
+            let hdr = ret.unwrap();
+            if hdr.ftype != frame_hdr.ftype || hdr.ts != frame_hdr.ts {
+                std::mem::swap(&mut sbuf, &mut self.slice_buf);
+                return Err(DecoderError::InvalidData);
+            }
+            let ret = self.decode_slice(&mut br, &hdr, &mut dframe);
+            std::mem::swap(&mut sbuf, &mut self.slice_buf);
+            if let Err(err) = ret {
+                return Err(err);
+            }
+            slice_prepared = false;
+            off += slice_len;
+        }
+
+        validate!(self.mb_x == 0 && self.mb_y == self.mb_h);
+
+        if frame_hdr.ftype != FrameType::B {
+            self.ipbs.add_frame(buf.clone());
+            std::mem::swap(&mut self.mvi, &mut self.ref_mvi);
+            self.ts_fwd = self.ts_bwd;
+            self.ts_bwd = frame_hdr.ts;
+
+            self.pts_base = pkt.get_pts().unwrap_or(0);
+            self.ts_base = frame_hdr.ts;
+        }
+
+        let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
+        frm.set_keyframe(frame_hdr.ftype == FrameType::I);
+        frm.set_frame_type(frame_hdr.ftype);
+        if !self.no_bframes && frm.get_pts().is_some() {
+            let pts = self.pts_base - u64::from(self.ts_base.wrapping_sub(frame_hdr.ts));
+            frm.set_pts(Some(pts));
+        }
+        Ok(frm.into_ref())
+    }
+    fn flush(&mut self) {
+        self.ipbs.clear();
+        self.ts_fwd = 0;
+        self.ts_bwd = 0;
+    }
+}
+
+impl NAOptionHandler for SVQ3Decoder {
+    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(SVQ3Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::qt_register_all_codecs;
+    use nihav_commonfmt::generic_register_all_demuxers;
+    #[test]
+    fn test_svq3() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        generic_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        qt_register_all_codecs(&mut dec_reg);
+
+//let file = "assets/QT/cristinreel.mov";
+//let file = "assets/QT/broken_sword_Large.mov";
+//test_file_decoding("mov", file, Some(264), true, false, Some("svq3"), &dmx_reg, &dec_reg);
+//panic!("end");
+        test_decoding("mov", "sorenson-video3", "assets/QT/broken_sword_Large.mov", Some(40), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5Frames(vec![
+                        [0x16924d18, 0xccc5a0b4, 0xc2bb9412, 0x93d41f10],
+                        [0x84cccf62, 0x0762a61c, 0xe0b1d369, 0x211f066e],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0x8f9e157e, 0xb61f5864, 0x49cc29a7, 0xa2b648a4],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xb7a27005, 0xd22f8f4d, 0x8414d8e2, 0x84be8fda],
+                        [0xad96c999, 0x89bfe564, 0x476f918a, 0xf89bb023],
+                        [0x1f40cce7, 0xcccc68b3, 0x2a0b28b1, 0x3210675c],
+                        [0x3165e832, 0xcb7dad5b, 0x295983fa, 0x270acdcd],
+                        [0x54b88d2a, 0x97c5ad60, 0x9cca1823, 0x458566e6],
+                        [0xbdd02a56, 0x7ee24530, 0x32262d19, 0x2f3c8237],
+                        [0x4e898806, 0x85fb7504, 0x19da4747, 0x00c55a0e],
+                        [0x5899e1f5, 0x667fbc86, 0xcbeeff49, 0x6ac996b9],
+                        [0x1b640dd6, 0xa999c0f6, 0x57cb9bed, 0xf0265669],
+                        [0x3cee4540, 0x35ce897b, 0x9db825aa, 0xd6204c2c],
+                        [0x459bfa2f, 0x451555e6, 0x08681f32, 0xf56cdc05],
+                        [0x78018c23, 0x333f1892, 0xabab4889, 0x3e3cf020],
+                        [0x2a24d296, 0xc572a5fe, 0x0af6a85a, 0x5721bfc4],
+                        [0xdf354969, 0xfbf01155, 0xa1e6d53a, 0x49334823],
+                        [0x5e493eb2, 0xc92258b8, 0xcec5e684, 0x92bd0f3c],
+                        [0x5bf8ea79, 0xb363c077, 0x05c461a3, 0xa065da2c]]));
+    }
+}
+
+const SVQ3_INTRA_ANGLE: [i8; 4] = [ 0, 2, 1, 3 ];
+const SVQ3_INTRA_CBP: [u8; 6] = [ 0x00, 0x10, 0x20, 0x0F, 0x1F, 0x2F ];
+
+const SVQ3_INTRA4_PAIRS: [[u8; 2]; 25] = [
+    [ 0, 0 ],
+    [ 1, 0 ], [ 0, 1 ],
+    [ 0, 2 ], [ 1, 1 ], [ 2, 0 ],
+    [ 3, 0 ], [ 2, 1 ], [ 1, 2 ], [ 0, 3 ],
+    [ 0, 4 ], [ 1, 3 ], [ 2, 2 ], [ 3, 1 ], [ 4, 0 ],
+    [ 4, 1 ], [ 3, 2 ], [ 2, 3 ], [ 1, 4 ],
+    [ 2, 4 ], [ 3, 3 ], [ 4, 2 ],
+    [ 4, 3 ], [ 3, 4 ],
+    [ 4, 4 ]
+];
+
+const SVQ3_INTRA4_CTX_PRED: [[[i8; 5]; 6]; 6] = [
+  [
+    [ 2, -1, -1, -1, -1 ], [ 2, 1, -1, -1, -1 ], [ 1, 2, -1, -1, -1 ],
+    [ 2,  1, -1, -1, -1 ], [ 1, 2, -1, -1, -1 ], [ 1, 2, -1, -1, -1 ]
+  ], [
+    [ 0,  2, -1, -1, -1 ], [ 0, 2,  1,  4,  3 ], [ 0, 1,  2,  4,  3 ],
+    [ 0,  2,  1,  4,  3 ], [ 2, 0,  1,  3,  4 ], [ 0, 4,  2,  1,  3 ]
+  ], [
+    [ 2,  0, -1, -1, -1 ], [ 2, 1,  0,  4,  3 ], [ 1, 2,  4,  0,  3 ],
+    [ 2,  1,  0,  4,  3 ], [ 2, 1,  4,  3,  0 ], [ 1, 2,  4,  0,  3 ]
+  ], [
+    [ 2,  0, -1, -1, -1 ], [ 2, 0,  1,  4,  3 ], [ 1, 2,  0,  4,  3 ],
+    [ 2,  1,  0,  4,  3 ], [ 2, 1,  3,  4,  0 ], [ 2, 4,  1,  0,  3 ]
+  ], [
+    [ 0,  2, -1, -1, -1 ], [ 0, 2,  1,  3,  4 ], [ 1, 2,  3,  0,  4 ],
+    [ 2,  0,  1,  3,  4 ], [ 2, 1,  3,  0,  4 ], [ 2, 0,  4,  3,  1 ]
+  ], [
+    [ 0,  2, -1, -1, -1 ], [ 0, 2,  4,  1,  3 ], [ 1, 4,  2,  0,  3 ],
+    [ 4,  2,  0,  1,  3 ], [ 2, 0,  1,  4,  3 ], [ 4, 2,  1,  0,  3 ]
+  ]
+];
+
+const SVQ3_PART_SIZES: [(u8, u8); 8] = [
+    (16, 16), (16, 16), (8, 16), (16, 8), (8, 8), (4, 8), (8, 4), (4, 4)
+];
+
+const SVQ3_CHROMA_QUANT: [u8; 32] = [
+     0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+    16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25
+];
diff --git a/nihav-qt/src/codecs/svq3dsp.rs b/nihav-qt/src/codecs/svq3dsp.rs
new file mode 100644 (file)
index 0000000..0c45402
--- /dev/null
@@ -0,0 +1,620 @@
+use nihav_codec_support::codecs::blockdsp::*;
+
+#[allow(dead_code)]
+#[derive(Debug,Clone,Copy)]
+pub enum PredType4x4 {
+    Ver,
+    Hor,
+    DC,
+    DiagDownLeft,
+    DiagDownRight,
+    VerRight,
+    HorDown,
+    VerLeft,
+    HorUp,
+    LeftDC,
+    TopDC,
+    DC128,
+}
+
+#[allow(dead_code)]
+#[derive(Debug,Clone,Copy)]
+pub enum PredType8x8 {
+    DC,
+    Hor,
+    Ver,
+    Plane,
+    LeftDC,
+    TopDC,
+    DC128
+}
+
+pub const INTRA_PRED16: [PredType8x8; 4] = [
+    PredType8x8::DC, PredType8x8::Hor, PredType8x8::Ver, PredType8x8::Plane
+];
+pub const INTRA_PRED4: [PredType4x4; 9] = [
+    PredType4x4::Ver, PredType4x4::Hor, PredType4x4::DC,
+    PredType4x4::DiagDownLeft, PredType4x4::DiagDownRight,
+    PredType4x4::VerRight, PredType4x4::HorDown,
+    PredType4x4::VerLeft, PredType4x4::HorUp
+];
+
+
+const SVQ3_QUANTS: [i32; 32] = [
+     3881,  4351,  4890,  5481,   6154,   6914,   7761,   8718,
+     9781, 10987, 12339, 13828,  15523,  17435,  19561,  21873,
+    24552, 27656, 30847, 34870,  38807,  43747,  49103,  54683,
+    61694, 68745, 77615, 89113, 100253, 109366, 126635, 141533
+];
+
+pub fn chroma_transform(blk: &mut [i16; 4]) {
+    let t0 = blk[0] + blk[2];
+    let t1 = blk[0] - blk[2];
+    let t2 = blk[1] + blk[3];
+    let t3 = blk[1] - blk[3];
+    blk[0] = t0 + t2;
+    blk[1] = t0 - t2;
+    blk[2] = t1 + t3;
+    blk[3] = t1 - t3;
+}
+
+pub fn idct_dc_coeffs(blk: &mut [i16; 16], q: u8) {
+    let quant = SVQ3_QUANTS[q as usize];
+    let mut tmp = [0i32; 16];
+    for (src, dst) in blk.chunks(4).zip(tmp.chunks_mut(4)) {
+        let s0 = i32::from(src[0]);
+        let s1 = i32::from(src[1]);
+        let s2 = i32::from(src[2]);
+        let s3 = i32::from(src[3]);
+        let t0 = 13 * (s0 + s2);
+        let t1 = 13 * (s0 - s2);
+        let t2 = 17 * s1 +  7 * s3;
+        let t3 =  7 * s1 - 17 * s3;
+        dst[0] = t0 + t2;
+        dst[1] = t1 + t3;
+        dst[2] = t1 - t3;
+        dst[3] = t0 - t2;
+    }
+    for i in 0..4 {
+        let s0 = tmp[i];
+        let s1 = tmp[i + 4];
+        let s2 = tmp[i + 4 * 2];
+        let s3 = tmp[i + 4 * 3];
+        let t0 = 13 * (s0 + s2);
+        let t1 = 13 * (s0 - s2);
+        let t2 = 17 * s1 +  7 * s3;
+        let t3 =  7 * s1 - 17 * s3;
+        blk[i]         = (((t0 + t2).wrapping_mul(quant) + (1 << 19)) >> 20) as i16;
+        blk[i + 4]     = (((t1 + t3).wrapping_mul(quant) + (1 << 19)) >> 20) as i16;
+        blk[i + 4 * 2] = (((t1 - t3).wrapping_mul(quant) + (1 << 19)) >> 20) as i16;
+        blk[i + 4 * 3] = (((t0 - t2).wrapping_mul(quant) + (1 << 19)) >> 20) as i16;
+    }
+}
+
+pub fn idct(blk: &mut [i16; 16], q: u8, chroma: bool) {
+    let quant = SVQ3_QUANTS[q as usize];
+    let mut tmp = [0i32; 16];
+    let dc = 13 * 13 * if chroma { quant * i32::from(blk[0]) / 2 } else { i32::from(blk[0]) * 1538 };
+    blk[0] = 0;
+    for (src, dst) in blk.chunks(4).zip(tmp.chunks_mut(4)) {
+        let s0 = i32::from(src[0]);
+        let s1 = i32::from(src[1]);
+        let s2 = i32::from(src[2]);
+        let s3 = i32::from(src[3]);
+        let t0 = 13 * (s0 + s2);
+        let t1 = 13 * (s0 - s2);
+        let t2 = 17 * s1 +  7 * s3;
+        let t3 =  7 * s1 - 17 * s3;
+        dst[0] = t0 + t2;
+        dst[1] = t1 + t3;
+        dst[2] = t1 - t3;
+        dst[3] = t0 - t2;
+    }
+    for i in 0..4 {
+        let s0 = tmp[i];
+        let s1 = tmp[i + 4];
+        let s2 = tmp[i + 4 * 2];
+        let s3 = tmp[i + 4 * 3];
+        let t0 = 13 * (s0 + s2);
+        let t1 = 13 * (s0 - s2);
+        let t2 = 17 * s1 +  7 * s3;
+        let t3 =  7 * s1 - 17 * s3;
+        blk[i]         = (((t0 + t2).wrapping_mul(quant) + dc + (1 << 19)) >> 20) as i16;
+        blk[i + 4]     = (((t1 + t3).wrapping_mul(quant) + dc + (1 << 19)) >> 20) as i16;
+        blk[i + 4 * 2] = (((t1 - t3).wrapping_mul(quant) + dc + (1 << 19)) >> 20) as i16;
+        blk[i + 4 * 3] = (((t0 - t2).wrapping_mul(quant) + dc + (1 << 19)) >> 20) as i16;
+    }
+}
+
+pub fn add_coeffs(dst: &mut [u8], offset: usize, stride: usize, coeffs: &[i16]) {
+    let out = &mut dst[offset..][..stride * 3 + 4];
+    for (line, src) in out.chunks_mut(stride).take(4).zip(coeffs.chunks(4)) {
+        for (dst, src) in line.iter_mut().take(4).zip(src.iter()) {
+            *dst = (i32::from(*dst) + i32::from(*src)).max(0).min(255) as u8;
+        }
+    }
+}
+
+pub fn avg(dst: &mut [u8], dstride: usize,
+           src: &[u8], sstride: usize, bw: usize, bh: usize) {
+   for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(bh) {
+        for (dst, src) in dline.iter_mut().zip(sline.iter()).take(bw) {
+            *dst = ((u16::from(*dst) + u16::from(*src) + 1) >> 1) as u8;
+        }
+    }
+}
+
+fn clip8(val: i16) -> u8 { val.max(0).min(255) as u8 }
+
+fn ipred_dc128(buf: &mut [u8], mut idx: usize, stride: usize, bsize: usize) {
+    for _ in 0..bsize {
+        for x in 0..bsize { buf[idx + x] = 128; }
+        idx += stride;
+    }
+}
+fn ipred_ver(buf: &mut [u8], mut idx: usize, stride: usize, bsize: usize) {
+    let oidx = idx - stride;
+    for _ in 0..bsize {
+        for x in 0..bsize { buf[idx + x] = buf[oidx + x]; }
+        idx += stride;
+    }
+}
+fn ipred_hor(buf: &mut [u8], mut idx: usize, stride: usize, bsize: usize) {
+    for _ in 0..bsize {
+        for x in 0..bsize { buf[idx + x] = buf[idx - 1]; }
+        idx += stride;
+    }
+}
+fn ipred_dc(buf: &mut [u8], mut idx: usize, stride: usize, bsize: usize, shift: u8) {
+    let mut adc: u16 = 0;
+    for i in 0..bsize { adc += u16::from(buf[idx - stride + i]); }
+    for i in 0..bsize { adc += u16::from(buf[idx - 1 + i * stride]); }
+    let dc = ((adc + (1 << (shift - 1))) >> shift) as u8;
+
+    for _ in 0..bsize {
+        for x in 0..bsize { buf[idx + x] = dc; }
+        idx += stride;
+    }
+}
+fn ipred_left_dc(buf: &mut [u8], mut idx: usize, stride: usize, bsize: usize, shift: u8) {
+    let mut adc: u16 = 0;
+    for i in 0..bsize { adc += u16::from(buf[idx - 1 + i * stride]); }
+    let dc = ((adc + (1 << (shift - 1))) >> shift) as u8;
+
+    for _ in 0..bsize {
+        for x in 0..bsize { buf[idx + x] = dc; }
+        idx += stride;
+    }
+}
+fn ipred_top_dc(buf: &mut [u8], mut idx: usize, stride: usize, bsize: usize, shift: u8) {
+    let mut adc: u16 = 0;
+    for i in 0..bsize { adc += u16::from(buf[idx - stride + i]); }
+    let dc = ((adc + (1 << (shift - 1))) >> shift) as u8;
+
+    for _ in 0..bsize {
+        for x in 0..bsize { buf[idx + x] = dc; }
+        idx += stride;
+    }
+}
+
+fn load_top(dst: &mut [u16], buf: &mut [u8], idx: usize, stride: usize, len: usize) {
+    for i in 0..len { dst[i] = u16::from(buf[idx - stride + i]); }
+}
+fn load_left(dst: &mut [u16], buf: &mut [u8], idx: usize, stride: usize, len: usize) {
+    for i in 0..len { dst[i] = u16::from(buf[idx - 1 + i * stride]); }
+}
+
+fn ipred_4x4_ver(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    ipred_ver(buf, idx, stride, 4);
+}
+fn ipred_4x4_hor(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    ipred_hor(buf, idx, stride, 4);
+}
+fn ipred_4x4_diag_down_left(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    let mut t: [u16; 8] = [0; 8];
+    let mut l: [u16; 8] = [0; 8];
+    load_top(&mut t, buf, idx, stride, 4);
+    load_left(&mut l, buf, idx, stride, 4);
+    let a = ((l[1] + t[1]) >> 1) as u8;
+    let b = ((l[2] + t[2]) >> 1) as u8;
+    let c = ((l[3] + t[3]) >> 1) as u8;
+
+    let dst = &mut buf[idx..];
+    dst[0] = a; dst[1] = b; dst[2] = c; dst[3] = c;
+    let dst = &mut buf[idx + stride..];
+    dst[0] = b; dst[1] = c; dst[2] = c; dst[3] = c;
+    let dst = &mut buf[idx + stride * 2..];
+    dst[0] = c; dst[1] = c; dst[2] = c; dst[3] = c;
+    let dst = &mut buf[idx + stride * 3..];
+    dst[0] = c; dst[1] = c; dst[2] = c; dst[3] = c;
+}
+fn ipred_4x4_diag_down_right(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    let mut t: [u16; 5] = [0; 5];
+    let mut l: [u16; 5] = [0; 5];
+    load_top(&mut t, buf, idx - 1, stride, 5);
+    load_left(&mut l, buf, idx - stride, stride, 5);
+    let dst = &mut buf[idx..];
+
+    for j in 0..4 {
+        for i in 0..j {
+            dst[i + j * stride] = ((l[j - i - 1] + 2 * l[j - i] + l[j - i + 1] + 2) >> 2) as u8;
+        }
+        dst[j + j * stride] = ((l[1] + 2 * l[0] + t[1] + 2) >> 2) as u8;
+        for i in (j+1)..4 {
+            dst[i + j * stride] = ((t[i - j - 1] + 2 * t[i - j] + t[i - j + 1] + 2) >> 2) as u8;
+        }
+    }
+}
+fn ipred_4x4_ver_right(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    let mut t: [u16; 5] = [0; 5];
+    let mut l: [u16; 5] = [0; 5];
+    load_top(&mut t, buf, idx - 1, stride, 5);
+    load_left(&mut l, buf, idx - stride, stride, 5);
+    let dst = &mut buf[idx..];
+
+    for j in 0..4 {
+        for i in 0..4 {
+            let zvr = ((2 * i) as i8) - (j as i8);
+            let pix;
+            if zvr >= 0 {
+                if (zvr & 1) == 0 {
+                    pix = (t[i - (j >> 1)] + t[i - (j >> 1) + 1] + 1) >> 1;
+                } else {
+                    pix = (t[i - (j >> 1) - 1] + 2 * t[i - (j >> 1)] + t[i - (j >> 1) + 1] + 2) >> 2;
+                }
+            } else {
+                if zvr == -1 {
+                    pix = (l[1] + 2 * l[0] + t[1] + 2) >> 2;
+                } else {
+                    pix = (l[j] + 2 * l[j - 1] + l[j - 2] + 2) >> 2;
+                }
+            }
+            dst[i + j * stride] = pix as u8;
+        }
+    }
+}
+fn ipred_4x4_ver_left(buf: &mut [u8], idx: usize, stride: usize, tr: &[u8]) {
+    let mut t: [u16; 8] = [0; 8];
+    load_top(&mut t, buf, idx, stride, 4);
+    for i in 0..4 { t[i + 4] = u16::from(tr[i]); }
+    let dst = &mut buf[idx..];
+
+    dst[0 + 0 * stride] = ((t[0] + t[1] + 1) >> 1) as u8;
+    let pix = ((t[1] + t[2] + 1) >> 1) as u8;
+    dst[1 + 0 * stride] = pix;
+    dst[0 + 2 * stride] = pix;
+    let pix = ((t[2] + t[3] + 1) >> 1) as u8;
+    dst[2 + 0 * stride] = pix;
+    dst[1 + 2 * stride] = pix;
+    let pix = ((t[3] + t[4] + 1) >> 1) as u8;
+    dst[3 + 0 * stride] = pix;
+    dst[2 + 2 * stride] = pix;
+    dst[3 + 2 * stride] = ((t[4] + t[5] + 1) >> 1) as u8;
+    dst[0 + 1 * stride] = ((t[0] + 2*t[1] + t[2] + 2) >> 2) as u8;
+    let pix = ((t[1] + 2*t[2] + t[3] + 2) >> 2) as u8;
+    dst[1 + 1 * stride] = pix;
+    dst[0 + 3 * stride] = pix;
+    let pix = ((t[2] + 2*t[3] + t[4] + 2) >> 2) as u8;
+    dst[2 + 1 * stride] = pix;
+    dst[1 + 3 * stride] = pix;
+    let pix = ((t[3] + 2*t[4] + t[5] + 2) >> 2) as u8;
+    dst[3 + 1 * stride] = pix;
+    dst[2 + 3 * stride] = pix;
+    dst[3 + 3 * stride] = ((t[4] + 2*t[5] + t[6] + 2) >> 2) as u8;
+}
+fn ipred_4x4_hor_down(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    let mut t: [u16; 5] = [0; 5];
+    let mut l: [u16; 5] = [0; 5];
+    load_top(&mut t, buf, idx - 1, stride, 5);
+    load_left(&mut l, buf, idx - stride, stride, 5);
+    let dst = &mut buf[idx..];
+
+    for j in 0..4 {
+        for i in 0..4 {
+            let zhd = ((2 * j) as i8) - (i as i8);
+            let pix;
+            if zhd >= 0 {
+                if (zhd & 1) == 0 {
+                    pix = (l[j - (i >> 1)] + l[j - (i >> 1) + 1] + 1) >> 1;
+                } else {
+                    pix = (l[j - (i >> 1) - 1] + 2 * l[j - (i >> 1)] + l[j - (i >> 1) + 1] + 2) >> 2;
+                }
+            } else {
+                if zhd == -1 {
+                    pix = (l[1] + 2 * l[0] + t[1] + 2) >> 2;
+                } else {
+                    pix = (t[i - 2] + 2 * t[i - 1] + t[i] + 2) >> 2;
+                }
+            }
+            dst[i + j * stride] = pix as u8;
+        }
+    }
+}
+fn ipred_4x4_hor_up(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    let mut l: [u16; 8] = [0; 8];
+    load_left(&mut l, buf, idx, stride, 8);
+    let dst = &mut buf[idx..];
+
+    dst[0 + 0 * stride] = ((l[0] + l[1] + 1) >> 1) as u8;
+    dst[1 + 0 * stride] = ((l[0] + 2*l[1] + l[2] + 2) >> 2) as u8;
+    let pix = ((l[1] + l[2] + 1) >> 1) as u8;
+    dst[2 + 0 * stride] = pix;
+    dst[0 + 1 * stride] = pix;
+    let pix = ((l[1] + 2*l[2] + l[3] + 2) >> 2) as u8;
+    dst[3 + 0 * stride] = pix;
+    dst[1 + 1 * stride] = pix;
+    let pix = ((l[2] + l[3] + 1) >> 1) as u8;
+    dst[2 + 1 * stride] = pix;
+    dst[0 + 2 * stride] = pix;
+    let pix = ((l[2] + 3*l[3] + 2) >> 2) as u8;
+    dst[3 + 1 * stride] = pix;
+    dst[1 + 2 * stride] = pix;
+    dst[3 + 2 * stride] = l[3] as u8;
+    dst[1 + 3 * stride] = l[3] as u8;
+    dst[0 + 3 * stride] = l[3] as u8;
+    dst[2 + 2 * stride] = l[3] as u8;
+    dst[2 + 3 * stride] = l[3] as u8;
+    dst[3 + 3 * stride] = l[3] as u8;
+}
+fn ipred_4x4_dc(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    ipred_dc(buf, idx, stride, 4, 3);
+}
+fn ipred_4x4_left_dc(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    ipred_left_dc(buf, idx, stride, 4, 2);
+}
+fn ipred_4x4_top_dc(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    ipred_top_dc(buf, idx, stride, 4, 2);
+}
+fn ipred_4x4_dc128(buf: &mut [u8], idx: usize, stride: usize, _tr: &[u8]) {
+    ipred_dc128(buf, idx, stride, 4);
+}
+
+fn ipred_8x8_ver(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_ver(buf, idx, stride, 8);
+}
+fn ipred_8x8_hor(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_hor(buf, idx, stride, 8);
+}
+fn ipred_8x8_dc(buf: &mut [u8], idx: usize, stride: usize) {
+    let mut t: [u16; 8] = [0; 8];
+    load_top(&mut t, buf, idx, stride, 8);
+    let mut l: [u16; 8] = [0; 8];
+    load_left(&mut l, buf, idx, stride, 8);
+
+    let dc0 = ((t[0] + t[1] + t[2] + t[3] + l[0] + l[1] + l[2] + l[3] + 4) >> 3) as u8;
+    let sum1 = t[4] + t[5] + t[6] + t[7];
+    let dc1 = ((sum1 + 2) >> 2) as u8;
+    let sum2 = l[4] + l[5] + l[6] + l[7];
+    let dc2 = ((sum2 + 2) >> 2) as u8;
+    let dc3 = ((sum1 + sum2 + 4) >> 3) as u8;
+
+    let dst = &mut buf[idx..];
+    for row in dst.chunks_mut(stride).take(4) {
+        row[..4].copy_from_slice(&[dc0; 4]);
+        row[4..8].copy_from_slice(&[dc1; 4]);
+    }
+    for row in dst.chunks_mut(stride).skip(4).take(4) {
+        row[..4].copy_from_slice(&[dc2; 4]);
+        row[4..8].copy_from_slice(&[dc3; 4]);
+    }
+}
+fn ipred_8x8_left_dc(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_left_dc(buf, idx, stride, 8, 3);
+}
+fn ipred_8x8_top_dc(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_top_dc(buf, idx, stride, 8, 3);
+}
+fn ipred_8x8_dc128(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_dc128(buf, idx, stride, 8);
+}
+fn ipred_8x8_plane(_buf: &mut [u8], _idx: usize, _stride: usize) {
+    unreachable!();
+/*    let mut h: i16 = 0;
+    let mut v: i16 = 0;
+    let     idx0 = idx + 3 - stride;
+    let mut idx1 = idx + 4 * stride - 1;
+    let mut idx2 = idx + 2 * stride - 1;
+    for i in 0..4 {
+        let i1 = (i + 1) as i16;
+        h += i1 * (i16::from(buf[idx0 + i + 1]) - i16::from(buf[idx0 - i - 1]));
+        v += i1 * (i16::from(buf[idx1]) - i16::from(buf[idx2]));
+        idx1 += stride;
+        idx2 -= stride;
+    }
+    let b = (17 * h + 16) >> 5;
+    let c = (17 * v + 16) >> 5;
+    let mut a = 16 * (i16::from(buf[idx - 1 + 7 * stride]) + i16::from(buf[idx + 7 - stride])) - 3 * (b + c) + 16;
+    for line in buf[idx..].chunks_mut(stride).take(8) {
+        let mut acc = a;
+        for el in line.iter_mut().take(8) {
+            *el = clip8(acc >> 5);
+            acc += b;
+        }
+        a += c;
+    }*/
+}
+
+fn ipred_16x16_ver(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_ver(buf, idx, stride, 16);
+}
+fn ipred_16x16_hor(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_hor(buf, idx, stride, 16);
+}
+fn ipred_16x16_dc(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_dc(buf, idx, stride, 16, 5);
+}
+fn ipred_16x16_left_dc(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_left_dc(buf, idx, stride, 16, 4);
+}
+fn ipred_16x16_top_dc(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_top_dc(buf, idx, stride, 16, 4);
+}
+fn ipred_16x16_dc128(buf: &mut [u8], idx: usize, stride: usize) {
+    ipred_dc128(buf, idx, stride, 16);
+}
+fn ipred_16x16_plane(buf: &mut [u8], mut idx: usize, stride: usize) {
+    let     idx0 = idx + 7 - stride;
+    let mut idx1 = idx + 8 * stride - 1;
+    let mut idx2 = idx1 - 2 * stride;
+
+    let mut h = i16::from(buf[idx0 + 1]) - i16::from(buf[idx0 - 1]);
+    let mut v = i16::from(buf[idx1])     - i16::from(buf[idx2]);
+
+    for k in 2..9 {
+        idx1 += stride;
+        idx2 -= stride;
+        h += (k as i16) * (i16::from(buf[idx0 + k]) - i16::from(buf[idx0 - k]));
+        v += (k as i16) * (i16::from(buf[idx1])     - i16::from(buf[idx2]));
+    }
+    h = 5 * (h / 4) / 16;
+    v = 5 * (v / 4) / 16;
+    std::mem::swap(&mut h, &mut v);
+
+    let mut a = 16 * (i16::from(buf[idx - 1 + 15 * stride]) + i16::from(buf[idx + 15 - stride]) + 1) - 7 * (v + h);
+
+    for _ in 0..16 {
+        let mut b = a;
+        a += v;
+
+        for dst in buf[idx..].chunks_mut(4).take(4) {
+            dst[0] = clip8((b      ) >> 5);
+            dst[1] = clip8((b +   h) >> 5);
+            dst[2] = clip8((b + 2*h) >> 5);
+            dst[3] = clip8((b + 3*h) >> 5);
+            b += h * 4;
+        }
+        idx += stride;
+    }
+}
+
+pub type IPred4x4Func = fn(buf: &mut [u8], off: usize, stride: usize, tr: &[u8]);
+pub type IPred8x8Func = fn(buf: &mut [u8], off: usize, stride: usize);
+
+pub const IPRED_FUNCS4X4: [IPred4x4Func; 12] = [
+    ipred_4x4_ver, ipred_4x4_hor, ipred_4x4_dc,
+    ipred_4x4_diag_down_left, ipred_4x4_diag_down_right,
+    ipred_4x4_ver_right, ipred_4x4_hor_down, ipred_4x4_ver_left, ipred_4x4_hor_up,
+    ipred_4x4_left_dc, ipred_4x4_top_dc, ipred_4x4_dc128
+];
+
+pub const IPRED_FUNCS8X8: [IPred8x8Func; 7] = [
+    ipred_8x8_dc, ipred_8x8_hor, ipred_8x8_ver, ipred_8x8_plane,
+    ipred_8x8_left_dc, ipred_8x8_top_dc, ipred_8x8_dc128
+];
+
+pub const IPRED_FUNCS16X16: [IPred8x8Func; 7] = [
+    ipred_16x16_dc, ipred_16x16_hor, ipred_16x16_ver, ipred_16x16_plane,
+    ipred_16x16_left_dc, ipred_16x16_top_dc, ipred_16x16_dc128
+];
+
+fn tpel_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(bh) {
+        dline[..bw].copy_from_slice(&sline[..bw]);
+    }
+}
+
+fn interp2(val: u32) -> u8 {
+    (((val + 1) * 683) >> 11) as u8
+}
+
+fn interp4(val: u32) -> u8 {
+    (((val + 6) * 2731) >> 15) as u8
+}
+
+fn tpel_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(bh) {
+        let mut last = u32::from(sline[0]);
+        for (dst, src) in dline.iter_mut().take(bw).zip(sline[1..].iter()) {
+            let new = u32::from(*src);
+            *dst = interp2(last * 2 + new);
+            last = new;
+        }
+    }
+}
+
+fn tpel_interp02(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    for (dline, sline) in dst.chunks_mut(dstride).zip(src.chunks(sstride)).take(bh) {
+        let mut last = u32::from(sline[0]);
+        for (dst, src) in dline.iter_mut().take(bw).zip(sline[1..].iter()) {
+            let new = u32::from(*src);
+            *dst = interp2(last + new * 2);
+            last = new;
+        }
+    }
+}
+
+fn tpel_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    let src1 = &src[sstride..];
+    for (dline, (sline0, sline1)) in dst.chunks_mut(dstride).zip(src.chunks(sstride).zip(src1.chunks(sstride))).take(bh) {
+        for (dst, (s0, s1)) in dline.iter_mut().zip(sline0.iter().zip(sline1.iter())).take(bw) {
+            *dst = interp2(u32::from(*s0) * 2 + u32::from(*s1));
+        }
+    }
+}
+
+fn tpel_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    let mut sidx0 = 0;
+    let mut sidx1 = sstride;
+    for dline in dst.chunks_mut(dstride).take(bh) {
+        for (x, dst) in dline.iter_mut().take(bw).enumerate() {
+            *dst = interp4(u32::from(src[sidx0 + x]) * 4 + u32::from(src[sidx0 + x + 1]) * 3 +
+                           u32::from(src[sidx1 + x]) * 3 + u32::from(src[sidx1 + x + 1]) * 2);
+        }
+        sidx0 += sstride;
+        sidx1 += sstride;
+    }
+}
+
+fn tpel_interp12(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    let mut sidx0 = 0;
+    let mut sidx1 = sstride;
+    for dline in dst.chunks_mut(dstride).take(bh) {
+        for (x, dst) in dline.iter_mut().take(bw).enumerate() {
+            *dst = interp4(u32::from(src[sidx0 + x]) * 3 + u32::from(src[sidx0 + x + 1]) * 4 +
+                           u32::from(src[sidx1 + x]) * 2 + u32::from(src[sidx1 + x + 1]) * 3);
+        }
+        sidx0 += sstride;
+        sidx1 += sstride;
+    }
+}
+
+fn tpel_interp20(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    let src1 = &src[sstride..];
+    for (dline, (sline0, sline1)) in dst.chunks_mut(dstride).zip(src.chunks(sstride).zip(src1.chunks(sstride))).take(bh) {
+        for (dst, (s0, s1)) in dline.iter_mut().zip(sline0.iter().zip(sline1.iter())).take(bw) {
+            *dst = interp2(u32::from(*s0) + u32::from(*s1) * 2);
+        }
+    }
+}
+
+fn tpel_interp21(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    let mut sidx0 = 0;
+    let mut sidx1 = sstride;
+    for dline in dst.chunks_mut(dstride).take(bh) {
+        for (x, dst) in dline.iter_mut().take(bw).enumerate() {
+            *dst = interp4(u32::from(src[sidx0 + x]) * 3 + u32::from(src[sidx0 + x + 1]) * 2 +
+                           u32::from(src[sidx1 + x]) * 4 + u32::from(src[sidx1 + x + 1]) * 3);
+        }
+        sidx0 += sstride;
+        sidx1 += sstride;
+    }
+}
+
+fn tpel_interp22(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) {
+    let mut sidx0 = 0;
+    let mut sidx1 = sstride;
+    for dline in dst.chunks_mut(dstride).take(bh) {
+        for (x, dst) in dline.iter_mut().take(bw).enumerate() {
+            *dst = interp4(u32::from(src[sidx0 + x]) * 2 + u32::from(src[sidx0 + x + 1]) * 3 +
+                           u32::from(src[sidx1 + x]) * 3 + u32::from(src[sidx1 + x + 1]) * 4);
+        }
+        sidx0 += sstride;
+        sidx1 += sstride;
+    }
+}
+
+pub const THIRDPEL_INTERP_FUNCS: &[BlkInterpFunc] = &[
+    tpel_interp00, tpel_interp01, tpel_interp02,
+    tpel_interp10, tpel_interp11, tpel_interp12,
+    tpel_interp20, tpel_interp21, tpel_interp22
+];
diff --git a/nihav-qt/src/lib.rs b/nihav-qt/src/lib.rs
new file mode 100644 (file)
index 0000000..1996c60
--- /dev/null
@@ -0,0 +1,6 @@
+extern crate nihav_core;
+extern crate nihav_codec_support;
+
+#[allow(clippy::single_match)]
+mod codecs;
+pub use crate::codecs::qt_register_all_codecs;