From: Kostya Shishkov Date: Fri, 3 Apr 2020 13:23:11 +0000 (+0200) Subject: h263-based codecs: use proper motion compensation X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=401b2b60a38e3eb19ae19aee9e652f7c8c0cf6f8;p=nihav.git h263-based codecs: use proper motion compensation --- diff --git a/nihav-codec-support/src/codecs/h263/code.rs b/nihav-codec-support/src/codecs/h263/code.rs index 9b9033a..c2100bb 100644 --- a/nihav-codec-support/src/codecs/h263/code.rs +++ b/nihav-codec-support/src/codecs/h263/code.rs @@ -1,7 +1,7 @@ -use nihav_core::frame::NAVideoBuffer; +use nihav_core::frame::{NAVideoBuffer, NAVideoBufferRef, NASimpleVideoFrame}; use super::{BlockDSP, CBPInfo, MV}; use super::super::blockdsp; -//use super::h263data::*; +use super::data::H263_CHROMA_ROUND; /*const W1: i32 = 22725; const W2: i32 = 21407; @@ -478,19 +478,63 @@ impl BlockDSP for H263BlockDSP { fn idct(&self, blk: &mut [i16; 64]) { h263_idct(blk) } - fn copy_blocks(&self, dst: &mut NAVideoBuffer, src: &NAVideoBuffer, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) { - let srcx = ((mv.x >> 1) as isize) + (xpos as isize); - let srcy = ((mv.y >> 1) as isize) + (ypos as isize); + 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; + let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 }); - blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_FUNCS); + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + 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); + } + 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 { + let xadd = (i & 1) * 8; + let yadd = (i & 2) * 4; + let mode = ((mvs[i].x & 1) + (mvs[i].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); + } + + let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize]; + let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize]; + let mode = ((cmx & 1) + (cmy & 1) * 2) as usize; + for plane in 1..3 { + blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS); + } } - fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: &NAVideoBuffer, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) { - let srcx = ((mv.x >> 1) as isize) + (xpos as isize); - let srcy = ((mv.y >> 1) as isize) + (ypos as isize); + fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV) { let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; + let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 }); - blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_AVG_FUNCS); + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + 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); + } + 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 { + let xadd = (i & 1) * 8; + let yadd = (i & 2) * 4; + let mode = ((mvs[i].x & 1) + (mvs[i].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); + } + + let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize]; + let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize]; + let mode = ((cmx & 1) + (cmy & 1) * 2) as usize; + for plane in 1..3 { + blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS); + } } fn filter_row(&self, buf: &mut NAVideoBuffer, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) { h263_filter_row(buf, mb_y, mb_w, cbpi) diff --git a/nihav-codec-support/src/codecs/h263/data.rs b/nihav-codec-support/src/codecs/h263/data.rs index 9a2d4a2..40d5cc8 100644 --- a/nihav-codec-support/src/codecs/h263/data.rs +++ b/nihav-codec-support/src/codecs/h263/data.rs @@ -63,6 +63,8 @@ pub const H263_MBTYPE_B: &[(u8, u8)] = &[ (7, 6), (4, 6), (5, 6), (1, 6), (1, 7), (1, 8), (1, 10) ]; +pub const H263_CHROMA_ROUND: [i16; 16] = [ 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1 ]; + // 0x1 - direct, 0x2 - has quant, 0x4 - has CBP, 0x8 - has dquant, 0x10 - has fwd, 0x20 - has bwd, 0x40 - intra pub const H263_MBB_CAP_CODED: u8 = 0x2; diff --git a/nihav-codec-support/src/codecs/h263/decoder.rs b/nihav-codec-support/src/codecs/h263/decoder.rs index a78bf4f..7a88882 100644 --- a/nihav-codec-support/src/codecs/h263/decoder.rs +++ b/nihav-codec-support/src/codecs/h263/decoder.rs @@ -353,7 +353,7 @@ impl H263BaseDecoder { self.mv_data.push(BlockMVInfo::Inter_1MV(mv)); } if let Some(ref srcbuf) = self.ipbs.get_lastref() { - bdsp.copy_blocks(&mut buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, mv); + bdsp.copy_blocks(&mut buf, srcbuf.clone(), mb_x * 16, mb_y * 16, mv); } if pinfo.is_pb() { mvi2.predict(mb_x, 0, false, binfo.get_mv(0), sstate.first_line, sstate.first_mb); @@ -362,11 +362,9 @@ impl H263BaseDecoder { let mut mv: [MV; 4] = [ZERO_MV, ZERO_MV, ZERO_MV, ZERO_MV]; for blk_no in 0..4 { mv[blk_no] = mvi.predict(mb_x, blk_no, true, binfo.get_mv(blk_no), sstate.first_line, sstate.first_mb); - if let Some(ref srcbuf) = self.ipbs.get_lastref() { - bdsp.copy_blocks(&mut buf, srcbuf, - mb_x * 16 + (blk_no & 1) * 8, - mb_y * 16 + (blk_no & 2) * 4, 8, 8, mv[blk_no]); - } + } + if let Some(ref srcbuf) = self.ipbs.get_lastref() { + bdsp.copy_blocks8x8(&mut buf, srcbuf.clone(), mb_x * 16, mb_y * 16, &mv); } if pinfo.is_pb() { for blk_no in 0..4 { @@ -392,7 +390,7 @@ impl H263BaseDecoder { mvi2.set_zero_mv(mb_x); } if let Some(ref srcbuf) = self.ipbs.get_lastref() { - bdsp.copy_blocks(&mut buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV); + bdsp.copy_blocks(&mut buf, srcbuf.clone(), mb_x * 16, mb_y * 16, ZERO_MV); } } else { let ref_mv_info = self.mv_data[mb_pos]; @@ -416,26 +414,28 @@ impl H263BaseDecoder { } if let (Some(ref fwd_buf), Some(ref bck_buf)) = (self.ipbs.get_nextref(), self.ipbs.get_lastref()) { if has_fwd && has_bwd { - bdsp.copy_blocks(&mut buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, fwd_mv); - bdsp.avg_blocks (&mut buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, bwd_mv); + bdsp.copy_blocks(&mut buf, fwd_buf.clone(), mb_x * 16, mb_y * 16, fwd_mv); + bdsp.avg_blocks (&mut buf, bck_buf.clone(), mb_x * 16, mb_y * 16, bwd_mv); } else if has_fwd { - bdsp.copy_blocks(&mut buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, fwd_mv); + bdsp.copy_blocks(&mut buf, fwd_buf.clone(), mb_x * 16, mb_y * 16, fwd_mv); } else { - bdsp.copy_blocks(&mut buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, bwd_mv); + bdsp.copy_blocks(&mut buf, bck_buf.clone(), mb_x * 16, mb_y * 16, bwd_mv); } } } else { if let BlockMVInfo::Inter_4MV(mvs) = ref_mv_info { + let mut mv_f = [ZERO_MV; 4]; + let mut mv_b = [ZERO_MV; 4]; for blk_no in 0..4 { let ref_mv = mvs[blk_no]; let ref_mv_fwd = ref_mv.scale(bsdiff, tsdiff); let ref_mv_bwd = ref_mv - ref_mv_fwd; - let xoff = mb_x * 16 + (blk_no & 1) * 8; - let yoff = mb_y * 16 + (blk_no & 2) * 4; - if let (Some(ref fwd_buf), Some(ref bck_buf)) = (self.ipbs.get_nextref(), self.ipbs.get_lastref()) { - bdsp.copy_blocks(&mut buf, fwd_buf, xoff, yoff, 8, 8, ref_mv_fwd); - bdsp.avg_blocks (&mut buf, bck_buf, xoff, yoff, 8, 8, ref_mv_bwd); - } + mv_f[blk_no] = ref_mv_fwd; + mv_b[blk_no] = ref_mv_bwd; + } + if let (Some(ref fwd_buf), Some(ref bck_buf)) = (self.ipbs.get_nextref(), self.ipbs.get_lastref()) { + bdsp.copy_blocks8x8(&mut buf, fwd_buf.clone(), mb_x * 16, mb_y * 16, &mv_f); + bdsp.avg_blocks8x8 (&mut buf, bck_buf.clone(), mb_x * 16, mb_y * 16, &mv_b); } } else { let ref_mv = if let BlockMVInfo::Inter_1MV(mv_) = ref_mv_info { mv_ } else { ZERO_MV }; @@ -443,8 +443,8 @@ impl H263BaseDecoder { let ref_mv_bwd = MV::b_sub(ref_mv, ref_mv_fwd, ZERO_MV, bsdiff, tsdiff); if let (Some(ref fwd_buf), Some(ref bck_buf)) = (self.ipbs.get_nextref(), self.ipbs.get_lastref()) { - bdsp.copy_blocks(&mut buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, ref_mv_fwd); - bdsp.avg_blocks (&mut buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, ref_mv_bwd); + bdsp.copy_blocks(&mut buf, fwd_buf.clone(), mb_x * 16, mb_y * 16, ref_mv_fwd); + bdsp.avg_blocks (&mut buf, bck_buf.clone(), mb_x * 16, mb_y * 16, ref_mv_bwd); } } mvi.set_zero_mv(mb_x); @@ -534,10 +534,10 @@ impl H263BaseDecoder { let fmt = formats::YUV420_FORMAT; let vinfo = NAVideoInfo::new(self.w, self.h, false, fmt); let bufinfo = alloc_video_buffer(vinfo, 4)?; - let mut b_buf = bufinfo.get_vbuf().unwrap(); + let b_buf = bufinfo.get_vbuf().unwrap(); if let (Some(ref bck_buf), Some(ref fwd_buf)) = (self.ipbs.get_nextref(), self.ipbs.get_lastref()) { - recon_b_frame(&mut b_buf, fwd_buf, bck_buf, self.mb_w, self.mb_h, self.b_data.as_slice(), bdsp); + recon_b_frame(b_buf, fwd_buf.clone(), bck_buf.clone(), self.mb_w, self.mb_h, self.b_data.as_slice(), bdsp); } self.b_data.truncate(0); @@ -545,7 +545,7 @@ impl H263BaseDecoder { } } -fn recon_b_frame(b_buf: &mut NAVideoBuffer, bck_buf: &NAVideoBuffer, fwd_buf: &NAVideoBuffer, +fn recon_b_frame(mut b_buf: NAVideoBufferRef, bck_buf: NAVideoBufferRef, fwd_buf: NAVideoBufferRef, mb_w: usize, mb_h: usize, b_data: &[BMB], bdsp: &BlockDSP) { let mut cbpi = CBPInfo::new(); let mut cur_mb = 0; @@ -557,22 +557,18 @@ fn recon_b_frame(b_buf: &mut NAVideoBuffer, bck_buf: &NAVideoBuffer, fwd let cbp = b_data[cur_mb].cbp; cbpi.set_cbp(mb_x, cbp); if num_mv == 1 { - bdsp.copy_blocks(b_buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, b_data[cur_mb].mv_b[0]); + bdsp.copy_blocks(&mut b_buf, fwd_buf.clone(), mb_x * 16, mb_y * 16, b_data[cur_mb].mv_b[0]); if !is_fwd { - bdsp.avg_blocks(b_buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, b_data[cur_mb].mv_f[0]); + bdsp.avg_blocks(&mut b_buf, bck_buf.clone(), mb_x * 16, mb_y * 16, b_data[cur_mb].mv_f[0]); } } else { - for blk_no in 0..4 { - let xpos = mb_x * 16 + (blk_no & 1) * 8; - let ypos = mb_y * 16 + (blk_no & 2) * 4; - bdsp.copy_blocks(b_buf, fwd_buf, xpos, ypos, 8, 8, b_data[cur_mb].mv_b[blk_no]); - if !is_fwd { - bdsp.avg_blocks(b_buf, bck_buf, xpos, ypos, 8, 8, b_data[cur_mb].mv_f[blk_no]); - } + bdsp.copy_blocks8x8(&mut b_buf, fwd_buf.clone(), mb_x * 16, mb_y * 16, &b_data[cur_mb].mv_b); + if !is_fwd { + bdsp.avg_blocks8x8(&mut b_buf, bck_buf.clone(), mb_x * 16, mb_y * 16, &b_data[cur_mb].mv_f); } } if cbp != 0 { - blockdsp::add_blocks(b_buf, mb_x, mb_y, &b_data[cur_mb].blk); + blockdsp::add_blocks(&mut b_buf, mb_x, mb_y, &b_data[cur_mb].blk); } cur_mb += 1; } diff --git a/nihav-codec-support/src/codecs/h263/mod.rs b/nihav-codec-support/src/codecs/h263/mod.rs index 33d71ba..8c3ca65 100644 --- a/nihav-codec-support/src/codecs/h263/mod.rs +++ b/nihav-codec-support/src/codecs/h263/mod.rs @@ -1,6 +1,6 @@ use nihav_core::codecs::DecoderResult; use super::{MV, ZERO_MV}; -use nihav_core::frame::NAVideoBuffer; +use nihav_core::frame::{NAVideoBuffer, NAVideoBufferRef}; #[allow(clippy::many_single_char_names)] pub mod code; @@ -19,8 +19,10 @@ pub trait BlockDecoder { pub trait BlockDSP { fn idct(&self, blk: &mut [i16; 64]); - fn copy_blocks(&self, dst: &mut NAVideoBuffer, src: &NAVideoBuffer, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV); - fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: &NAVideoBuffer, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV); + fn copy_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV); + fn copy_blocks8x8(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mvs: &[MV; 4]); + fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV); + fn avg_blocks8x8(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mvs: &[MV; 4]); fn filter_row(&self, buf: &mut NAVideoBuffer, mb_y: usize, mb_w: usize, cbpi: &CBPInfo); } diff --git a/nihav-realmedia/src/codecs/rv20.rs b/nihav-realmedia/src/codecs/rv20.rs index 7f24650..0d24b28 100644 --- a/nihav-realmedia/src/codecs/rv20.rs +++ b/nihav-realmedia/src/codecs/rv20.rs @@ -131,19 +131,63 @@ impl BlockDSP for RV20BlockDSP { idct!(&tmp[i..], 8, &mut blk[i..], 8, 1 << 19, 20, i16); } } - fn copy_blocks(&self, dst: &mut NAVideoBuffer, src: &NAVideoBuffer, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) { - let srcx = ((mv.x >> 1) as isize) + (xpos as isize); - let srcy = ((mv.y >> 1) as isize) + (ypos as isize); + 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; + let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 }); - blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_FUNCS); + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + 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); + } + 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 { + let xadd = (i & 1) * 8; + let yadd = (i & 2) * 4; + let mode = ((mvs[i].x & 1) + (mvs[i].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); + } + + let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize]; + let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize]; + let mode = ((cmx & 1) + (cmy & 1) * 2) as usize; + for plane in 1..3 { + blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_FUNCS); + } } - fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: &NAVideoBuffer, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) { - let srcx = ((mv.x >> 1) as isize) + (xpos as isize); - let srcy = ((mv.y >> 1) as isize) + (ypos as isize); + fn avg_blocks(&self, dst: &mut NAVideoBuffer, src: NAVideoBufferRef, xpos: usize, ypos: usize, mv: MV) { let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; + let cmode = (if (mv.x & 3) != 0 { 1 } else { 0 }) + (if (mv.y & 3) != 0 { 2 } else { 0 }); - blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_AVG_FUNCS); + let mut dst = NASimpleVideoFrame::from_video_buf(dst).unwrap(); + + 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); + } + 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 { + let xadd = (i & 1) * 8; + let yadd = (i & 2) * 4; + let mode = ((mvs[i].x & 1) + (mvs[i].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); + } + + let sum_mv = mvs[0] + mvs[1] + mvs[2] + mvs[3]; + let cmx = (sum_mv.x >> 3) + H263_CHROMA_ROUND[(sum_mv.x & 0xF) as usize]; + let cmy = (sum_mv.y >> 3) + H263_CHROMA_ROUND[(sum_mv.y & 0xF) as usize]; + let mode = ((cmx & 1) + (cmy & 1) * 2) as usize; + for plane in 1..3 { + blockdsp::copy_block(&mut dst, src.clone(), plane, xpos >> 1, ypos >> 1, cmx >> 1, cmy >> 1, 8, 8, 0, 1, mode, H263_INTERP_AVG_FUNCS); + } } fn filter_row(&self, buf: &mut NAVideoBuffer, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) { h263_filter_row(buf, mb_y, mb_w, cbpi)