]>
| Commit | Line | Data |
|---|---|---|
| c6004662 | 1 | //! Various pixel block manipulation functions. |
| b4d5b851 | 2 | use nihav_core::frame::*; |
| cf64af13 | 3 | |
| c6004662 | 4 | /// Puts YUV420 16x16 macroblock data onto picture in the requested place. |
| cf64af13 KS |
5 | pub fn put_blocks(buf: &mut NAVideoBuffer<u8>, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) { |
| 6 | let stridey = buf.get_stride(0); | |
| 7 | let strideu = buf.get_stride(1); | |
| 8 | let stridev = buf.get_stride(2); | |
| 9 | let mut idxy = buf.get_offset(0) + xpos * 16 + ypos * 16 * stridey; | |
| 10 | let mut idxu = buf.get_offset(1) + xpos * 8 + ypos * 8 * strideu; | |
| 11 | let mut idxv = buf.get_offset(2) + xpos * 8 + ypos * 8 * stridev; | |
| 12 | ||
| 1a967e6b | 13 | let data = buf.get_data_mut().unwrap(); |
| 9037cf6b | 14 | let framebuf: &mut [u8] = data.as_mut_slice(); |
| cf64af13 KS |
15 | |
| 16 | for j in 0..8 { | |
| 17 | for k in 0..8 { | |
| 18 | let mut v = blk[0][k + j * 8]; | |
| e243ceb4 | 19 | if v < 0 { v = 0; } else if v > 255 { v = 255; } |
| cf64af13 KS |
20 | framebuf[idxy + k] = v as u8; |
| 21 | } | |
| 22 | for k in 0..8 { | |
| 23 | let mut v = blk[1][k + j * 8]; | |
| e243ceb4 | 24 | if v < 0 { v = 0; } else if v > 255 { v = 255; } |
| cf64af13 KS |
25 | framebuf[idxy + k + 8] = v as u8; |
| 26 | } | |
| 27 | idxy += stridey; | |
| 28 | } | |
| 29 | for j in 0..8 { | |
| 30 | for k in 0..8 { | |
| 31 | let mut v = blk[2][k + j * 8]; | |
| e243ceb4 | 32 | if v < 0 { v = 0; } else if v > 255 { v = 255; } |
| cf64af13 KS |
33 | framebuf[idxy + k] = v as u8; |
| 34 | } | |
| 35 | for k in 0..8 { | |
| 36 | let mut v = blk[3][k + j * 8]; | |
| e243ceb4 | 37 | if v < 0 { v = 0; } else if v > 255 { v = 255; } |
| cf64af13 KS |
38 | framebuf[idxy + k + 8] = v as u8; |
| 39 | } | |
| 40 | idxy += stridey; | |
| 41 | } | |
| 42 | ||
| 43 | for j in 0..8 { | |
| 44 | for k in 0..8 { | |
| 45 | let mut v = blk[4][k + j * 8]; | |
| e243ceb4 | 46 | if v < 0 { v = 0; } else if v > 255 { v = 255; } |
| cf64af13 KS |
47 | framebuf[idxu + k] = v as u8; |
| 48 | } | |
| 49 | for k in 0..8 { | |
| 50 | let mut v = blk[5][k + j * 8]; | |
| e243ceb4 | 51 | if v < 0 { v = 0; } else if v > 255 { v = 255; } |
| cf64af13 KS |
52 | framebuf[idxv + k] = v as u8; |
| 53 | } | |
| 54 | idxu += strideu; | |
| 55 | idxv += stridev; | |
| 56 | } | |
| 57 | } | |
| 58 | ||
| c6004662 | 59 | /// Adds YUV420 16x16 macroblock coefficients to the picture in the requested place. |
| cf64af13 KS |
60 | pub fn add_blocks(buf: &mut NAVideoBuffer<u8>, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) { |
| 61 | let stridey = buf.get_stride(0); | |
| 62 | let strideu = buf.get_stride(1); | |
| 63 | let stridev = buf.get_stride(2); | |
| 64 | let mut idxy = buf.get_offset(0) + xpos * 16 + ypos * 16 * stridey; | |
| 65 | let mut idxu = buf.get_offset(1) + xpos * 8 + ypos * 8 * strideu; | |
| 66 | let mut idxv = buf.get_offset(2) + xpos * 8 + ypos * 8 * stridev; | |
| 67 | ||
| 1a967e6b | 68 | let data = buf.get_data_mut().unwrap(); |
| 9037cf6b | 69 | let framebuf: &mut [u8] = data.as_mut_slice(); |
| cf64af13 KS |
70 | |
| 71 | for j in 0..8 { | |
| 72 | for k in 0..8 { | |
| e243ceb4 KS |
73 | let mut v = blk[0][k + j * 8] + i16::from(framebuf[idxy + k]); |
| 74 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
| cf64af13 KS |
75 | framebuf[idxy + k] = v as u8; |
| 76 | } | |
| 77 | for k in 0..8 { | |
| e243ceb4 KS |
78 | let mut v = blk[1][k + j * 8] + i16::from(framebuf[idxy + k + 8]); |
| 79 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
| cf64af13 KS |
80 | framebuf[idxy + k + 8] = v as u8; |
| 81 | } | |
| 82 | idxy += stridey; | |
| 83 | } | |
| 84 | for j in 0..8 { | |
| 85 | for k in 0..8 { | |
| e243ceb4 KS |
86 | let mut v = blk[2][k + j * 8] + i16::from(framebuf[idxy + k]); |
| 87 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
| cf64af13 KS |
88 | framebuf[idxy + k] = v as u8; |
| 89 | } | |
| 90 | for k in 0..8 { | |
| e243ceb4 KS |
91 | let mut v = blk[3][k + j * 8] + i16::from(framebuf[idxy + k + 8]); |
| 92 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
| cf64af13 KS |
93 | framebuf[idxy + k + 8] = v as u8; |
| 94 | } | |
| 95 | idxy += stridey; | |
| 96 | } | |
| 97 | ||
| 98 | for j in 0..8 { | |
| 99 | for k in 0..8 { | |
| e243ceb4 KS |
100 | let mut v = blk[4][k + j * 8] + i16::from(framebuf[idxu + k]); |
| 101 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
| cf64af13 KS |
102 | framebuf[idxu + k] = v as u8; |
| 103 | } | |
| 104 | for k in 0..8 { | |
| e243ceb4 KS |
105 | let mut v = blk[5][k + j * 8] + i16::from(framebuf[idxv + k]); |
| 106 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
| cf64af13 KS |
107 | framebuf[idxv + k] = v as u8; |
| 108 | } | |
| 109 | idxu += strideu; | |
| 110 | idxv += stridev; | |
| 111 | } | |
| 112 | } | |
| 113 | ||
| c6004662 | 114 | /// Copies block from the picture with pixels beyond the picture borders being replaced with replicated edge pixels. |
| 86081fed | 115 | pub fn edge_emu(src: &NAVideoBuffer<u8>, xpos: isize, ypos: isize, bw: usize, bh: usize, dst: &mut [u8], dstride: usize, comp: usize, align: u8) { |
| cf64af13 KS |
116 | let stride = src.get_stride(comp); |
| 117 | let offs = src.get_offset(comp); | |
| 86081fed KS |
118 | let (w_, h_) = src.get_dimensions(comp); |
| 119 | let (hss, vss) = src.get_info().get_format().get_chromaton(comp).unwrap().get_subsampling(); | |
| cf64af13 KS |
120 | let data = src.get_data(); |
| 121 | let framebuf: &[u8] = data.as_slice(); | |
| 122 | ||
| 86081fed KS |
123 | let (w, h) = if align == 0 { |
| 124 | (w_, h_) | |
| 125 | } else { | |
| 126 | let wa = if align > hss { (1 << (align - hss)) - 1 } else { 0 }; | |
| 127 | let ha = if align > vss { (1 << (align - vss)) - 1 } else { 0 }; | |
| 128 | ((w_ + wa) & !wa, (h_ + ha) & !ha) | |
| 129 | }; | |
| 130 | ||
| cf64af13 KS |
131 | for y in 0..bh { |
| 132 | let srcy; | |
| 133 | if (y as isize) + ypos < 0 { srcy = 0; } | |
| 134 | else if (y as isize) + ypos >= (h as isize) { srcy = h - 1; } | |
| 135 | else { srcy = ((y as isize) + ypos) as usize; } | |
| 136 | ||
| 137 | for x in 0..bw { | |
| 138 | let srcx; | |
| 139 | if (x as isize) + xpos < 0 { srcx = 0; } | |
| 140 | else if (x as isize) + xpos >= (w as isize) { srcx = w - 1; } | |
| 141 | else { srcx = ((x as isize) + xpos) as usize; } | |
| 142 | dst[x + y * dstride] = framebuf[offs + srcx + srcy * stride]; | |
| 143 | } | |
| 144 | } | |
| 145 | } | |
| 146 | ||
| c6004662 KS |
147 | /// A generic type for motion interpolation function used by [`copy_blocks`] |
| 148 | /// | |
| 149 | /// The function expects following parameters: | |
| 150 | /// * destination buffer | |
| 151 | /// * destination buffer stride | |
| 152 | /// * source buffer | |
| 153 | /// * source buffer stride | |
| 154 | /// * block width | |
| 155 | /// * block height | |
| 156 | /// | |
| 157 | /// [`copy_blocks`]: ./fn.copy_blocks.html | |
| fdb4b2fb KS |
158 | pub type BlkInterpFunc = fn(&mut [u8], usize, &[u8], usize, usize, usize); |
| 159 | ||
| c6004662 KS |
160 | /// Performs motion compensation on YUV420 macroblock. |
| 161 | /// | |
| 162 | /// Arguments: | |
| 163 | /// * `dx` and `dy` - destination coordinates | |
| 164 | /// * `sx` and `sy` - source coordinates | |
| 165 | /// * `bw` and `bh` - block dimensions | |
| 166 | /// * `preborder` and `postborder` - number of pixels before and after interpolated one used by the interpolation filter. | |
| 167 | /// * `mode` - interpolation mode (essentially the index for the `interp` array) | |
| cf64af13 KS |
168 | pub fn copy_blocks(dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, |
| 169 | dx: usize, dy: usize, sx: isize, sy: isize, bw: usize, bh: usize, | |
| 170 | preborder: usize, postborder: usize, | |
| fdb4b2fb | 171 | mode: usize, interp: &[BlkInterpFunc]) |
| cf64af13 KS |
172 | { |
| 173 | let pre = if mode != 0 { preborder as isize } else { 0 }; | |
| 174 | let post = if mode != 0 { postborder as isize } else { 0 }; | |
| 175 | let (w, h) = src.get_dimensions(0); | |
| 176 | ||
| 177 | if (sx - pre < 0) || ((sx >> 1) - pre < 0) || (sx + (bw as isize) + post > (w as isize)) || | |
| 178 | (sy - pre < 0) || ((sy >> 1) - pre < 0) || (sy + (bh as isize) + post > (h as isize)) { | |
| 179 | let ebuf_stride: usize = 32; | |
| e243ceb4 | 180 | let mut ebuf: Vec<u8> = vec![0; ebuf_stride * (bh + ((pre + post) as usize))]; |
| cf64af13 KS |
181 | |
| 182 | for comp in 0..3 { | |
| 2bfdf329 | 183 | let dstride = dst.get_stride(comp); |
| cf64af13 | 184 | let doff = dst.get_offset(comp); |
| 1a967e6b | 185 | let ddta = dst.get_data_mut().unwrap(); |
| 4a9d2671 | 186 | let dbuf: &mut [u8] = ddta.as_mut_slice(); |
| cf64af13 KS |
187 | let x = if comp > 0 { dx/2 } else { dx }; |
| 188 | let y = if comp > 0 { dy/2 } else { dy }; | |
| 189 | let sx_ = (if comp > 0 { sx >> 1 } else { sx }) - pre; | |
| 190 | let sy_ = (if comp > 0 { sy >> 1 } else { sy }) - pre; | |
| 191 | let bw_ = (if comp > 0 { bw/2 } else { bw }) + ((pre + post) as usize); | |
| 192 | let bh_ = (if comp > 0 { bh/2 } else { bh }) + ((pre + post) as usize); | |
| 193 | edge_emu(src, sx_ - pre, sy_ - pre, bw_, bh_, | |
| 86081fed | 194 | ebuf.as_mut_slice(), ebuf_stride, comp, 0); |
| cf64af13 KS |
195 | let bw_ = if comp > 0 { bw/2 } else { bw }; |
| 196 | let bh_ = if comp > 0 { bh/2 } else { bh }; | |
| 197 | (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, ebuf.as_slice(), ebuf_stride, bw_, bh_); | |
| 198 | } | |
| cf64af13 KS |
199 | } else { |
| 200 | for comp in 0..3 { | |
| 201 | let sstride = src.get_stride(comp); | |
| 202 | let soff = src.get_offset(comp); | |
| 203 | let sdta = src.get_data(); | |
| 204 | let sbuf: &[u8] = sdta.as_slice(); | |
| 2bfdf329 | 205 | let dstride = dst.get_stride(comp); |
| cf64af13 | 206 | let doff = dst.get_offset(comp); |
| 1a967e6b | 207 | let ddta = dst.get_data_mut().unwrap(); |
| 4a9d2671 | 208 | let dbuf: &mut [u8] = ddta.as_mut_slice(); |
| cf64af13 KS |
209 | let x = if comp > 0 { dx/2 } else { dx }; |
| 210 | let y = if comp > 0 { dy/2 } else { dy }; | |
| 211 | let sx_ = ((if comp > 0 { sx >> 1 } else { sx }) - pre) as usize; | |
| 212 | let sy_ = ((if comp > 0 { sy >> 1 } else { sy }) - pre) as usize; | |
| 213 | let bw_ = if comp > 0 { bw/2 } else { bw }; | |
| 214 | let bh_ = if comp > 0 { bh/2 } else { bh }; | |
| 215 | (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, &sbuf[(soff + sx_ + sy_ * sstride)..], sstride, bw_, bh_); | |
| 216 | } | |
| 217 | } | |
| 218 | } | |
| c6670064 | 219 | |
| c6004662 KS |
220 | /// Performs motion compensation on arbitrary block on some plane. |
| 221 | /// | |
| 222 | /// See [`copy_blocks`] for the arguments explanation. | |
| 223 | /// | |
| 224 | /// [`copy_blocks`]: ./fn.copy_blocks.html | |
| c6670064 KS |
225 | pub fn copy_block(dst: &mut NASimpleVideoFrame<u8>, src: NAVideoBufferRef<u8>, comp: usize, |
| 226 | dx: usize, dy: usize, mv_x: i16, mv_y: i16, bw: usize, bh: usize, | |
| 227 | preborder: usize, postborder: usize, | |
| 228 | mode: usize, interp: &[BlkInterpFunc]) | |
| 229 | { | |
| 230 | let pre = if mode != 0 { preborder as isize } else { 0 }; | |
| 231 | let post = if mode != 0 { postborder as isize } else { 0 }; | |
| 232 | let (w, h) = src.get_dimensions(comp); | |
| 233 | let sx = (dx as isize) + (mv_x as isize); | |
| 234 | let sy = (dy as isize) + (mv_y as isize); | |
| 235 | ||
| 236 | if (sx - pre < 0) || (sx + (bw as isize) + post > (w as isize)) || | |
| 237 | (sy - pre < 0) || (sy + (bh as isize) + post > (h as isize)) { | |
| 238 | let ebuf_stride: usize = 32; | |
| 239 | let mut ebuf: Vec<u8> = vec![0; ebuf_stride * (bh + ((pre + post) as usize))]; | |
| 240 | ||
| 241 | let dstride = dst.stride[comp]; | |
| 242 | let doff = dst.offset[comp]; | |
| 243 | let edge = (pre + post) as usize; | |
| 244 | edge_emu(&src, sx - pre, sy - pre, bw + edge, bh + edge, | |
| 86081fed | 245 | ebuf.as_mut_slice(), ebuf_stride, comp, 0); |
| c6670064 KS |
246 | (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride, |
| 247 | ebuf.as_slice(), ebuf_stride, bw, bh); | |
| 248 | } else { | |
| 249 | let sstride = src.get_stride(comp); | |
| 250 | let soff = src.get_offset(comp); | |
| 251 | let sdta = src.get_data(); | |
| 252 | let sbuf: &[u8] = sdta.as_slice(); | |
| 253 | let dstride = dst.stride[comp]; | |
| 254 | let doff = dst.offset[comp]; | |
| 255 | let saddr = soff + ((sx - pre) as usize) + ((sy - pre) as usize) * sstride; | |
| 256 | (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride, | |
| 257 | &sbuf[saddr..], sstride, bw, bh); | |
| 258 | } | |
| 259 | } | |
| 0faa067b KS |
260 | |
| 261 | fn hpel_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) | |
| 262 | { | |
| 263 | let mut didx = 0; | |
| 264 | let mut sidx = 0; | |
| 265 | for _ in 0..bh { | |
| 266 | dst[didx..][..bw].copy_from_slice(&src[sidx..][..bw]); | |
| 267 | didx += dstride; | |
| 268 | sidx += sstride; | |
| 269 | } | |
| 270 | } | |
| 271 | ||
| 272 | fn hpel_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) | |
| 273 | { | |
| 274 | let mut didx = 0; | |
| 275 | let mut sidx = 0; | |
| 276 | for _ in 0..bh { | |
| 277 | for x in 0..bw { dst[didx + x] = ((u16::from(src[sidx + x]) + u16::from(src[sidx + x + 1]) + 1) >> 1) as u8; } | |
| 278 | didx += dstride; | |
| 279 | sidx += sstride; | |
| 280 | } | |
| 281 | } | |
| 282 | ||
| 283 | fn hpel_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) | |
| 284 | { | |
| 285 | let mut didx = 0; | |
| 286 | let mut sidx = 0; | |
| 287 | for _ in 0..bh { | |
| 288 | for x in 0..bw { dst[didx + x] = ((u16::from(src[sidx + x]) + u16::from(src[sidx + x + sstride]) + 1) >> 1) as u8; } | |
| 289 | didx += dstride; | |
| 290 | sidx += sstride; | |
| 291 | } | |
| 292 | } | |
| 293 | ||
| 294 | fn hpel_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) | |
| 295 | { | |
| 296 | let mut didx = 0; | |
| 297 | let mut sidx = 0; | |
| 298 | for _ in 0..bh { | |
| 299 | for x in 0..bw { | |
| 300 | dst[didx + x] = ((u16::from(src[sidx + x]) + | |
| 301 | u16::from(src[sidx + x + 1]) + | |
| 302 | u16::from(src[sidx + x + sstride]) + | |
| 303 | u16::from(src[sidx + x + sstride + 1]) + 2) >> 2) as u8; | |
| 304 | } | |
| 305 | didx += dstride; | |
| 306 | sidx += sstride; | |
| 307 | } | |
| 308 | } | |
| 309 | ||
| 310 | /// Half-pixel interpolation functions. | |
| 311 | pub const HALFPEL_INTERP_FUNCS: &[BlkInterpFunc] = &[ | |
| 312 | hpel_interp00, hpel_interp01, hpel_interp10, hpel_interp11 ]; | |
| 313 |