X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-vivo%2Fsrc%2Fcodecs%2Fvivo.rs;h=64af5ffae9833396c07a162877c8043cc04eb982;hb=886cde4847280b96e10d240c2f2d76abec121dc8;hp=27576ca2b2a7d6dfee53823671b7db9520406779;hpb=2af66d559dfbdedf96bdef85de3fae0a141a5be5;p=nihav.git diff --git a/nihav-vivo/src/codecs/vivo.rs b/nihav-vivo/src/codecs/vivo.rs index 27576ca..64af5ff 100644 --- a/nihav-vivo/src/codecs/vivo.rs +++ b/nihav-vivo/src/codecs/vivo.rs @@ -20,13 +20,42 @@ struct Tables { mv_cb: Codebook, } -struct VivoBlockDSP {} +struct VivoBlockDSP { + dct_tab: [[f64; 64]; 64], +} -impl VivoBlockDSP { fn new() -> Self { Self {} } } +fn gen_coef(i: usize, j: usize) -> f64 { + if i == 0 { + 1.0 / 8.0f64.sqrt() + } else { + (((j as f64) + 0.5) * (i as f64) * std::f64::consts::PI / 8.0).cos() * 0.5 + } +} + +impl VivoBlockDSP { + fn new() -> Self { + let mut dct_tab = [[0.0; 64]; 64]; + for i in 0..8 { + for j in 0..8 { + for k in 0..8 { + for l in 0..8 { + let c0 = gen_coef(i, k); + let c1 = gen_coef(j, l); + let c = c0 * c1 * 64.0; + dct_tab[i * 8 + j][k * 8 + l] = c; + } + } + } + } + Self { + dct_tab + } + } +} #[allow(clippy::erasing_op)] #[allow(clippy::identity_op)] -fn deblock_hor(buf: &mut [u8], off: usize, stride: usize, clip_tab: &[i16; 64]) { +fn deblock_hor(buf: &mut [u8], stride: usize, off: usize, clip_tab: &[i16; 64]) { for x in 0..8 { let p1 = i16::from(buf[off - 2 * stride + x]); let p0 = i16::from(buf[off - 1 * stride + x]); @@ -42,7 +71,7 @@ fn deblock_hor(buf: &mut [u8], off: usize, stride: usize, clip_tab: &[i16; 64]) } #[allow(clippy::identity_op)] -fn deblock_ver(buf: &mut [u8], off: usize, stride: usize, clip_tab: &[i16; 64]) { +fn deblock_ver(buf: &mut [u8], stride: usize, off: usize, clip_tab: &[i16; 64]) { for y in 0..8 { let p1 = i16::from(buf[off - 2 + y * stride]); let p0 = i16::from(buf[off - 1 + y * stride]); @@ -66,7 +95,7 @@ fn gen_clip_tab(clip_tab: &mut [i16; 64], q: u8) { clip_tab[(32 + i) as usize] = i; } for i in lim..q { - let val = q - i; + let val = q - i; clip_tab[(32 - i) as usize] = -val; clip_tab[(32 + i) as usize] = val; } @@ -74,7 +103,18 @@ fn gen_clip_tab(clip_tab: &mut [i16; 64], q: u8) { impl BlockDSP for VivoBlockDSP { fn idct(&self, blk: &mut [i16; 64]) { - h263_annex_w_idct(blk); + let mut tmp = [0i32; 64]; + for (i, &el) in blk.iter().enumerate() { + if el != 0 { + let cmat = self.dct_tab[i]; + for (dst, &src) in tmp.iter_mut().zip(cmat.iter()) { + *dst += (src * (el as f64)) as i32; + } + } + } + for (dst, &src) in blk.iter_mut().zip(tmp.iter()) { + *dst = ((src + 0x20) >> 6) as i16; + } } fn copy_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV) { let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; @@ -84,17 +124,17 @@ impl BlockDSP for VivoBlockDSP { blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_FUNCS); blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS); - blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS); + blockdsp::copy_block(&mut dst, src, 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_FUNCS); } fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mvs: &[MV; 4]) { let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); - for i in 0..4 { + for (i, mv) in mvs.iter().enumerate() { let xadd = (i & 1) * 8; let yadd = (i & 2) * 4; - let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize; + let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; - blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS); + blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mv.x >> 1, mv.y >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS); } let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; @@ -113,17 +153,17 @@ impl BlockDSP for VivoBlockDSP { blockdsp::copy_block(&mut dst, src.clone(), 0, xpos, ypos, mv.x >> 1, mv.y >> 1, 16, 16, 0, 1, mode, H263_INTERP_AVG_FUNCS); blockdsp::copy_block(&mut dst, src.clone(), 1, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS); - blockdsp::copy_block(&mut dst, src.clone(), 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS); + blockdsp::copy_block(&mut dst, src, 2, xpos >> 1, ypos >> 1, mv.x >> 2, mv.y >> 2, 8, 8, 0, 1, cmode, H263_INTERP_AVG_FUNCS); } fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mvs: &[MV; 4]) { let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); - for i in 0..4 { + for (i, mv) in mvs.iter().enumerate() { let xadd = (i & 1) * 8; let yadd = (i & 2) * 4; - let mode = ((mvs[i].x & 1) + (mvs[i].y & 1) * 2) as usize; + let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; - blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mvs[i].x >> 1, mvs[i].y >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS); + blockdsp::copy_block(&mut dst, src.clone(), 0, xpos + xadd, ypos + yadd, mv.x >> 1, mv.y >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS); } let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; @@ -147,106 +187,63 @@ impl BlockDSP for VivoBlockDSP { let mut last_q = 0; let mut off = yoff; for mb_x in 0..mb_w { - let coff = off; - let coded0 = cbpi.is_coded(mb_x, 0); - let coded1 = cbpi.is_coded(mb_x, 1); let q = cbpi.get_q(mb_w + mb_x); if q != last_q { gen_clip_tab(&mut clip_tab, q); last_q = q; } if mb_y != 0 { - if coded0 && cbpi.is_coded_top(mb_x, 0) { - deblock_hor(buf, ystride, coff, &clip_tab); - } - if coded1 && cbpi.is_coded_top(mb_x, 1) { - deblock_hor(buf, ystride, coff + 8, &clip_tab); - } - } - let coff = off + 8 * ystride; - if cbpi.is_coded(mb_x, 2) && coded0 { - deblock_hor(buf, ystride, coff, &clip_tab); - } - if cbpi.is_coded(mb_x, 3) && coded1 { - deblock_hor(buf, ystride, coff + 8, &clip_tab); + deblock_hor(buf, ystride, off, &clip_tab); + deblock_hor(buf, ystride, off + 8, &clip_tab); } + deblock_hor(buf, ystride, off + 8 * ystride, &clip_tab); + deblock_hor(buf, ystride, off + 8 * ystride + 8, &clip_tab); off += 16; } - let mut leftt = false; - let mut leftc = false; let mut off = yoff; for mb_x in 0..mb_w { - let ctop0 = cbpi.is_coded_top(mb_x, 0); - let ctop1 = cbpi.is_coded_top(mb_x, 0); - let ccur0 = cbpi.is_coded(mb_x, 0); - let ccur1 = cbpi.is_coded(mb_x, 1); let q = cbpi.get_q(mb_w + mb_x); if q != last_q { gen_clip_tab(&mut clip_tab, q); last_q = q; } if mb_y != 0 { - let coff = off - 8 * ystride; let qtop = cbpi.get_q(mb_x); if qtop != last_q { gen_clip_tab(&mut clip_tab, qtop); last_q = qtop; } - if leftt && ctop0 { - deblock_ver(buf, ystride, coff, &clip_tab); - } - if ctop0 && ctop1 { - deblock_ver(buf, ystride, coff + 8, &clip_tab); + if mb_x != 0 { + deblock_ver(buf, ystride, off - 8 * ystride, &clip_tab); } + deblock_ver(buf, ystride, off - 8 * ystride + 8, &clip_tab); } - if leftc && ccur0 { + if mb_x != 0 { deblock_ver(buf, ystride, off, &clip_tab); - } - if ccur0 && ccur1 { deblock_ver(buf, ystride, off + 8, &clip_tab); } - leftt = ctop1; - leftc = ccur1; off += 16; } if mb_y != 0 { for mb_x in 0..mb_w { - let ctu = cbpi.is_coded_top(mb_x, 4); - let ccu = cbpi.is_coded(mb_x, 4); - let ctv = cbpi.is_coded_top(mb_x, 5); - let ccv = cbpi.is_coded(mb_x, 5); let q = cbpi.get_q(mb_w + mb_x); if q != last_q { gen_clip_tab(&mut clip_tab, q); last_q = q; } - if ctu && ccu { - deblock_hor(buf, ustride, uoff + mb_x * 8, &clip_tab); - } - if ctv && ccv { - deblock_hor(buf, vstride, voff + mb_x * 8, &clip_tab); - } + deblock_hor(buf, ustride, uoff + mb_x * 8, &clip_tab); + deblock_hor(buf, vstride, voff + mb_x * 8, &clip_tab); } - let mut leftu = false; - let mut leftv = false; let offu = uoff - 8 * ustride; let offv = voff - 8 * vstride; - for mb_x in 0..mb_w { - let ctu = cbpi.is_coded_top(mb_x, 4); - let ctv = cbpi.is_coded_top(mb_x, 5); + for mb_x in 1..mb_w { let qt = cbpi.get_q(mb_x); if qt != last_q { gen_clip_tab(&mut clip_tab, qt); last_q = qt; } - if leftu && ctu { - deblock_ver(buf, ustride, offu + mb_x * 8, &clip_tab); - } - if leftv && ctv { - deblock_ver(buf, vstride, offv + mb_x * 8, &clip_tab); - } - leftu = ctu; - leftv = ctv; + deblock_ver(buf, ustride, offu + mb_x * 8, &clip_tab); + deblock_ver(buf, vstride, offv + mb_x * 8, &clip_tab); } } } @@ -312,8 +309,8 @@ impl<'a> VivoBR<'a> { }; let rl_cb = if self.aic && intra { &self.tables.aic_rl_cb } else { &self.tables.rl_cb }; - let q = i16::from(quant * 2); - let q_add = if q == 0 || self.aic { 0i16 } else { (((q >> 1) - 1) | 1) as i16 }; + let q = i16::from(quant) * 2; + let q_add = q >> 1; while idx < 64 { let code = br.read_cb(rl_cb)?; let run; @@ -324,7 +321,7 @@ impl<'a> VivoBR<'a> { level = code.get_level(); last = code.is_last(); if br.read_bool()? { level = -level; } - if !intra || idx != 0 { + if !intra || !self.aic { if level >= 0 { level = (level * q) + q_add; } else { @@ -340,7 +337,7 @@ impl<'a> VivoBR<'a> { let top = br.read_s(6)? as i16; level = (top << 5) | low; } - if !intra || idx != 0 { + if !intra || !self.aic { if level >= 0 { level = (level * q) + q_add; } else { @@ -431,11 +428,12 @@ impl<'a> BlockDecoder for VivoBR<'a> { sfmt = br.read(3)?; validate!(sfmt != 0b000 && sfmt != 0b110); aic = br.read_bool()?; - br.read(1)?; // umv mode deblock = br.read_bool()?; - br.read(3)?; // unknown flags - pbplus = br.read_bool()?; br.read(4)?; // unknown flags + pbplus = br.read_bool()?; + br.read(1)?; // unknown flag + let _interlaced = br.read_bool()?; + br.read(2)?; // unknown flags } else { aic = false; deblock = false; @@ -731,6 +729,7 @@ mod test { use nihav_codec_support::test::dec_video::*; use crate::vivo_register_all_decoders; use crate::vivo_register_all_demuxers; + // samples from https://samples.mplayerhq.hu/vivo/ #[test] fn test_vivo1() { let mut dmx_reg = RegisteredDemuxers::new(); @@ -738,9 +737,25 @@ mod test { let mut dec_reg = RegisteredDecoders::new(); vivo_register_all_decoders(&mut dec_reg); -test_file_decoding("vivo", "assets/Misc/gr_al.viv", Some(16), true, false, Some("viv1"), &dmx_reg, &dec_reg); -// test_decoding("vivo", "vivo1", "assets/Misc/gr_al.viv", Some(16), -// &dmx_reg, &dec_reg, ExpectedTestResult::GenerateMD5Frames)); + test_decoding("vivo", "vivo1", "assets/Misc/gr_al.viv", Some(16), + &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ + [0x59ea0837, 0xdf9b5ca3, 0x73cd45c3, 0xaaf2fbf1], + [0x5d21c5a0, 0xfb335c4f, 0xe30945e9, 0xec65d54f], + [0x46916c45, 0x406f1019, 0xba0105e0, 0xfccd0aab], + [0x11006812, 0xb8e8c959, 0x5f69950b, 0x3578db5e], + [0xd0b84c1e, 0xad327825, 0x4a98dbbe, 0x48edc280], + [0xe1be71a4, 0xc7649922, 0x949496a6, 0xed697d09], + [0x0ed9deea, 0x3e9b9784, 0x4836e38b, 0x363f8108], + [0x358f2581, 0x95e6b290, 0x35ffde28, 0x003fa23e], + [0x482385bd, 0x43bb7cee, 0xf1900758, 0x3b5f1255], + [0x91d7549f, 0x96976ef4, 0xb2920f71, 0x71c7a9a6], + [0x95736d4f, 0x56748245, 0x5733bd5d, 0x20eacf6d], + [0xb5045185, 0x55dbe063, 0xb1c96f24, 0xe5d78296], + [0xa88cadf4, 0xedc4a0aa, 0xbb359ed8, 0x1ea28916], + [0x4d9f9491, 0x13d29319, 0x57aef355, 0x7e0c9e0b], + [0xc3b52284, 0xabb74a4b, 0xf03c9503, 0x834d149e], + [0x35fc95d0, 0x0f583ef0, 0xb176f055, 0xb587839a], + [0xd5e3b443, 0x3b11b285, 0x78ec3098, 0xe2109aaa]])); } #[test] fn test_vivo2() { @@ -749,9 +764,64 @@ test_file_decoding("vivo", "assets/Misc/gr_al.viv", Some(16), true, false, Some( let mut dec_reg = RegisteredDecoders::new(); vivo_register_all_decoders(&mut dec_reg); -test_file_decoding("vivo", "assets/Misc/02-KimagureOrangeRoad.viv", Some(50), true, false, Some("viv2"), &dmx_reg, &dec_reg); -panic!("end"); -// test_decoding("vivo", "vivo2", "assets/Misc/greetings.viv", Some(16), -// &dmx_reg, &dec_reg, ExpectedTestResult::GenerateMD5Frames)); + test_decoding("vivo", "vivo2", "assets/Misc/02-KimagureOrangeRoad.viv", Some(56), + &dmx_reg, &dec_reg, ExpectedTestResult::MD5Frames(vec![ + [0x73f2afc2, 0x1cc43762, 0xbcfa886d, 0x7e607dd1], + [0x45652ef5, 0x7c03046c, 0xcef60a62, 0x4a1e8f24], + [0x09f6557e, 0x852cf108, 0x13dbb6ff, 0xaa8667e9], + [0x3668d658, 0xfdc37a56, 0x267cb690, 0xa33924ee], + [0x0ad13447, 0x26315ca3, 0xfbf43f79, 0xc3951941], + [0x8c870462, 0x9135c664, 0x586accfa, 0xfe6d9113], + [0x26b08477, 0xcdef5073, 0x86899b3c, 0x0d911f1d], + [0x7db88b9c, 0x780729bb, 0xe3195f66, 0xb4f2e7e7], + [0x9008ed4e, 0x29b05b6c, 0x3f8a2c23, 0x6d396334], + [0xa255e91b, 0x324b764b, 0x265a08ea, 0x0a5a6ae7], + [0xf2110e23, 0x8fa53178, 0x675c32cb, 0x63ba9297], + [0xbe0bb384, 0xde08646e, 0x45d3530c, 0xd5cdf571], + [0xfa19949a, 0xb9e12931, 0xcaa98f06, 0xa284718a], + [0x9b1472e5, 0x2d18472c, 0xd5419a58, 0xff16d619], + [0xeecd4532, 0xa6301dcc, 0x6eed2b15, 0xa456cae0], + [0xb58b2bb8, 0x1c07bd9a, 0x1913e1c3, 0xa1f4fdc2], + [0x51b6bef2, 0xd155d675, 0xaba07c15, 0xcf0a673e], + [0x3c607ce6, 0x3a203449, 0xdda5b7a0, 0x9119b738], + [0x7e7bae10, 0x4beb488e, 0x33db98bb, 0x8b49311e], + [0xfff04316, 0xe29afa50, 0xa6f0c921, 0x5b0d29e2], + [0xe640595a, 0x98bb55a4, 0x50c0a1e5, 0xe4970206], + [0x63873ec7, 0x03a5fd08, 0xe3154f25, 0xb4ed64c2], + [0xfa792148, 0x7efebf2c, 0x88d91825, 0x9dce368d], + [0x5ed17368, 0x0e056059, 0x2c872282, 0xe5a98237], + [0xd7ed6bd6, 0x01414003, 0x5187d790, 0x0af5b029], + [0x2991a9c6, 0x8e2dda24, 0xfbf79bbb, 0xbcbfc672], + [0xf2d23c64, 0xeb7e6094, 0x70a54901, 0x6d9d0204], + [0x54997451, 0xb4edb3c0, 0x5a873e8f, 0xe89d7aa6], + [0x94325a5f, 0xe0feb4b3, 0x2b1860bc, 0xc6b6a1a4], + [0x8fd428de, 0x17f14f9f, 0x94c8d0da, 0xf9feda90], + [0xed90d455, 0x22745327, 0x0ac511f1, 0x2dc2c29e], + [0xc50ac6c1, 0xc9eaf8ec, 0x5d9dc7f3, 0x4e55fd09], + [0x51325c40, 0xa7c01917, 0xdc064cc6, 0x143badc1], + [0x3fc207ee, 0x2c4b0f91, 0x66555499, 0xdf6dc148], + [0xd6e7fa33, 0x68ba6ce9, 0x45cac834, 0x1d51b094], + [0x1ed541a8, 0x8dd0cc41, 0x149024d4, 0x13777a2e], + [0x7fcbd065, 0xb20e068f, 0x9a5e3ed5, 0x6c35dded], + [0x07ea66c1, 0xbfadea3b, 0x07bb6580, 0xf40d7d2f], + [0x2e0fe75e, 0xa03d3011, 0x539c097d, 0x95fb265c], + [0x2f177f09, 0x63b7172a, 0xb0fdd893, 0xcab516cf], + [0x7cc5a956, 0xcd1ecff1, 0xf927038c, 0xa0610b48], + [0xc0518934, 0xf5c38e4b, 0x7fa255cd, 0x9b054c5b], + [0x0551de82, 0x08253d6b, 0x9144ced8, 0xc5adda55], + [0xf45735b5, 0x3f2e2111, 0x54d1ff16, 0xe4866157], + [0x0aad101e, 0xd37001f4, 0xd5734080, 0xfa4cf449], + [0x65318bdd, 0x68809e67, 0x1e27946a, 0x2ca977e5], + [0x119cf864, 0x8834473e, 0x721a253e, 0x4e417f19], + [0x0d887145, 0xa42a05cc, 0x64a4388e, 0xa05de81d], + [0xc184105a, 0x71ac7a8e, 0xaab0dba5, 0x078a331e], + [0x078827ea, 0x27670e40, 0x92be9ebb, 0x0fc1f5a0], + [0x8c82ca58, 0xbae0a643, 0x845afc5b, 0x15052a84], + [0x92065c13, 0x69d3f6b7, 0x7270aab9, 0xb80921fd], + [0xa58536b5, 0x6c46d7e1, 0x5f07f282, 0x350900e9], + [0x13bf3f52, 0x71f8aa99, 0x97e0aaa5, 0xd6c1cff5], + [0xa760cf95, 0xeb33c24c, 0x8dd35c6a, 0x4d81c8b5], + [0x50f68b90, 0x41b1f1a0, 0x9847b3ec, 0x1cab5ccc], + [0xbd71de9e, 0xc097b4ac, 0x003ab1e5, 0x9394b5bd]])); } }