From: Kostya Shishkov Date: Sat, 4 Jul 2020 16:30:01 +0000 (+0200) Subject: add nihav_qt crate with some QuickTime codecs X-Git-Url: https://git.nihav.org/?p=nihav.git;a=commitdiff_plain;h=4c1582cf2e275af7c0f4a2c1a397fed5b68d31d5 add nihav_qt crate with some QuickTime codecs --- diff --git a/nihav-allstuff/Cargo.toml b/nihav-allstuff/Cargo.toml index 49aeaae..6c5de36 100644 --- a/nihav-allstuff/Cargo.toml +++ b/nihav-allstuff/Cargo.toml @@ -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" } diff --git a/nihav-allstuff/src/lib.rs b/nihav-allstuff/src/lib.rs index 0b85b89..88435c5 100644 --- a/nihav-allstuff/src/lib.rs +++ b/nihav-allstuff/src/lib.rs @@ -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 index 0000000..3e4b653 --- /dev/null +++ b/nihav-qt/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "nihav_qt" +version = "0.1.0" +authors = ["Kostya Shishkov "] +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 index 0000000..1d1a647 --- /dev/null +++ b/nihav-qt/src/codecs/imaadpcm.rs @@ -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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..d3fc953 --- /dev/null +++ b/nihav-qt/src/codecs/mace.rs @@ -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 { + 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 { None } +} + +pub fn get_decoder_3() -> Box { + Box::new(MaceDecoder::new(false)) +} + +pub fn get_decoder_6() -> Box { + 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 index 0000000..733d599 --- /dev/null +++ b/nihav-qt/src/codecs/mod.rs @@ -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 index 0000000..ff9a337 --- /dev/null +++ b/nihav-qt/src/codecs/qdm2.rs @@ -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 { + 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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..22ca5dc --- /dev/null +++ b/nihav-qt/src/codecs/qdm2fft.rs @@ -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; 5], + level_exp_alt_cb: Codebook, + level_exp_cb: Codebook, + stereo_exp_cb: Codebook, + phase_diff_cb: Codebook, +} + +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 { + 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; 5], + tone_start: [usize; 5], + old_tones: Vec, + + 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 index 0000000..ece74c2 --- /dev/null +++ b/nihav-qt/src/codecs/qdm2qmf.rs @@ -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, + level_diff_cb: Codebook, + run_cb: Codebook, + tone_idx_mid_cb: Codebook, + tone_idx_high1_cb: Codebook, + tone_idx_high2_cb: Codebook, + type30_codes_cb: Codebook, + type34_codes_cb: Codebook, +} + +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 index 0000000..818b02f --- /dev/null +++ b/nihav-qt/src/codecs/qdmc.rs @@ -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, + noise_seg_cb: Codebook, + amp_cb: Codebook, + amp_diff_cb: Codebook, + freq_diff_cb: Codebook, + phase_diff_cb: Codebook, + 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; 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(&_CODES, &_BITS, def_cb_map); + let amp_cb = Codebook::new(&mut cbr, CodebookMode::LSB).unwrap(); + let mut cbr = TableCodebookDescReader::new(&_DIFF_CODES, &_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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..6011140 --- /dev/null +++ b/nihav-qt/src/codecs/qdmcommon.rs @@ -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 for QdmBitReader<'a> { + #[allow(unused_variables)] + fn read_cb(&mut self, cb: &Codebook) -> CodebookResult { + 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) -> DecoderResult; + fn read_code_long(&mut self, cb: &Codebook) -> DecoderResult; +} + +impl<'a> QdmcCodeReader for BitReader<'a> { + fn read_code(&mut self, cb: &Codebook) -> DecoderResult { + 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) -> DecoderResult { + 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) -> DecoderResult { + 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) -> DecoderResult { + 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 index 0000000..0d3ed06 --- /dev/null +++ b/nihav-qt/src/codecs/rle.rs @@ -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, + hams16: HAMShuffler, + 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, start_line: usize, end_line: usize) -> DecoderResult { + 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, start_line: usize, end_line: usize) -> DecoderResult { + 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, start_line: usize, end_line: usize) -> DecoderResult { + 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, start_line: usize, end_line: usize) -> DecoderResult { + 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, start_line: usize, end_line: usize) -> DecoderResult { + 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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..a3b2e5f --- /dev/null +++ b/nihav-qt/src/codecs/rpza.rs @@ -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, + 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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..96fcba2 --- /dev/null +++ b/nihav-qt/src/codecs/smc.rs @@ -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, + 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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..68db3a3 --- /dev/null +++ b/nihav-qt/src/codecs/svq1.rs @@ -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 { + 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 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 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>, + mvs: Vec, + intra_stages_cb: Vec>, + inter_stages_cb: Vec>, + intra_mean_cb: Codebook, + inter_mean_cb: Codebook, + mv_cb: Codebook, + + 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 { + 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, 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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..fcfa47b --- /dev/null +++ b/nihav-qt/src/codecs/svq1data.rs @@ -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 index 0000000..6d65e65 --- /dev/null +++ b/nihav-qt/src/codecs/svq3.rs @@ -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, + 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_f: Vec, + w: usize, + h: usize, + has_b: Vec, + has_f: Vec, +} + +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, + imode: IntraModeState, + mvi: MVInfo, + ref_mvi: MVInfo, + mbtypes: Vec, + 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, + 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 { + 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 { + 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 { + 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, src: NAVideoBufferRef, 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, src: NAVideoBufferRef, 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 { + 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 { + 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) -> 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) -> 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) -> 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) -> 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, 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) { + 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) -> 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 { + 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 { None } +} + +pub fn get_decoder() -> Box { + 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 index 0000000..0c45402 --- /dev/null +++ b/nihav-qt/src/codecs/svq3dsp.rs @@ -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 index 0000000..1996c60 --- /dev/null +++ b/nihav-qt/src/lib.rs @@ -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;