X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-core%2Fsrc%2Fcodecs%2Fblockdsp.rs;h=0b66527ea9b67e1098416b3a2022a0ff288b9fe5;hb=2b8bf9a03242bbd6e80091082a50ec13b1a95143;hp=70b842037522470f49dc1d563b8f80e2305c0cbd;hpb=e243ceb4d694cc08767ad70027bb6963f4cefea3;p=nihav.git diff --git a/nihav-core/src/codecs/blockdsp.rs b/nihav-core/src/codecs/blockdsp.rs index 70b8420..0b66527 100644 --- a/nihav-core/src/codecs/blockdsp.rs +++ b/nihav-core/src/codecs/blockdsp.rs @@ -1,5 +1,7 @@ +//! Various pixel block manipulation functions. use crate::frame::*; +/// Puts YUV420 16x16 macroblock data onto picture in the requested place. pub fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) { let stridey = buf.get_stride(0); let strideu = buf.get_stride(1); @@ -54,6 +56,7 @@ pub fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[ } } +/// Adds YUV420 16x16 macroblock coefficients to the picture in the requested place. pub fn add_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) { let stridey = buf.get_stride(0); let strideu = buf.get_stride(1); @@ -108,6 +111,7 @@ pub fn add_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[ } } +/// Copies block from the picture with pixels beyond the picture borders being replaced with replicated edge pixels. pub fn edge_emu(src: &NAVideoBuffer, xpos: isize, ypos: isize, bw: usize, bh: usize, dst: &mut [u8], dstride: usize, comp: usize) { let stride = src.get_stride(comp); let offs = src.get_offset(comp); @@ -131,10 +135,31 @@ pub fn edge_emu(src: &NAVideoBuffer, xpos: isize, ypos: isize, bw: usize, bh } } +/// A generic type for motion interpolation function used by [`copy_blocks`] +/// +/// The function expects following parameters: +/// * destination buffer +/// * destination buffer stride +/// * source buffer +/// * source buffer stride +/// * block width +/// * block height +/// +/// [`copy_blocks`]: ./fn.copy_blocks.html +pub type BlkInterpFunc = fn(&mut [u8], usize, &[u8], usize, usize, usize); + +/// Performs motion compensation on YUV420 macroblock. +/// +/// Arguments: +/// * `dx` and `dy` - destination coordinates +/// * `sx` and `sy` - source coordinates +/// * `bw` and `bh` - block dimensions +/// * `preborder` and `postborder` - number of pixels before and after interpolated one used by the interpolation filter. +/// * `mode` - interpolation mode (essentially the index for the `interp` array) pub fn copy_blocks(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, dx: usize, dy: usize, sx: isize, sy: isize, bw: usize, bh: usize, preborder: usize, postborder: usize, - mode: usize, interp: &[fn(&mut [u8], usize, &[u8], usize, usize, 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 }; @@ -182,3 +207,44 @@ pub fn copy_blocks(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, } } } + +/// Performs motion compensation on arbitrary block on some plane. +/// +/// See [`copy_blocks`] for the arguments explanation. +/// +/// [`copy_blocks`]: ./fn.copy_blocks.html +pub fn copy_block(dst: &mut NASimpleVideoFrame, src: NAVideoBufferRef, 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 mut ebuf: Vec = vec![0; ebuf_stride * (bh + ((pre + post) as usize))]; + + 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.as_mut_slice(), ebuf_stride, comp); + (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride, + ebuf.as_slice(), 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); + } +}