RealVideo 4 encoder
[nihav.git] / nihav-realmedia / src / codecs / rv40enc / types.rs
CommitLineData
4965a5e5
KS
1use nihav_codec_support::codecs::{MV, ZERO_MV};
2
3pub trait RV34MVOps {
4 fn scale(&self, trd: u32, trb: u32) -> (MV, MV);
5 fn diff_gt_3(self, other: Self) -> bool;
6}
7
8impl 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)]
28pub 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)]
47pub enum PredType8x8 {
48 DC,
49 Hor,
50 Ver,
51 Plane,
52 LeftDC,
53 TopDC,
54 DC128
55}
56
57pub trait ToIndex {
58 fn to_index(self) -> i8;
59}
60
61impl 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
72impl 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)]
89pub struct Block {
90 pub coeffs: [i16; 16],
91}
92
93impl 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}
107impl 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)]
118pub 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)]
127pub 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
143impl 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)]
185pub 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
194impl SliceState {
195 pub fn new() -> Self { Self::default() }
196}
197
198#[derive(Default)]
199pub 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
210impl 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)]
551pub 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
567impl Default for MacroblockType {
568 fn default() -> Self { Self::Intra16x16(PredType8x8::DC) }
569}
570
571impl 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
583pub struct Macroblock {
584 pub mb_type: MacroblockType,
585 pub coeffs: [Block; 25],
586}