]>
Commit | Line | Data |
---|---|---|
c5d5793c KS |
1 | use nihav_codec_support::codecs::{MV, ZERO_MV}; |
2 | use super::super::vp78::{PredMode, MVSplitMode, SubMVRef}; | |
3 | use super::super::vp78dsp::*; | |
4 | use super::blocks::*; | |
5 | use super::coder::*; | |
6 | use super::models::*; | |
7 | use super::motion_est::*; | |
8 | use super::rdo::*; | |
9 | ||
10 | pub struct IntraModePredCtx<'a> { | |
11 | pub metric: &'a RateDistMetric, | |
12 | pub models: &'a VP7Models, | |
13 | pub q: usize, | |
14 | pub tr: [u8; 4], | |
15 | pub ipred_y: IPredContext, | |
16 | pub ipred_u: IPredContext, | |
17 | pub ipred_v: IPredContext, | |
18 | pub pctx: BlockPCtx, | |
19 | } | |
20 | ||
21 | struct UniqueList<A> { | |
22 | list: [A; 4], | |
23 | fill: usize, | |
24 | } | |
25 | ||
26 | impl<A:Copy+Default+PartialEq> UniqueList<A> { | |
27 | fn new() -> Self { | |
28 | Self { list: [A::default(); 4], fill: 0 } | |
29 | } | |
30 | fn add(&mut self, cand: A) { | |
31 | if self.fill == self.list.len() { return; } | |
32 | let mut unique = true; | |
33 | for el in self.list.iter().take(self.fill) { | |
34 | if *el == cand { | |
35 | unique = false; | |
36 | break; | |
37 | } | |
38 | } | |
39 | if unique { | |
40 | self.list[self.fill] = cand; | |
41 | self.fill += 1; | |
42 | } | |
43 | } | |
44 | fn get_list(&self) -> &[A] { &self.list[..self.fill] } | |
45 | } | |
46 | ||
47 | pub fn try_i4x4_pred(mut src: LumaIterator, modes: &mut [PredMode; 16], res: &mut Residue, new: &mut [u8; 256], pctx: &IntraModePredCtx, ref_best_dist: u32) -> u32 { | |
48 | const PRED4X4: [PredMode; 10] = [ | |
49 | PredMode::DCPred, PredMode::HPred, PredMode::VPred, PredMode::TMPred, | |
50 | PredMode::LDPred, PredMode::RDPred, PredMode::VRPred, PredMode::VLPred, | |
51 | PredMode::HUPred, PredMode::HDPred | |
52 | ]; | |
53 | ||
54 | let mut ipred4 = IPredContext::default(); | |
55 | let mut top = [0x80; 21]; | |
56 | let mut diff = [0i16; 16]; | |
57 | let mut yblk = [0u8; 16]; | |
58 | top[0] = pctx.ipred_y.tl; | |
59 | top[1..][..16].copy_from_slice(&pctx.ipred_y.top); | |
60 | top[17..].copy_from_slice(&pctx.tr); | |
61 | ||
62 | let mut tot_dist = 0; | |
63 | let mut nz_top = pctx.pctx.nz_y_top; | |
64 | let mut nz_left = pctx.pctx.nz_y_left; | |
65 | for y in 0..4 { | |
66 | let (l1, l2) = ipred4.left.split_at_mut(16 - y * 4); | |
67 | l1.copy_from_slice(&pctx.ipred_y.left[y * 4..]); | |
68 | for el in l2.iter_mut() { *el = 0x80; } | |
69 | ||
70 | ipred4.tl = if y == 0 { top[0] } else { pctx.ipred_y.left[y * 4 - 1] }; | |
71 | for x in 0..4 { | |
72 | let tsrc = &top[x * 4 + 1..]; | |
73 | let (t1, t2) = ipred4.top.split_at_mut(tsrc.len().min(16)); | |
74 | for (dst, &src) in t1.iter_mut().zip(tsrc.iter()) { *dst = src; } | |
75 | for el in t2.iter_mut() { *el = 0x80; } | |
76 | ||
77 | let mut best_mode = PredMode::DCPred; | |
78 | let mut best_dist = MAX_DIST; | |
79 | let mut best_has_nz = false; | |
80 | ||
81 | let srcblk = src.next().unwrap(); | |
82 | for &mode in PRED4X4.iter() { | |
83 | yblk.ipred4(4, mode, &ipred4); | |
84 | let mode_nits = b_mode_nits(mode); | |
85 | let blkctx = (nz_top[x] as u8) + (nz_left[y] as u8); | |
86 | let (dist1, has_nz) = pctx.metric.block_dist(&srcblk, &yblk, pctx.q, 3, blkctx, &pctx.models.coef_probs[3]); | |
87 | let dist = dist1 + pctx.metric.calc_metric(0, mode_nits); | |
88 | if dist < best_dist { | |
89 | best_mode = mode; | |
90 | best_dist = dist; | |
91 | best_has_nz = has_nz; | |
92 | if dist <= SMALL_DIST { | |
93 | break; | |
94 | } | |
95 | } | |
96 | } | |
97 | nz_top[x] = best_has_nz; | |
98 | nz_left[y] = best_has_nz; | |
99 | modes[x + y * 4] = best_mode; | |
100 | tot_dist += best_dist; | |
101 | if tot_dist >= ref_best_dist { | |
102 | return MAX_DIST; | |
103 | } | |
104 | ||
105 | yblk.ipred4(4, modes[x + y * 4], &ipred4); | |
106 | get_block_difference(&mut diff, &srcblk, &yblk); | |
107 | res.luma[x + y * 4] = diff; | |
108 | diff.fdct(); | |
109 | diff.requant_y(pctx.q); | |
110 | diff.idct(); | |
111 | ||
112 | let nblk = &mut new[x * 4 + y * 4 * 16..]; | |
113 | for (dst, (src, res)) in nblk.chunks_mut(16).zip(yblk.chunks(4).zip(diff.chunks(4))) { | |
114 | for (del, (&sel, &rel)) in dst.iter_mut().zip(src.iter().zip(res.iter())) { | |
115 | *del = (i16::from(sel) + rel).max(0).min(255) as u8; | |
116 | } | |
117 | } | |
118 | ||
119 | ipred4.tl = top[x * 4 + 4]; | |
120 | top[x * 4 + 1..][..4].copy_from_slice(&nblk[16 * 3..][..4]); | |
121 | for (dst, src) in ipred4.left[..4].iter_mut().zip(nblk.chunks(16)) { | |
122 | *dst = src[3]; | |
123 | } | |
124 | } | |
125 | } | |
126 | tot_dist | |
127 | } | |
128 | ||
129 | fn try_intra16_pred(sblk: &SrcBlock, newblk: &mut SrcBlock, res: &mut Residue, imctx: &IntraModePredCtx, ymode: PredMode) -> u32 { | |
130 | newblk.fill_ipred_luma(ymode, &imctx.ipred_y); | |
131 | ||
132 | for (dst, (src1, src2)) in res.luma.iter_mut().zip(sblk.luma_blocks().zip(newblk.luma_blocks())) { | |
133 | get_block_difference(dst, &src1, &src2); | |
134 | } | |
135 | ||
136 | let mut nits = 0; | |
137 | ||
138 | res.fdct_luma(); | |
139 | res.fdct_dc_block(); | |
140 | res.quant_luma(imctx.q); | |
141 | nits += estimate_subblock_nits(&res.dcs, 1, imctx.pctx.nz_y2, &imctx.models.coef_probs[1]); | |
142 | let mut nz_top = imctx.pctx.nz_y_top; | |
143 | let mut nz_left = imctx.pctx.nz_y_left; | |
144 | for (y, row) in res.luma.chunks(4).enumerate() { | |
145 | for (x, blk) in row.iter().enumerate() { | |
146 | let has_nz = blk.has_nz(); | |
147 | let pctx = (nz_top[x] as u8) + (nz_left[y] as u8); | |
148 | nits += estimate_subblock_nits(blk, 0, pctx, &imctx.models.coef_probs[0]); | |
149 | nz_top[x] = has_nz; | |
150 | nz_left[y] = has_nz; | |
151 | } | |
152 | } | |
153 | res.dequant_luma(); | |
154 | res.idct_luma(); | |
155 | ||
156 | let mut dist = 0; | |
157 | for (diff, (src1, src2)) in res.luma.iter().zip(sblk.luma_blocks().zip(newblk.luma_blocks())) { | |
158 | dist += get_difference_dist(&src1, &src2, diff); | |
159 | } | |
160 | ||
161 | imctx.metric.calc_metric(dist, nits) | |
162 | } | |
163 | ||
164 | pub fn select_intra_mode(sblk: &SrcBlock, newblk: &mut SrcBlock, res: &mut Residue, imctx: &IntraModePredCtx, ref_best_dist: u32, mb_type: MBType) -> MBType { | |
165 | const PRED16X16: [PredMode; 4] = [PredMode::DCPred, PredMode::HPred, PredMode::VPred, PredMode::TMPred]; | |
166 | ||
167 | let mut best_ymode = PredMode::DCPred; | |
168 | let mut y_best_dist = MAX_DIST; | |
169 | let mut use_i4 = false; | |
170 | let mut i4_modes = [PredMode::DCPred; 16]; | |
171 | if !sblk.is_flat() { | |
172 | for &ymode in PRED16X16.iter() { | |
173 | let dist = try_intra16_pred(sblk, newblk, res, imctx, ymode); | |
174 | ||
175 | if dist < y_best_dist { | |
176 | best_ymode = ymode; | |
177 | y_best_dist = dist; | |
178 | if dist <= SMALL_DIST { | |
179 | break; | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
184 | if y_best_dist >= ref_best_dist { | |
185 | return mb_type; | |
186 | } | |
187 | ||
188 | if y_best_dist > SMALL_DIST { | |
189 | res.reset(); | |
6f263099 | 190 | let dist4 = try_i4x4_pred(sblk.luma_blocks(), &mut i4_modes, res, &mut newblk.luma, imctx, y_best_dist); |
c5d5793c KS |
191 | use_i4 = dist4 < y_best_dist; |
192 | y_best_dist = y_best_dist.min(dist4); | |
193 | } | |
194 | } else if ref_best_dist != MAX_DIST { // we can skip that for intra-only case | |
195 | y_best_dist = try_intra16_pred(sblk, newblk, res, imctx, PredMode::DCPred); | |
196 | if y_best_dist >= ref_best_dist { | |
197 | return mb_type; | |
198 | } | |
199 | } | |
200 | ||
201 | let mut best_cmode = PredMode::DCPred; | |
202 | let mut c_best_dist = MAX_DIST; | |
203 | for &cmode in PRED16X16.iter() { | |
204 | newblk.fill_ipred_chroma(cmode, &imctx.ipred_u, &imctx.ipred_v); | |
205 | let mut dist = 0; | |
206 | 'csearch: for chroma in 0..2 { | |
207 | let mut nz_top = imctx.pctx.nz_c_top[chroma]; | |
208 | let mut nz_left = imctx.pctx.nz_c_left[chroma]; | |
209 | for (idx, (sblk, nblk)) in sblk.chroma_blocks(chroma).zip(newblk.chroma_blocks(chroma)).enumerate() { | |
210 | let pctx = (nz_top[idx & 1] as u8) + (nz_left[idx >> 1] as u8); | |
211 | let (dist1, has_nz) = imctx.metric.block_dist(&sblk, &nblk, imctx.q, 2, pctx, &imctx.models.coef_probs[2]); | |
212 | dist += dist1; | |
213 | nz_top[idx & 1] = has_nz; | |
214 | nz_left[idx >> 1] = has_nz; | |
215 | if dist >= c_best_dist { | |
216 | break 'csearch; | |
217 | } | |
218 | } | |
219 | } | |
220 | if dist < c_best_dist { | |
221 | best_cmode = cmode; | |
222 | c_best_dist = dist; | |
223 | } | |
224 | } | |
225 | let tot_dist = y_best_dist.saturating_add(c_best_dist); | |
226 | if (ref_best_dist == MAX_DIST) || (tot_dist < ref_best_dist) { | |
227 | if !use_i4 { | |
228 | MBType::Intra(best_ymode, best_cmode) | |
229 | } else { | |
230 | MBType::Intra4x4(i4_modes, [0; 16], best_cmode) | |
231 | } | |
232 | } else { | |
233 | mb_type | |
234 | } | |
235 | } | |
236 | ||
237 | pub fn calc_inter_mb_dist(sblk: &SrcBlock, newblk: &SrcBlock, res: &mut Residue, imctx: &IntraModePredCtx, pdc: i16) -> u32 { | |
238 | res.set_luma_from_diff(&sblk.luma, &newblk.luma); | |
239 | res.set_chroma_from_diff(&sblk.chroma, &newblk.chroma); | |
240 | res.fdct(); | |
241 | res.fdct_dc_block(); | |
242 | requant_y2_dc(&mut res.dcs[0], imctx.q); | |
243 | res.dcs[0] -= pdc; | |
244 | res.quant(imctx.q); | |
245 | let mut nits = estimate_subblock_nits(&res.dcs, 1, imctx.pctx.nz_y2, &imctx.models.coef_probs[1]); | |
246 | let mut nz_top = imctx.pctx.nz_y_top; | |
247 | let mut nz_left = imctx.pctx.nz_y_left; | |
248 | for (y, row) in res.luma.chunks(4).enumerate() { | |
249 | for (x, blk) in row.iter().enumerate() { | |
250 | let has_nz = blk.has_nz(); | |
251 | let pctx = (nz_top[x] as u8) + (nz_left[y] as u8); | |
252 | nits += estimate_subblock_nits(blk, 0, pctx, &imctx.models.coef_probs[0]); | |
253 | nz_top[x] = has_nz; | |
254 | nz_left[y] = has_nz; | |
255 | } | |
256 | } | |
257 | for (c_idx, chroma) in res.chroma.iter().enumerate() { | |
258 | let mut nz_top = imctx.pctx.nz_c_top[c_idx]; | |
259 | let mut nz_left = imctx.pctx.nz_c_left[c_idx]; | |
260 | for (idx, blk) in chroma.iter().enumerate() { | |
261 | let pctx = (nz_top[idx & 1] as u8) + (nz_left[idx >> 1] as u8); | |
262 | let has_nz = blk.has_nz(); | |
263 | nits += estimate_subblock_nits(blk, 2, pctx, &imctx.models.coef_probs[2]); | |
264 | nz_top[idx & 1] = has_nz; | |
265 | nz_left[idx >> 1] = has_nz; | |
266 | } | |
267 | } | |
268 | res.dequant(); | |
269 | res.idct(); | |
270 | let mut dist = 0; | |
271 | for (diff, (src, new)) in res.luma.iter().zip(sblk.luma_blocks().zip(newblk.luma_blocks())) { | |
272 | dist += get_difference_dist(&src, &new, diff); | |
273 | } | |
274 | for chroma in 0..2 { | |
275 | for (diff, (src, new)) in res.chroma[chroma].iter().zip(sblk.chroma_blocks(chroma).zip(newblk.chroma_blocks(chroma))) { | |
276 | dist += get_difference_dist(&src, &new, diff); | |
277 | } | |
278 | } | |
279 | ||
280 | res.reset(); | |
281 | imctx.metric.calc_metric(dist, nits) | |
282 | } | |
283 | ||
284 | #[allow(clippy::too_many_arguments)] | |
285 | pub fn try_inter_split(sblk: &SrcBlock, newblk: &mut SrcBlock, res: &mut Residue, mvprobs: [u8; 4], nearest_mv: MV, near_mv: MV, pred_mv: MV, last: bool, mb_x: usize, mb_y: usize, mv_search: &mut Box<dyn MVSearch + Send>, mv_est: &mut MVEstimator, pctx: &mut PredContext, imctx: &IntraModePredCtx, inter_dist: u32) -> Option<(MBType, u32)> { | |
286 | let mv_stride = pctx.mv_stride; | |
287 | let mut blk8 = [0; 64]; | |
288 | let mut mvs8 = [ZERO_MV; 4]; | |
289 | let mut split_cand = [false; 4]; | |
290 | let mut mv_dist = [0; 4]; | |
291 | ||
292 | let mb_mv = pctx.mvs[mb_x * 4 + mb_y * 4 * mv_stride]; | |
293 | for (quarter, dst_mv) in mvs8.iter_mut().enumerate() { | |
294 | let xoff = mb_x * 16 + (quarter & 1) * 8; | |
295 | let yoff = mb_y * 16 + (quarter & 2) * 4; | |
296 | ||
297 | let off = (quarter & 1) * 8 + (quarter >> 1) * 8 * 16; | |
298 | for (src, dst) in sblk.luma[off..].chunks(16).zip(blk8.chunks_mut(8)) { | |
299 | dst.copy_from_slice(&src[..8]); | |
300 | } | |
301 | ||
302 | let mut mvs = UniqueList::new(); | |
303 | mvs.add(ZERO_MV); | |
304 | mvs.add(mb_mv); | |
305 | let mv_idx = xoff / 4 + (yoff / 4) * mv_stride; | |
306 | if xoff > 0 { | |
307 | mvs.add(pctx.mvs[mv_idx - 1]); | |
308 | } | |
309 | if mv_idx >= mv_stride { | |
310 | mvs.add(pctx.mvs[mv_idx - mv_stride]); | |
311 | } | |
312 | mvs.add(near_mv); | |
313 | mvs.add(nearest_mv); | |
314 | let (mv, dist) = mv_search.search_blk8(mv_est, &blk8, xoff, yoff, mvs.get_list()); | |
315 | *dst_mv = mv; | |
316 | split_cand[quarter] = dist > LARGE_BLK8_DIST; | |
317 | mv_dist[quarter] = dist; | |
318 | } | |
319 | if mvs8[0] == mvs8[1] && mvs8[0] == mvs8[2] && mvs8[0] == mvs8[3] { | |
320 | // single MV per MB | |
321 | return None; | |
322 | } | |
323 | let mv_idx = mb_x * 4 + mb_y * 4 * mv_stride; | |
324 | for (dst, src) in pctx.mvs[mv_idx..].chunks_mut(2 * mv_stride).zip(mvs8.chunks(2)) { | |
325 | dst[0] = src[0]; | |
326 | dst[1] = src[0]; | |
327 | dst[2] = src[1]; | |
328 | dst[3] = src[1]; | |
329 | dst[mv_stride ] = src[0]; | |
330 | dst[mv_stride + 1] = src[0]; | |
331 | dst[mv_stride + 2] = src[1]; | |
332 | dst[mv_stride + 3] = src[1]; | |
333 | } | |
334 | recon_split_mb(newblk, mb_x, mb_y, &pctx.mvs, mv_stride, mv_est); | |
335 | ||
336 | let mut tot_dist = calc_inter_mb_dist(sblk, newblk, res, imctx, pctx.get_y2_dc_pred(last)); | |
337 | ||
338 | let mut split_mode = MVSplitMode::Quarters; | |
339 | let mut sub_refs = [SubMVRef::Zero; 16]; | |
340 | let mut sub_mvs = [ZERO_MV; 16]; | |
341 | ||
342 | let mut mv_nits = 0; | |
343 | if mvs8[0] == mvs8[1] && mvs8[2] == mvs8[3] { | |
344 | split_mode = MVSplitMode::TopBottom; | |
345 | sub_mvs[0] = mvs8[0] - pred_mv; | |
346 | sub_mvs[1] = mvs8[2] - pred_mv; | |
347 | ||
348 | let mv_idx = mb_x * 4 + mb_y * 4 * mv_stride; | |
349 | let left_mv = if mb_x > 0 { pctx.mvs[mv_idx - 1] } else { ZERO_MV }; | |
350 | let top_mv = if mb_y > 0 { pctx.mvs[mv_idx - mv_stride] } else { ZERO_MV }; | |
351 | let (ref0, nits0) = sub_mv_nits(mvs8[0], left_mv, top_mv, pred_mv, imctx.models); | |
352 | let left_mv = if mb_x > 0 { pctx.mvs[mv_idx + 2 * mv_stride - 1] } else { ZERO_MV }; | |
353 | let (ref1, nits1) = sub_mv_nits(mvs8[2], left_mv, mvs8[0], pred_mv, imctx.models); | |
354 | sub_refs[0] = ref0; | |
355 | sub_refs[1] = ref1; | |
356 | mv_nits += nits0 + nits1; | |
357 | } else if mvs8[0] == mvs8[2] && mvs8[1] == mvs8[3] { | |
358 | split_mode = MVSplitMode::LeftRight; | |
359 | sub_mvs[0] = mvs8[0] - pred_mv; | |
360 | sub_mvs[1] = mvs8[1] - pred_mv; | |
361 | ||
362 | let mv_idx = mb_x * 4 + mb_y * 4 * mv_stride; | |
363 | let left_mv = if mb_x > 0 { pctx.mvs[mv_idx - 1] } else { ZERO_MV }; | |
364 | let top_mv = if mb_y > 0 { pctx.mvs[mv_idx - mv_stride] } else { ZERO_MV }; | |
365 | let (ref0, nits0) = sub_mv_nits(mvs8[0], left_mv, top_mv, pred_mv, imctx.models); | |
366 | let top_mv = if mb_y > 0 { pctx.mvs[mv_idx - mv_stride + 2] } else { ZERO_MV }; | |
367 | let (ref1, nits1) = sub_mv_nits(mvs8[1], mvs8[0], top_mv, pred_mv, imctx.models); | |
368 | sub_refs[0] = ref0; | |
369 | sub_refs[1] = ref1; | |
370 | mv_nits += nits0 + nits1; | |
371 | } else { | |
372 | for (quarter, &mv) in mvs8.iter().enumerate() { | |
373 | let xoff = mb_x * 16 + (quarter & 1) * 8; | |
374 | let yoff = mb_y * 16 + (quarter & 2) * 4; | |
375 | let mv_idx = xoff / 4 + (yoff / 4) * mv_stride; | |
376 | let left_mv = if xoff > 0 { pctx.mvs[mv_idx - 1] } else { ZERO_MV }; | |
377 | let top_mv = if yoff > 0 { pctx.mvs[mv_idx - mv_stride] } else { ZERO_MV }; | |
378 | let (cur_sub_ref, nits) = sub_mv_nits(mv, left_mv, top_mv, pred_mv, imctx.models); | |
379 | sub_refs[quarter] = cur_sub_ref; | |
380 | sub_mvs[quarter] = mv - pred_mv; | |
381 | mv_nits += nits; | |
382 | ||
383 | pctx.mvs[mv_idx] = mv; | |
384 | pctx.mvs[mv_idx + 1] = mv; | |
385 | pctx.mvs[mv_idx + mv_stride] = mv; | |
386 | pctx.mvs[mv_idx + mv_stride + 1] = mv; | |
387 | } | |
388 | } | |
389 | mv_nits += sub_mv_mode_nits(split_mode); | |
390 | tot_dist += imctx.metric.calc_metric(0, mv_nits); | |
391 | if tot_dist < inter_dist { | |
392 | if tot_dist > SMALL_DIST && (split_cand[0] || split_cand[1] || split_cand[2] || split_cand[3]) { | |
393 | let mut blk4 = [0; 16]; | |
394 | let mut has_splits = false; | |
395 | for (quarter, &mv_dist) in mv_dist.iter().enumerate() { | |
396 | if !split_cand[quarter] { | |
397 | continue; | |
398 | } | |
399 | let xoff = mb_x * 16 + (quarter & 1) * 8; | |
400 | let yoff = mb_y * 16 + (quarter & 2) * 4; | |
401 | let mut dist_sum = 0; | |
402 | let mut smv = [ZERO_MV; 4]; | |
403 | for (subq, smv) in smv.iter_mut().enumerate() { | |
404 | let off = (quarter & 1) * 8 + (subq & 1) * 4 + ((quarter >> 1) * 8 + (subq >> 1) * 4) * 16; | |
405 | for (dst, src) in blk4.chunks_mut(4).zip(sblk.luma[off..].chunks(16)) { | |
406 | dst.copy_from_slice(&src[..4]); | |
407 | } | |
408 | ||
409 | let mut mvs = UniqueList::new(); | |
410 | mvs.add(ZERO_MV); | |
411 | mvs.add(mvs8[quarter]); | |
412 | mvs.add(mb_mv); | |
413 | let mv_idx = xoff / 4 + (subq & 1) + ((yoff / 4) + (subq >> 1)) * mv_stride; | |
414 | if xoff > 0 || (subq & 1) != 0 { | |
415 | mvs.add(pctx.mvs[mv_idx - 1]); | |
416 | } | |
417 | if mv_idx >= mv_stride { | |
418 | mvs.add(pctx.mvs[mv_idx - mv_stride]); | |
419 | } | |
420 | let (mv, dist) = mv_search.search_blk4(mv_est, &blk4, xoff, yoff, mvs.get_list()); | |
421 | *smv = mv; | |
422 | dist_sum += dist; | |
423 | } | |
424 | if dist_sum < mv_dist / 2 { | |
425 | for (subq, &smv) in smv.iter().enumerate() { | |
426 | let mv_idx = xoff / 4 + (subq & 1) + ((yoff / 4) + (subq >> 1)) * mv_stride; | |
427 | pctx.mvs[mv_idx] = smv; | |
428 | } | |
429 | has_splits = true; | |
430 | } | |
431 | } | |
432 | if has_splits { | |
433 | recon_split_mb(newblk, mb_x, mb_y, &pctx.mvs, mv_stride, mv_est); | |
434 | let mut split16_dist = calc_inter_mb_dist(sblk, newblk, res, imctx, pctx.get_y2_dc_pred(last)); | |
435 | if split16_dist < tot_dist { | |
436 | let mut mv_nits = sub_mv_mode_nits(MVSplitMode::Sixteenths); | |
437 | let mut mv_idx = mb_x * 4 + mb_y * 4 * mv_stride; | |
438 | let mut sub_refs2 = [SubMVRef::Zero; 16]; | |
439 | let mut sub_mvs2 = [ZERO_MV; 16]; | |
440 | for y in 0..4 { | |
441 | for x in 0..4 { | |
442 | let left_mv = if x > 0 || mb_x > 0 { pctx.mvs[mv_idx + x - 1] } else { ZERO_MV }; | |
443 | let top_mv = if mv_idx + x >= mv_stride { pctx.mvs[mv_idx + x - mv_stride] } else { ZERO_MV }; | |
444 | let cur_mv = pctx.mvs[mv_idx + x]; | |
445 | sub_mvs2[x + y * 4] = cur_mv - pred_mv; | |
446 | let (cur_sub_ref, nits) = sub_mv_nits(cur_mv, left_mv, top_mv, pred_mv, imctx.models); | |
447 | sub_refs2[x + y * 4] = cur_sub_ref; | |
448 | mv_nits += nits; | |
449 | } | |
450 | mv_idx += mv_stride; | |
451 | } | |
452 | split16_dist += imctx.metric.calc_metric(0, mv_nits); | |
453 | if split16_dist < tot_dist { | |
454 | let mb_t = MBType::InterSplitMV(last, mvprobs, MVSplitMode::Sixteenths, sub_refs2, sub_mvs2); | |
455 | return Some((mb_t, split16_dist)); | |
456 | } | |
457 | } | |
458 | } | |
459 | } | |
460 | let mv_idx = mb_x * 4 + mb_y * 4 * mv_stride; | |
461 | for (dst, src) in pctx.mvs[mv_idx..].chunks_mut(2 * mv_stride).zip(mvs8.chunks(2)) { | |
462 | dst[0] = src[0]; | |
463 | dst[1] = src[0]; | |
464 | dst[2] = src[1]; | |
465 | dst[3] = src[1]; | |
466 | dst[mv_stride ] = src[0]; | |
467 | dst[mv_stride + 1] = src[0]; | |
468 | dst[mv_stride + 2] = src[1]; | |
469 | dst[mv_stride + 3] = src[1]; | |
470 | } | |
471 | Some((MBType::InterSplitMV(last, mvprobs, split_mode, sub_refs, sub_mvs), tot_dist)) | |
472 | } else { | |
473 | None | |
474 | } | |
475 | } | |
476 | ||
477 | fn get_chroma_mv(mut mv: MV) -> MV { | |
478 | if mv.x < 0 { | |
479 | mv.x += 1; | |
480 | } else { | |
481 | mv.x += 2; | |
482 | } | |
483 | if mv.y < 0 { | |
484 | mv.y += 1; | |
485 | } else { | |
486 | mv.y += 2; | |
487 | } | |
488 | mv.x >>= 2; | |
489 | mv.y >>= 2; | |
490 | mv | |
491 | } | |
492 | ||
493 | pub fn recon_split_mb(newblk: &mut SrcBlock, mb_x: usize, mb_y: usize, mvs: &[MV], mv_stride: usize, mv_est: &mut MVEstimator) { | |
494 | let mut mv_idx = mb_x * 4 + mb_y * 4 * mv_stride; | |
495 | let mut sum_mv = [ZERO_MV; 2]; | |
496 | let mut blk4 = [0; 16]; | |
497 | for (y, strip) in newblk.luma.chunks_mut(16 * 4).enumerate() { | |
498 | if (y & 1) == 0 { | |
499 | sum_mv = [ZERO_MV; 2]; | |
500 | } | |
501 | for x in 0..4 { | |
502 | let mv = mvs[mv_idx + x]; | |
503 | sum_mv[x / 2] += mv; | |
504 | mv_est.get_blk4(&mut blk4, 0, mb_x * 16 + x * 4, mb_y * 16 + y * 4, mv); | |
505 | for (dst, src) in strip[x * 4..].chunks_mut(16).zip(blk4.chunks(4)) { | |
506 | dst[..4].copy_from_slice(src); | |
507 | } | |
508 | } | |
509 | if (y & 1) == 1 { | |
510 | let cmv = [get_chroma_mv(sum_mv[0]), get_chroma_mv(sum_mv[1])]; | |
511 | for chroma in 0..2 { | |
512 | for (x, &mv) in cmv.iter().enumerate() { | |
513 | mv_est.get_blk4(&mut blk4, chroma + 1, mb_x * 8 + x * 4, mb_y * 8 + (y & 2) * 2, mv); | |
514 | for (dst, src) in newblk.chroma[chroma][x * 4 + (y & 2) * 2 * 8..].chunks_mut(8).zip(blk4.chunks(4)) { | |
515 | dst[..4].copy_from_slice(src); | |
516 | } | |
517 | } | |
518 | } | |
519 | } | |
520 | mv_idx += mv_stride; | |
521 | } | |
522 | } |