]>
Commit | Line | Data |
---|---|---|
1 | use nihav_codec_support::codecs::{MV, ZERO_MV}; | |
2 | ||
3 | pub trait RV34MVOps { | |
4 | fn scale(&self, trd: u32, trb: u32) -> (MV, MV); | |
5 | fn diff_gt_3(self, other: Self) -> bool; | |
6 | } | |
7 | ||
8 | impl RV34MVOps for MV { | |
9 | fn scale(&self, trd: u32, trb: u32) -> (MV, MV) { | |
10 | const TR_SHIFT: u8 = 14; | |
11 | const TR_BIAS: i32 = 1 << (TR_SHIFT - 1); | |
12 | ||
13 | let ratio = ((trb as i32) << TR_SHIFT) / (trd as i32); | |
14 | let mv_f = MV { | |
15 | x: (((self.x as i32) * ratio + TR_BIAS) >> TR_SHIFT) as i16, | |
16 | y: (((self.y as i32) * ratio + TR_BIAS) >> TR_SHIFT) as i16 | |
17 | }; | |
18 | let mv_b = mv_f - *self; | |
19 | (mv_f, mv_b) | |
20 | } | |
21 | fn diff_gt_3(self, other: Self) -> bool { | |
22 | let diff = self - other; | |
23 | diff.x.abs() > 3 || diff.y.abs() > 3 | |
24 | } | |
25 | } | |
26 | ||
27 | #[derive(Debug,Clone,Copy)] | |
28 | pub enum PredType4x4 { | |
29 | Ver, | |
30 | Hor, | |
31 | DC, | |
32 | DiagDownLeft, | |
33 | DiagDownRight, | |
34 | VerRight, | |
35 | HorDown, | |
36 | VerLeft, | |
37 | HorUp, | |
38 | LeftDC, | |
39 | TopDC, | |
40 | DC128, | |
41 | DiagDownLeftNoDown, | |
42 | HorUpNoDown, | |
43 | VerLeftNoDown | |
44 | } | |
45 | ||
46 | #[derive(Debug,Clone,Copy)] | |
47 | pub enum PredType8x8 { | |
48 | DC, | |
49 | Hor, | |
50 | Ver, | |
51 | Plane, | |
52 | LeftDC, | |
53 | TopDC, | |
54 | DC128 | |
55 | } | |
56 | ||
57 | pub trait ToIndex { | |
58 | fn to_index(self) -> i8; | |
59 | } | |
60 | ||
61 | impl ToIndex for PredType8x8 { | |
62 | fn to_index(self) -> i8 { | |
63 | match self { | |
64 | PredType8x8::Ver => 1, | |
65 | PredType8x8::Hor => 2, | |
66 | PredType8x8::Plane => 3, | |
67 | _ => 0, | |
68 | } | |
69 | } | |
70 | } | |
71 | ||
72 | impl ToIndex for PredType4x4 { | |
73 | fn to_index(self) -> i8 { | |
74 | match self { | |
75 | PredType4x4::Ver => 1, | |
76 | PredType4x4::Hor => 2, | |
77 | PredType4x4::DiagDownRight => 3, | |
78 | PredType4x4::DiagDownLeft | PredType4x4::DiagDownLeftNoDown => 4, | |
79 | PredType4x4::VerRight => 5, | |
80 | PredType4x4::VerLeft | PredType4x4::VerLeftNoDown => 6, | |
81 | PredType4x4::HorUp |PredType4x4::HorUpNoDown => 7, | |
82 | PredType4x4::HorDown => 8, | |
83 | _ => 0, // DC predictions | |
84 | } | |
85 | } | |
86 | } | |
87 | ||
88 | #[derive(Clone,Copy,Default)] | |
89 | pub struct Block { | |
90 | pub coeffs: [i16; 16], | |
91 | } | |
92 | ||
93 | impl Block { | |
94 | pub fn new() -> Self { Self::default() } | |
95 | pub fn is_empty(&self) -> bool { | |
96 | for &el in self.coeffs.iter() { | |
97 | if el != 0 { | |
98 | return false; | |
99 | } | |
100 | } | |
101 | true | |
102 | } | |
103 | pub fn count_nz(&self) -> usize { | |
104 | self.coeffs.iter().filter(|&&x| x != 0).count() | |
105 | } | |
106 | } | |
107 | impl std::fmt::Display for Block { | |
108 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
109 | let mut out = String::new(); | |
110 | for row in self.coeffs.chunks(4) { | |
111 | out += format!(" {:3} {:3} {:3} {:3}\n", row[0], row[1], row[2], row[3]).as_str(); | |
112 | } | |
113 | write!(f, "{}", out) | |
114 | } | |
115 | } | |
116 | ||
117 | #[derive(Clone,Copy,Default)] | |
118 | pub struct DeblockInfo { | |
119 | pub is_strong: bool, | |
120 | pub q: u8, | |
121 | pub cbp_y: u16, | |
122 | pub cbp_c: u8, | |
123 | pub deblock_y: u16, | |
124 | } | |
125 | ||
126 | #[derive(Debug,Clone,Copy,PartialEq)] | |
127 | pub enum MBType { | |
128 | Intra, | |
129 | Intra16, | |
130 | Skip, | |
131 | P16x16, | |
132 | P16x16Mix, | |
133 | P16x8, | |
134 | P8x16, | |
135 | P8x8, | |
136 | Direct, | |
137 | Bidir, | |
138 | Forward, | |
139 | Backward, | |
140 | Invalid, | |
141 | } | |
142 | ||
143 | impl MBType { | |
144 | pub fn is_intra(self) -> bool { matches!(self, MBType::Intra | MBType::Intra16) } | |
145 | fn get_weight(self) -> u8 { | |
146 | match self { | |
147 | MBType::Intra => 0, | |
148 | MBType::Intra16 => 1, | |
149 | MBType::Skip => unreachable!(), | |
150 | MBType::P16x16 => 2, | |
151 | MBType::P16x16Mix => 10, | |
152 | MBType::P16x8 => 7, | |
153 | MBType::P8x16 => 8, | |
154 | MBType::P8x8 => 3, | |
155 | MBType::Direct => 6, | |
156 | MBType::Bidir => 9, | |
157 | MBType::Forward => 4, | |
158 | MBType::Backward => 5, | |
159 | MBType::Invalid => unreachable!(), | |
160 | } | |
161 | } | |
162 | pub fn to_code(self) -> usize { | |
163 | match self { | |
164 | MBType::Intra => 0, | |
165 | MBType::Intra16 => 1, | |
166 | MBType::P16x16 | MBType::Forward => 2, | |
167 | MBType::P8x8 | MBType::Backward => 3, | |
168 | MBType::P16x8 | MBType::Bidir => 4, | |
169 | MBType::P8x16 | MBType::Direct => 5, | |
170 | MBType::P16x16Mix => 6, | |
171 | _ => unreachable!(), | |
172 | } | |
173 | } | |
174 | pub fn has_dir_mv(self, fwd: bool) -> bool { | |
175 | match self { | |
176 | MBType::Bidir => true, | |
177 | MBType::Forward if fwd => true, | |
178 | MBType::Backward if !fwd => true, | |
179 | _ => false, | |
180 | } | |
181 | } | |
182 | } | |
183 | ||
184 | #[derive(Default)] | |
185 | pub struct SliceState { | |
186 | pub has_t: bool, | |
187 | pub has_l: bool, | |
188 | pub has_tl: bool, | |
189 | pub has_tr: bool, | |
190 | pub mb_x: usize, | |
191 | pub mb_y: usize, | |
192 | } | |
193 | ||
194 | impl SliceState { | |
195 | pub fn new() -> Self { Self::default() } | |
196 | } | |
197 | ||
198 | #[derive(Default)] | |
199 | pub struct MBState { | |
200 | pub mb_type: Vec<MBType>, | |
201 | pub ipred: Vec<i8>, | |
202 | pub fwd_mv: Vec<MV>, | |
203 | pub bwd_mv: Vec<MV>, | |
204 | pub ref_mv: Vec<MV>, | |
205 | pub mb_stride: usize, | |
206 | pub blk8_stride: usize, | |
207 | pub blk4_stride: usize, | |
208 | } | |
209 | ||
210 | impl MBState { | |
211 | pub fn new() -> Self { Self::default() } | |
212 | pub fn resize(&mut self, mb_w: usize, mb_h: usize) { | |
213 | self.mb_stride = mb_w + 2; | |
214 | self.blk8_stride = mb_w * 2 + 2; | |
215 | self.blk4_stride = mb_w * 4 + 2; | |
216 | ||
217 | self.mb_type.resize(self.mb_stride * (mb_h + 1), MBType::Invalid); | |
218 | self.ipred.resize(self.blk4_stride * (mb_h * 4 + 1), -1); | |
219 | self.fwd_mv.resize(self.blk8_stride * (mb_w * 2 + 1), ZERO_MV); | |
220 | self.bwd_mv.resize(self.blk8_stride * (mb_w * 2 + 1), ZERO_MV); | |
221 | self.ref_mv.resize(self.blk8_stride * (mb_w * 2 + 1), ZERO_MV); | |
222 | } | |
223 | pub fn reset(&mut self) { | |
224 | for el in self.mb_type.iter_mut() { | |
225 | *el = MBType::Invalid; | |
226 | } | |
227 | for el in self.ipred.iter_mut() { | |
228 | *el = -1; | |
229 | } | |
230 | } | |
231 | fn set_mv(&mut self, blk8_idx: usize, fwd: bool, mv: MV) { | |
232 | if fwd { | |
233 | self.fwd_mv[blk8_idx] = mv; | |
234 | self.fwd_mv[blk8_idx + 1] = mv; | |
235 | self.fwd_mv[blk8_idx + self.blk8_stride] = mv; | |
236 | self.fwd_mv[blk8_idx + self.blk8_stride + 1] = mv; | |
237 | } else { | |
238 | self.bwd_mv[blk8_idx] = mv; | |
239 | self.bwd_mv[blk8_idx + 1] = mv; | |
240 | self.bwd_mv[blk8_idx + self.blk8_stride] = mv; | |
241 | self.bwd_mv[blk8_idx + self.blk8_stride + 1] = mv; | |
242 | } | |
243 | } | |
244 | pub fn get_mb_idx(&self, mb_x: usize, mb_y: usize) -> usize { | |
245 | mb_x + 1 + (mb_y + 1) * self.mb_stride | |
246 | } | |
247 | pub fn get_blk8_idx(&self, mb_x: usize, mb_y: usize) -> usize { | |
248 | mb_x * 2 + 1 + (mb_y * 2 + 1) * self.blk8_stride | |
249 | } | |
250 | pub fn get_blk4_idx(&self, mb_x: usize, mb_y: usize) -> usize { | |
251 | mb_x * 4 + 1 + (mb_y * 4 + 1) * self.blk4_stride | |
252 | } | |
253 | pub fn update(&mut self, mb_type: &MacroblockType, mb_x: usize, mb_y: usize) { | |
254 | let mb_idx = self.get_mb_idx(mb_x, mb_y); | |
255 | let blk8_idx = self.get_blk8_idx(mb_x, mb_y); | |
256 | let blk4_idx = self.get_blk4_idx(mb_x, mb_y); | |
257 | ||
258 | for row in self.ipred[blk4_idx..].chunks_mut(self.blk4_stride).take(4) { | |
259 | for el in row[..4].iter_mut() { | |
260 | *el = 0; | |
261 | } | |
262 | } | |
263 | ||
264 | match *mb_type { | |
265 | MacroblockType::Intra16x16(ptype) => { | |
266 | self.mb_type[mb_idx] = MBType::Intra16; | |
267 | let pred_id = ptype.to_index(); | |
268 | for row in self.ipred[blk4_idx..].chunks_mut(self.blk4_stride).take(4) { | |
269 | for el in row[..4].iter_mut() { | |
270 | *el = pred_id; | |
271 | } | |
272 | } | |
273 | self.set_mv(blk8_idx, true, ZERO_MV); | |
274 | self.set_mv(blk8_idx, false, ZERO_MV); | |
275 | }, | |
276 | MacroblockType::Intra4x4(ptypes) => { | |
277 | self.mb_type[mb_idx] = MBType::Intra; | |
278 | for (dst, src) in self.ipred[blk4_idx..].chunks_mut(self.blk4_stride).zip(ptypes.chunks(4)) { | |
279 | for (dst, &ptype) in dst.iter_mut().zip(src.iter()) { | |
280 | *dst = ptype.to_index(); | |
281 | } | |
282 | } | |
283 | self.set_mv(blk8_idx, true, ZERO_MV); | |
284 | self.set_mv(blk8_idx, false, ZERO_MV); | |
285 | }, | |
286 | MacroblockType::PSkip => { | |
287 | self.mb_type[mb_idx] = MBType::Skip; | |
288 | self.set_mv(blk8_idx, true, ZERO_MV); | |
289 | self.set_mv(blk8_idx, false, ZERO_MV); | |
290 | }, | |
291 | MacroblockType::Inter16x16(mv) => { | |
292 | self.mb_type[mb_idx] = MBType::P16x16; | |
293 | self.set_mv(blk8_idx, true, mv); | |
294 | self.set_mv(blk8_idx, false, ZERO_MV); | |
295 | }, | |
296 | MacroblockType::InterMix(mv) => { | |
297 | self.mb_type[mb_idx] = MBType::P16x16Mix; | |
298 | self.set_mv(blk8_idx, true, mv); | |
299 | self.set_mv(blk8_idx, false, ZERO_MV); | |
300 | }, | |
301 | MacroblockType::Inter16x8(mvs) => { | |
302 | self.mb_type[mb_idx] = MBType::P16x8; | |
303 | self.fwd_mv[blk8_idx] = mvs[0]; | |
304 | self.fwd_mv[blk8_idx + 1] = mvs[0]; | |
305 | self.fwd_mv[blk8_idx + self.blk8_stride] = mvs[1]; | |
306 | self.fwd_mv[blk8_idx + self.blk8_stride + 1] = mvs[1]; | |
307 | self.set_mv(blk8_idx, false, ZERO_MV); | |
308 | }, | |
309 | MacroblockType::Inter8x16(mvs) => { | |
310 | self.mb_type[mb_idx] = MBType::P8x16; | |
311 | self.fwd_mv[blk8_idx] = mvs[0]; | |
312 | self.fwd_mv[blk8_idx + 1] = mvs[1]; | |
313 | self.fwd_mv[blk8_idx + self.blk8_stride] = mvs[0]; | |
314 | self.fwd_mv[blk8_idx + self.blk8_stride + 1] = mvs[1]; | |
315 | self.set_mv(blk8_idx, false, ZERO_MV); | |
316 | }, | |
317 | MacroblockType::Inter8x8(mvs) => { | |
318 | self.mb_type[mb_idx] = MBType::P8x8; | |
319 | self.fwd_mv[blk8_idx] = mvs[0]; | |
320 | self.fwd_mv[blk8_idx + 1] = mvs[1]; | |
321 | self.fwd_mv[blk8_idx + self.blk8_stride] = mvs[2]; | |
322 | self.fwd_mv[blk8_idx + self.blk8_stride + 1] = mvs[3]; | |
323 | self.set_mv(blk8_idx, false, ZERO_MV); | |
324 | }, | |
325 | MacroblockType::BSkip(fmvs, bmvs) => { | |
326 | self.mb_type[mb_idx] = MBType::Skip; | |
327 | self.fwd_mv[blk8_idx] = fmvs[0]; | |
328 | self.fwd_mv[blk8_idx + 1] = fmvs[1]; | |
329 | self.fwd_mv[blk8_idx + self.blk8_stride] = fmvs[0]; | |
330 | self.fwd_mv[blk8_idx + self.blk8_stride + 1] = fmvs[1]; | |
331 | self.bwd_mv[blk8_idx] = bmvs[0]; | |
332 | self.bwd_mv[blk8_idx + 1] = bmvs[1]; | |
333 | self.bwd_mv[blk8_idx + self.blk8_stride] = bmvs[0]; | |
334 | self.bwd_mv[blk8_idx + self.blk8_stride + 1] = bmvs[1]; | |
335 | }, | |
336 | /*MacroblockType::Direct(fmv, bmv) => { | |
337 | self.mb_type[mb_idx] = MBType::Direct; | |
338 | self.set_mv(blk8_idx, true, fmv); | |
339 | self.set_mv(blk8_idx, false, bmv); | |
340 | },*/ | |
341 | MacroblockType::Bidir(fmv, bmv) => { | |
342 | self.mb_type[mb_idx] = MBType::Bidir; | |
343 | self.set_mv(blk8_idx, true, fmv); | |
344 | self.set_mv(blk8_idx, false, bmv); | |
345 | }, | |
346 | MacroblockType::Forward(mv) => { | |
347 | self.mb_type[mb_idx] = MBType::Forward; | |
348 | self.set_mv(blk8_idx, true, mv); | |
349 | self.set_mv(blk8_idx, false, ZERO_MV); | |
350 | }, | |
351 | MacroblockType::Backward(mv) => { | |
352 | self.mb_type[mb_idx] = MBType::Backward; | |
353 | self.set_mv(blk8_idx, true, ZERO_MV); | |
354 | self.set_mv(blk8_idx, false, mv); | |
355 | }, | |
356 | }; | |
357 | } | |
358 | pub fn get_pred_mbtype(&self, sstate: &SliceState, is_b: bool) -> MBType { | |
359 | let mut cand = [MBType::Invalid; 4]; | |
360 | let mut ccount = 0; | |
361 | ||
362 | let mb_idx = self.get_mb_idx(sstate.mb_x, sstate.mb_y); | |
363 | if sstate.has_t { | |
364 | cand[ccount] = self.mb_type[mb_idx - self.mb_stride]; | |
365 | ccount += 1; | |
366 | if sstate.has_tr { | |
367 | cand[ccount] = self.mb_type[mb_idx - self.mb_stride + 1]; | |
368 | ccount += 1; | |
369 | } | |
370 | } | |
371 | if sstate.has_l { | |
372 | cand[ccount] = self.mb_type[mb_idx - 1]; | |
373 | ccount += 1; | |
374 | } | |
375 | if sstate.has_tl { | |
376 | cand[ccount] = self.mb_type[mb_idx - self.mb_stride - 1]; | |
377 | ccount += 1; | |
378 | } | |
379 | if !is_b { | |
380 | for el in cand[..ccount].iter_mut() { | |
381 | if *el == MBType::Skip { | |
382 | *el = MBType::P16x16; | |
383 | } | |
384 | } | |
385 | } else { | |
386 | for el in cand[..ccount].iter_mut() { | |
387 | if *el == MBType::Skip { | |
388 | *el = MBType::Direct; | |
389 | } | |
390 | } | |
391 | } | |
392 | match ccount { | |
393 | 0 => MBType::Intra, | |
394 | 1 => cand[0], | |
395 | 2 => if cand[0].get_weight() <= cand[1].get_weight() { cand[0] } else { cand[1] }, | |
396 | _ => { | |
397 | const MBTYPE_FROM_WEIGHT: [MBType; 11] = [ | |
398 | MBType::Intra, MBType::Intra16, MBType::P16x16, MBType::P8x8, | |
399 | MBType::Forward, MBType::Backward, MBType::Direct, MBType::P16x8, | |
400 | MBType::P8x16, MBType::Bidir, MBType::P16x16Mix | |
401 | ]; | |
402 | ||
403 | let mut counts = [0; 12]; | |
404 | for el in cand[..ccount].iter() { | |
405 | counts[usize::from(el.get_weight())] += 1; | |
406 | } | |
407 | let mut best_idx = 0; | |
408 | let mut best_wgt = 0; | |
409 | for (idx, &weight) in counts.iter().enumerate() { | |
410 | if weight > best_wgt { | |
411 | best_idx = idx; | |
412 | best_wgt = weight; | |
413 | } | |
414 | } | |
415 | MBTYPE_FROM_WEIGHT[best_idx] | |
416 | }, | |
417 | } | |
418 | } | |
419 | pub fn get_ipred4x4_ctx(&self, mb_x: usize, mb_y: usize, x: usize, y: usize) -> (i8, i8, i8) { | |
420 | let blk4_idx = self.get_blk4_idx(mb_x, mb_y) + x + y * self.blk4_stride; | |
421 | (self.ipred[blk4_idx - 1], | |
422 | self.ipred[blk4_idx - self.blk4_stride], | |
423 | self.ipred[blk4_idx - self.blk4_stride + 1]) | |
424 | } | |
425 | pub fn set_ipred4x4(&mut self, mb_x: usize, mb_y: usize, modes: &[PredType4x4; 16]) { | |
426 | let blk4_idx = self.get_blk4_idx(mb_x, mb_y); | |
427 | for (dst, src) in self.ipred[blk4_idx..].chunks_mut(self.blk4_stride).zip(modes.chunks(4)) { | |
428 | for (dst, src) in dst.iter_mut().zip(src.iter()) { | |
429 | *dst = src.to_index(); | |
430 | } | |
431 | } | |
432 | } | |
433 | fn get_mv(&self, idx: usize, fwd: bool) -> MV { | |
434 | if fwd { | |
435 | self.fwd_mv[idx] | |
436 | } else { | |
437 | self.bwd_mv[idx] | |
438 | } | |
439 | } | |
440 | pub fn get_diff_mv(&self, sstate: &SliceState, w16: bool, xoff: usize, yoff: usize) -> MV { | |
441 | let blk8_idx = self.get_blk8_idx(sstate.mb_x, sstate.mb_y) + xoff + yoff * self.blk8_stride; | |
442 | ||
443 | let cur_mv = self.get_mv(blk8_idx, true); | |
444 | ||
445 | if (yoff == 0 && !sstate.has_t) && (xoff == 0 && !sstate.has_l) { | |
446 | return cur_mv; | |
447 | } | |
448 | ||
449 | let left_mv = if sstate.has_l || (xoff != 0) { self.get_mv(blk8_idx - 1, true) } else { ZERO_MV }; | |
450 | let top_mv = if sstate.has_t || (yoff != 0) { self.get_mv(blk8_idx - self.blk8_stride, true) } else { left_mv }; | |
451 | let has_tr = match xoff + yoff * 2 { | |
452 | 0 if w16 => sstate.has_tr, | |
453 | 0 => sstate.has_t, | |
454 | 1 => sstate.has_tr, | |
455 | 2 if w16 => false, | |
456 | 2 => true, | |
457 | _ => false, | |
458 | }; | |
459 | let has_tl = match xoff + yoff * 2 { | |
460 | 0 => sstate.has_tl, | |
461 | 1 => sstate.has_t, | |
462 | 2 => sstate.has_l, | |
463 | _ => true, | |
464 | }; | |
465 | let mv_c = if has_tr { | |
466 | self.get_mv(blk8_idx - self.blk8_stride + if w16 { 2 } else { 1 }, true) | |
467 | } else if has_tl { | |
468 | self.get_mv(blk8_idx - self.blk8_stride - 1, true) | |
469 | } else { | |
470 | return cur_mv - left_mv; | |
471 | }; | |
472 | ||
473 | cur_mv - MV::pred(left_mv, top_mv, mv_c) | |
474 | } | |
475 | pub fn get_diff_mv_b(&self, sstate: &SliceState, fwd: bool) -> MV { | |
476 | let mb_idx = self.get_mb_idx(sstate.mb_x, sstate.mb_y); | |
477 | let blk8_idx = self.get_blk8_idx(sstate.mb_x, sstate.mb_y); | |
478 | ||
479 | let mut pred_mv = [ZERO_MV; 3]; | |
480 | let mut pcount = 0; | |
481 | ||
482 | let cur_mv = self.get_mv(blk8_idx, fwd); | |
483 | ||
484 | if sstate.has_l && self.mb_type[mb_idx - 1].has_dir_mv(fwd) { | |
485 | pred_mv[pcount] = self.get_mv(blk8_idx - 1, fwd); | |
486 | pcount += 1; | |
487 | } | |
488 | if !sstate.has_t { | |
489 | return cur_mv - pred_mv[0]; | |
490 | } | |
491 | if self.mb_type[mb_idx - self.mb_stride].has_dir_mv(fwd) { | |
492 | pred_mv[pcount] = self.get_mv(blk8_idx - self.blk8_stride, fwd); | |
493 | pcount += 1; | |
494 | } | |
495 | if sstate.has_tr { | |
496 | if self.mb_type[mb_idx - self.mb_stride + 1].has_dir_mv(fwd) { | |
497 | pred_mv[pcount] = self.get_mv(blk8_idx - self.blk8_stride + 2, fwd); | |
498 | pcount += 1; | |
499 | } | |
500 | } else if sstate.has_tl && self.mb_type[mb_idx - self.mb_stride - 1].has_dir_mv(fwd) { | |
501 | pred_mv[pcount] = self.get_mv(blk8_idx - self.blk8_stride - 1, fwd); | |
502 | pcount += 1; | |
503 | } | |
504 | let pred_mv = match pcount { | |
505 | 3 => MV::pred(pred_mv[0], pred_mv[1], pred_mv[2]), | |
506 | 2 => MV{ x: (pred_mv[0].x + pred_mv[1].x) / 2, y: (pred_mv[0].y + pred_mv[1].y) / 2 }, | |
507 | 1 => pred_mv[0], | |
508 | _ => ZERO_MV, | |
509 | }; | |
510 | cur_mv - pred_mv | |
511 | } | |
512 | pub fn swap_mvs(&mut self) { | |
513 | std::mem::swap(&mut self.fwd_mv, &mut self.ref_mv); | |
514 | } | |
515 | pub fn fill_deblock(&self, dblk: &mut DeblockInfo, sstate: &SliceState) { | |
516 | if dblk.is_strong { | |
517 | dblk.deblock_y = 0xFFFF; | |
518 | return; | |
519 | } | |
520 | let mut hmvmask = 0; | |
521 | let mut vmvmask = 0; | |
522 | ||
523 | let mut blk8_idx = self.get_blk8_idx(sstate.mb_x, sstate.mb_y); | |
524 | for y in 0..2 { | |
525 | for x in 0..2 { | |
526 | let shift = x * 2 + y * 8; | |
527 | let cur_mv = self.get_mv(blk8_idx + x, true); | |
528 | if (x > 0) || (sstate.mb_x > 0) { | |
529 | let left_mv = self.get_mv(blk8_idx + x - 1, true); | |
530 | if cur_mv.diff_gt_3(left_mv) { | |
531 | vmvmask |= 0x11 << shift; | |
532 | } | |
533 | } | |
534 | if (y > 0) || (sstate.mb_y > 0) { | |
535 | let top_mv = self.get_mv(blk8_idx + x - self.blk8_stride, true); | |
536 | if cur_mv.diff_gt_3(top_mv) { | |
537 | hmvmask |= 0x03 << shift; | |
538 | } | |
539 | } | |
540 | } | |
541 | blk8_idx += self.blk8_stride; | |
542 | } | |
543 | if sstate.mb_y == 0 { hmvmask &= !0x000F; } | |
544 | if sstate.mb_x == 0 { vmvmask &= !0x1111; } | |
545 | ||
546 | dblk.deblock_y = dblk.cbp_y | hmvmask | vmvmask; | |
547 | } | |
548 | } | |
549 | ||
550 | #[derive(Clone)] | |
551 | pub enum MacroblockType { | |
552 | Intra16x16(PredType8x8), | |
553 | Intra4x4([PredType4x4; 16]), | |
554 | PSkip, | |
555 | Inter16x16(MV), | |
556 | InterMix(MV), | |
557 | Inter16x8([MV; 2]), | |
558 | Inter8x16([MV; 2]), | |
559 | Inter8x8([MV; 4]), | |
560 | BSkip([MV; 4], [MV; 4]), | |
561 | //Direct(MV, MV), | |
562 | Bidir(MV, MV), | |
563 | Forward(MV), | |
564 | Backward(MV), | |
565 | } | |
566 | ||
567 | impl Default for MacroblockType { | |
568 | fn default() -> Self { Self::Intra16x16(PredType8x8::DC) } | |
569 | } | |
570 | ||
571 | impl MacroblockType { | |
572 | pub fn is_intra(&self) -> bool { | |
573 | matches!(*self, MacroblockType::Intra16x16(_) | MacroblockType::Intra4x4(_)) | |
574 | } | |
575 | pub fn is_16(&self) -> bool { | |
576 | matches!(*self, MacroblockType::Intra16x16(_) | MacroblockType::InterMix(_)) | |
577 | } | |
578 | pub fn is_skip(&self) -> bool { | |
579 | matches!(*self, MacroblockType::PSkip | MacroblockType::BSkip(_, _)) | |
580 | } | |
581 | } | |
582 | ||
583 | pub struct Macroblock { | |
584 | pub mb_type: MacroblockType, | |
585 | pub coeffs: [Block; 25], | |
586 | } |