]>
Commit | Line | Data |
---|---|---|
1 | //! Various pixel block manipulation functions. | |
2 | use crate::frame::*; | |
3 | ||
4 | /// Puts YUV420 16x16 macroblock data onto picture in the requested place. | |
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 | ||
13 | let data = buf.get_data_mut().unwrap(); | |
14 | let framebuf: &mut [u8] = data.as_mut_slice(); | |
15 | ||
16 | for j in 0..8 { | |
17 | for k in 0..8 { | |
18 | let mut v = blk[0][k + j * 8]; | |
19 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
20 | framebuf[idxy + k] = v as u8; | |
21 | } | |
22 | for k in 0..8 { | |
23 | let mut v = blk[1][k + j * 8]; | |
24 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
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]; | |
32 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
33 | framebuf[idxy + k] = v as u8; | |
34 | } | |
35 | for k in 0..8 { | |
36 | let mut v = blk[3][k + j * 8]; | |
37 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
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]; | |
46 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
47 | framebuf[idxu + k] = v as u8; | |
48 | } | |
49 | for k in 0..8 { | |
50 | let mut v = blk[5][k + j * 8]; | |
51 | if v < 0 { v = 0; } else if v > 255 { v = 255; } | |
52 | framebuf[idxv + k] = v as u8; | |
53 | } | |
54 | idxu += strideu; | |
55 | idxv += stridev; | |
56 | } | |
57 | } | |
58 | ||
59 | /// Adds YUV420 16x16 macroblock coefficients to the picture in the requested place. | |
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 | ||
68 | let data = buf.get_data_mut().unwrap(); | |
69 | let framebuf: &mut [u8] = data.as_mut_slice(); | |
70 | ||
71 | for j in 0..8 { | |
72 | for k in 0..8 { | |
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; } | |
75 | framebuf[idxy + k] = v as u8; | |
76 | } | |
77 | for k in 0..8 { | |
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; } | |
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 { | |
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; } | |
88 | framebuf[idxy + k] = v as u8; | |
89 | } | |
90 | for k in 0..8 { | |
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; } | |
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 { | |
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; } | |
102 | framebuf[idxu + k] = v as u8; | |
103 | } | |
104 | for k in 0..8 { | |
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; } | |
107 | framebuf[idxv + k] = v as u8; | |
108 | } | |
109 | idxu += strideu; | |
110 | idxv += stridev; | |
111 | } | |
112 | } | |
113 | ||
114 | /// Copies block from the picture with pixels beyond the picture borders being replaced with replicated edge pixels. | |
115 | pub fn edge_emu(src: &NAVideoBuffer<u8>, xpos: isize, ypos: isize, bw: usize, bh: usize, dst: &mut [u8], dstride: usize, comp: usize) { | |
116 | let stride = src.get_stride(comp); | |
117 | let offs = src.get_offset(comp); | |
118 | let (w, h) = src.get_dimensions(comp); | |
119 | let data = src.get_data(); | |
120 | let framebuf: &[u8] = data.as_slice(); | |
121 | ||
122 | for y in 0..bh { | |
123 | let srcy; | |
124 | if (y as isize) + ypos < 0 { srcy = 0; } | |
125 | else if (y as isize) + ypos >= (h as isize) { srcy = h - 1; } | |
126 | else { srcy = ((y as isize) + ypos) as usize; } | |
127 | ||
128 | for x in 0..bw { | |
129 | let srcx; | |
130 | if (x as isize) + xpos < 0 { srcx = 0; } | |
131 | else if (x as isize) + xpos >= (w as isize) { srcx = w - 1; } | |
132 | else { srcx = ((x as isize) + xpos) as usize; } | |
133 | dst[x + y * dstride] = framebuf[offs + srcx + srcy * stride]; | |
134 | } | |
135 | } | |
136 | } | |
137 | ||
138 | /// A generic type for motion interpolation function used by [`copy_blocks`] | |
139 | /// | |
140 | /// The function expects following parameters: | |
141 | /// * destination buffer | |
142 | /// * destination buffer stride | |
143 | /// * source buffer | |
144 | /// * source buffer stride | |
145 | /// * block width | |
146 | /// * block height | |
147 | /// | |
148 | /// [`copy_blocks`]: ./fn.copy_blocks.html | |
149 | pub type BlkInterpFunc = fn(&mut [u8], usize, &[u8], usize, usize, usize); | |
150 | ||
151 | /// Performs motion compensation on YUV420 macroblock. | |
152 | /// | |
153 | /// Arguments: | |
154 | /// * `dx` and `dy` - destination coordinates | |
155 | /// * `sx` and `sy` - source coordinates | |
156 | /// * `bw` and `bh` - block dimensions | |
157 | /// * `preborder` and `postborder` - number of pixels before and after interpolated one used by the interpolation filter. | |
158 | /// * `mode` - interpolation mode (essentially the index for the `interp` array) | |
159 | pub fn copy_blocks(dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, | |
160 | dx: usize, dy: usize, sx: isize, sy: isize, bw: usize, bh: usize, | |
161 | preborder: usize, postborder: usize, | |
162 | mode: usize, interp: &[BlkInterpFunc]) | |
163 | { | |
164 | let pre = if mode != 0 { preborder as isize } else { 0 }; | |
165 | let post = if mode != 0 { postborder as isize } else { 0 }; | |
166 | let (w, h) = src.get_dimensions(0); | |
167 | ||
168 | if (sx - pre < 0) || ((sx >> 1) - pre < 0) || (sx + (bw as isize) + post > (w as isize)) || | |
169 | (sy - pre < 0) || ((sy >> 1) - pre < 0) || (sy + (bh as isize) + post > (h as isize)) { | |
170 | let ebuf_stride: usize = 32; | |
171 | let mut ebuf: Vec<u8> = vec![0; ebuf_stride * (bh + ((pre + post) as usize))]; | |
172 | ||
173 | for comp in 0..3 { | |
174 | let dstride = dst.get_stride(comp); | |
175 | let doff = dst.get_offset(comp); | |
176 | let ddta = dst.get_data_mut().unwrap(); | |
177 | let dbuf: &mut [u8] = ddta.as_mut_slice(); | |
178 | let x = if comp > 0 { dx/2 } else { dx }; | |
179 | let y = if comp > 0 { dy/2 } else { dy }; | |
180 | let sx_ = (if comp > 0 { sx >> 1 } else { sx }) - pre; | |
181 | let sy_ = (if comp > 0 { sy >> 1 } else { sy }) - pre; | |
182 | let bw_ = (if comp > 0 { bw/2 } else { bw }) + ((pre + post) as usize); | |
183 | let bh_ = (if comp > 0 { bh/2 } else { bh }) + ((pre + post) as usize); | |
184 | edge_emu(src, sx_ - pre, sy_ - pre, bw_, bh_, | |
185 | ebuf.as_mut_slice(), ebuf_stride, comp); | |
186 | let bw_ = if comp > 0 { bw/2 } else { bw }; | |
187 | let bh_ = if comp > 0 { bh/2 } else { bh }; | |
188 | (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, ebuf.as_slice(), ebuf_stride, bw_, bh_); | |
189 | } | |
190 | } else { | |
191 | for comp in 0..3 { | |
192 | let sstride = src.get_stride(comp); | |
193 | let soff = src.get_offset(comp); | |
194 | let sdta = src.get_data(); | |
195 | let sbuf: &[u8] = sdta.as_slice(); | |
196 | let dstride = dst.get_stride(comp); | |
197 | let doff = dst.get_offset(comp); | |
198 | let ddta = dst.get_data_mut().unwrap(); | |
199 | let dbuf: &mut [u8] = ddta.as_mut_slice(); | |
200 | let x = if comp > 0 { dx/2 } else { dx }; | |
201 | let y = if comp > 0 { dy/2 } else { dy }; | |
202 | let sx_ = ((if comp > 0 { sx >> 1 } else { sx }) - pre) as usize; | |
203 | let sy_ = ((if comp > 0 { sy >> 1 } else { sy }) - pre) as usize; | |
204 | let bw_ = if comp > 0 { bw/2 } else { bw }; | |
205 | let bh_ = if comp > 0 { bh/2 } else { bh }; | |
206 | (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, &sbuf[(soff + sx_ + sy_ * sstride)..], sstride, bw_, bh_); | |
207 | } | |
208 | } | |
209 | } | |
210 | ||
211 | /// Performs motion compensation on arbitrary block on some plane. | |
212 | /// | |
213 | /// See [`copy_blocks`] for the arguments explanation. | |
214 | /// | |
215 | /// [`copy_blocks`]: ./fn.copy_blocks.html | |
216 | pub fn copy_block(dst: &mut NASimpleVideoFrame<u8>, src: NAVideoBufferRef<u8>, comp: usize, | |
217 | dx: usize, dy: usize, mv_x: i16, mv_y: i16, bw: usize, bh: usize, | |
218 | preborder: usize, postborder: usize, | |
219 | mode: usize, interp: &[BlkInterpFunc]) | |
220 | { | |
221 | let pre = if mode != 0 { preborder as isize } else { 0 }; | |
222 | let post = if mode != 0 { postborder as isize } else { 0 }; | |
223 | let (w, h) = src.get_dimensions(comp); | |
224 | let sx = (dx as isize) + (mv_x as isize); | |
225 | let sy = (dy as isize) + (mv_y as isize); | |
226 | ||
227 | if (sx - pre < 0) || (sx + (bw as isize) + post > (w as isize)) || | |
228 | (sy - pre < 0) || (sy + (bh as isize) + post > (h as isize)) { | |
229 | let ebuf_stride: usize = 32; | |
230 | let mut ebuf: Vec<u8> = vec![0; ebuf_stride * (bh + ((pre + post) as usize))]; | |
231 | ||
232 | let dstride = dst.stride[comp]; | |
233 | let doff = dst.offset[comp]; | |
234 | let edge = (pre + post) as usize; | |
235 | edge_emu(&src, sx - pre, sy - pre, bw + edge, bh + edge, | |
236 | ebuf.as_mut_slice(), ebuf_stride, comp); | |
237 | (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride, | |
238 | ebuf.as_slice(), ebuf_stride, bw, bh); | |
239 | } else { | |
240 | let sstride = src.get_stride(comp); | |
241 | let soff = src.get_offset(comp); | |
242 | let sdta = src.get_data(); | |
243 | let sbuf: &[u8] = sdta.as_slice(); | |
244 | let dstride = dst.stride[comp]; | |
245 | let doff = dst.offset[comp]; | |
246 | let saddr = soff + ((sx - pre) as usize) + ((sy - pre) as usize) * sstride; | |
247 | (interp[mode])(&mut dst.data[doff + dx + dy * dstride..], dstride, | |
248 | &sbuf[saddr..], sstride, bw, bh); | |
249 | } | |
250 | } |