1 use nihav_core::formats::YUV420_FORMAT;
2 use nihav_core::frame::{NABufferType, NAVideoInfo, NAVideoBuffer, NAVideoBufferRef, FrameType, alloc_video_buffer};
3 use nihav_core::codecs::{NADecoderSupport, DecoderError, DecoderResult};
4 use nihav_codec_support::codecs::{MV, ZERO_MV, IPBShuffler};
5 use nihav_core::io::bitreader::{BitReader,BitReaderMode};
6 use nihav_core::io::intcode::*;
7 use nihav_codec_support::data::GenericCache;
10 use super::rv34codes::*;
11 use super::rv34dsp::*;
14 fn scale(&self, trd: u16, trb: u16) -> (MV, MV);
17 const TR_SHIFT: u8 = 14;
18 const TR_BIAS: i32 = 1 << (TR_SHIFT - 1);
20 impl RV34MVScale for MV {
21 fn scale(&self, trd: u16, trb: u16) -> (MV, MV) {
22 let ratio = ((trb as i32) << TR_SHIFT) / (trd as i32);
24 x: (((self.x as i32) * ratio + TR_BIAS) >> TR_SHIFT) as i16,
25 y: (((self.y as i32) * ratio + TR_BIAS) >> TR_SHIFT) as i16
27 let mv_b = mv_f - *self;
33 pub struct RV34SliceHeader {
45 impl RV34SliceHeader {
46 pub fn fits(&self, cmp: &RV34SliceHeader) -> bool {
47 (self.ftype == cmp.ftype) &&
48 (self.pts == cmp.pts) &&
49 (self.width == cmp.width) &&
50 (self.height == cmp.height)
55 #[derive(Debug,Clone,Copy,PartialEq)]
73 pub fn is_intra(self) -> bool {
74 (self == MBType::MBIntra) || (self == MBType::MBIntra16)
76 pub fn is_16(self) -> bool {
77 (self == MBType::MBIntra16) || (self == MBType::MBP16x16Mix)
79 pub fn is_intra_or_16(self) -> bool {
80 self.is_intra() || self.is_16()
82 pub fn get_num_mvs(self) -> usize {
84 MBType::MBIntra | MBType::MBIntra16 |
85 MBType::MBSkip | MBType::MBDirect => 0,
86 MBType::MBP16x16 | MBType::MBP16x16Mix |
87 MBType::MBForward | MBType::MBBackward => 1,
88 MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBBidir => 2,
90 MBType::Invalid => unreachable!(),
93 pub fn is_fwd(self) -> bool {
95 MBType::MBP16x16 | MBType::MBP16x16Mix |
96 MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 |
97 MBType::MBForward => true,
101 pub fn is_bwd(self) -> bool {
103 MBType::MBBidir | MBType::MBBackward => true,
107 pub fn has_mv_dir(self, fwd: bool) -> bool {
109 MBType::MBBidir => true,
110 MBType::MBForward if fwd => true,
111 MBType::MBBackward if !fwd => true,
115 pub fn is_nomv(self) -> bool {
117 MBType::MBIntra | MBType::MBIntra16 | MBType::MBSkip | MBType::MBDirect => true,
121 /*pub fn is_16x16(self) -> bool {
123 MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 => false,
127 fn get_weight(self) -> usize {
129 MBType::MBIntra => 0,
130 MBType::MBIntra16 => 1,
131 MBType::MBSkip => unreachable!(),
132 MBType::MBP16x16 => 2,
133 MBType::MBP16x16Mix => 10,
134 MBType::MBP16x8 => 7,
135 MBType::MBP8x16 => 8,
137 MBType::MBDirect => 6,
138 MBType::MBBidir => 9,
139 MBType::MBForward => 4,
140 MBType::MBBackward => 5,
141 MBType::Invalid => unreachable!(),
146 const MBTYPE_FROM_WEIGHT: [MBType; 11] = [
147 MBType::MBIntra, MBType::MBIntra16, MBType::MBP16x16, MBType::MBP8x8,
148 MBType::MBForward, MBType::MBBackward, MBType::MBDirect, MBType::MBP16x8,
149 MBType::MBP8x16, MBType::MBBidir, MBType::MBP16x16Mix,
152 #[derive(Clone,Copy)]
159 #[derive(Clone,Copy)]
160 pub struct RV34MBInfo {
164 pub cbp_c: u8, // for deblocking purposes
168 struct IntraModeState {
169 cache: GenericCache<i8>,
172 const RV34_INTRA_PRED4: [PredType4x4; 9] = [
173 PredType4x4::DC, PredType4x4::Ver, PredType4x4::Hor,
174 PredType4x4::DiagDownRight, PredType4x4::DiagDownLeft,
175 PredType4x4::VerRight, PredType4x4::VerLeft,
176 PredType4x4::HorUp, PredType4x4::HorDown
179 const RV34_INTRA_PRED16: [PredType8x8; 4] = [
180 PredType8x8::DC, PredType8x8::Ver, PredType8x8::Hor, PredType8x8::Plane
183 impl IntraModeState {
184 fn new(mb_w: usize) -> Self {
185 let stride = 1 + mb_w * 4 + 1;
186 IntraModeState { cache: GenericCache::new(4, stride, -1) }
188 fn reset(&mut self) { self.cache.reset(); }
189 fn update(&mut self) { self.cache.update_row(); }
190 fn get_pos(&self, xpos: usize) -> usize {
191 self.cache.stride + 1 + xpos * 4
193 fn set_mb_x(&mut self, mb_x: usize) {
194 self.cache.xpos = self.get_pos(mb_x);
196 fn fill_block(&mut self, val: i8) {
197 let mut pos = self.cache.xpos;
200 self.cache.data[pos + j] = val;
202 pos += self.cache.stride;
205 fn get_pred16_type(&self, has_top: bool, has_left: bool) -> PredType8x8 {
206 if !has_top && !has_left { return PredType8x8::DC128; }
207 let mut im = RV34_INTRA_PRED16[self.cache.data[self.cache.xpos] as usize];
210 PredType8x8::Plane | PredType8x8::Ver => PredType8x8::Hor,
211 PredType8x8::DC => PredType8x8::LeftDC,
214 } else if !has_left {
216 PredType8x8::Plane | PredType8x8::Hor => PredType8x8::Ver,
217 PredType8x8::DC => PredType8x8::TopDC,
223 fn get_pred8_type(&self, has_top: bool, has_left: bool) -> PredType8x8 {
224 if !has_top && !has_left { return PredType8x8::DC128; }
225 let mut im = RV34_INTRA_PRED16[self.cache.data[self.cache.xpos] as usize];
226 im = match im { PredType8x8::Plane => PredType8x8::DC, _ => im };
229 PredType8x8::Plane | PredType8x8::Ver => PredType8x8::Hor,
230 PredType8x8::DC => PredType8x8::LeftDC,
233 } else if !has_left {
235 PredType8x8::Plane | PredType8x8::Hor => PredType8x8::Ver,
236 PredType8x8::DC => PredType8x8::TopDC,
242 fn get_pred4_type(&self, x: usize, y: usize, has_top: bool, has_left: bool) -> PredType4x4 {
243 let no_up = !has_top && (y == 0);
244 let no_left = !has_left && (x == 0);
245 if no_up && no_left { return PredType4x4::DC128; }
246 let no_down = !has_left || (x != 0) || (y == 3);
248 let mut im = RV34_INTRA_PRED4[self.cache.data[self.cache.xpos + x + y * self.cache.stride] as usize];
252 PredType4x4::Ver => PredType4x4::Hor,
253 PredType4x4::DC => PredType4x4::LeftDC,
258 PredType4x4::Hor => PredType4x4::Ver,
259 PredType4x4::DC => PredType4x4::TopDC,
260 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
266 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
267 PredType4x4::HorUp => PredType4x4::HorUpNoDown,
268 PredType4x4::VerLeft => PredType4x4::VerLeftNoDown,
275 fn get_pred4_type_chroma(&self, x: usize, y: usize, has_top: bool, has_left: bool) -> PredType4x4 {
276 let no_up = !has_top && (y == 0);
277 let no_left = !has_left && (x == 0);
278 if no_up && no_left { return PredType4x4::DC128; }
279 let no_down = !has_left || (x != 0) || (y == 1);
281 let mut im = RV34_INTRA_PRED4[self.cache.data[self.cache.xpos + x * 2 + y * 2 * self.cache.stride] as usize];
285 PredType4x4::Ver => PredType4x4::Hor,
286 PredType4x4::DC => PredType4x4::LeftDC,
291 PredType4x4::Hor => PredType4x4::Ver,
292 PredType4x4::DC => PredType4x4::TopDC,
293 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
299 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
300 PredType4x4::HorUp => PredType4x4::HorUpNoDown,
301 PredType4x4::VerLeft => PredType4x4::VerLeftNoDown,
314 pub has_b: Vec<bool>,
315 pub has_f: Vec<bool>,
320 Self { mv_b: Vec::new(), mv_f: Vec::new(), w: 0, h: 0, has_b: Vec::new(), has_f: Vec::new() }
322 fn resize(&mut self, mb_w: usize, mb_h: usize) {
327 fn reset(&mut self) {
328 let size = self.w * self.h;
329 self.mv_f.truncate(0);
330 self.mv_f.resize(size, ZERO_MV);
331 self.mv_b.truncate(0);
332 self.mv_b.resize(size, ZERO_MV);
333 self.has_f.truncate(0);
334 self.has_f.resize(size >> 2, false);
335 self.has_b.truncate(0);
336 self.has_b.resize(size >> 2, false);
338 fn fill(&mut self, mb_x: usize, mb_y: usize, fwd: bool, mv: MV) {
339 let idx = mb_x * 2 + mb_y * 2 * self.w;
341 self.mv_f[idx + 0] = mv;
342 self.mv_f[idx + 1] = mv;
343 self.mv_f[idx + self.w + 0] = mv;
344 self.mv_f[idx + self.w + 1] = mv;
346 self.mv_b[idx + 0] = mv;
347 self.mv_b[idx + 1] = mv;
348 self.mv_b[idx + self.w + 0] = mv;
349 self.mv_b[idx + self.w + 1] = mv;
352 fn get_mv_by_idx(&self, idx: usize, fwd: bool) -> MV {
353 if fwd { self.mv_f[idx] } else { self.mv_b[idx] }
355 fn pred_mv(&self, idx: usize, fwd: bool, has_top: bool, has_left: bool, has_tr: bool, has_tl: bool, is16: bool) -> MV {
356 if !has_top && !has_left { return ZERO_MV; }
357 let left_mv = if has_left { self.get_mv_by_idx(idx - 1, fwd) } else { ZERO_MV };
358 let top_mv = if has_top { self.get_mv_by_idx(idx - self.w, fwd) } else { left_mv };
359 let tr_add = if is16 { 2 } else { 1 };
362 tr_mv = self.get_mv_by_idx(idx - self.w + tr_add, fwd);
364 tr_mv = self.get_mv_by_idx(idx - self.w - 1, fwd);
368 MV::pred(left_mv, top_mv, tr_mv)
370 pub fn pred_mb_mv(&self, mb_x: usize, mb_y: usize, fwd: bool, has_top: bool, has_left: bool, has_tr: bool, has_tl: bool) -> MV {
371 self.pred_mv(mb_x * 2 + mb_y * 2 * self.w, fwd, has_top, has_left, has_tr, has_tl, true)
373 fn set_mb(&mut self, mb_x: usize, mb_y: usize, mbtype: MBType, ref_mvi: &Self, mvs: &[MV], sstate: &SState) {
374 let mb_idx = mb_x + mb_y * (self.w >> 1);
375 self.has_f[mb_idx] = mbtype.is_fwd();
376 self.has_b[mb_idx] = mbtype.is_bwd();
377 if mbtype.is_nomv() {
378 self.fill(mb_x, mb_y, true, ZERO_MV);
379 self.fill(mb_x, mb_y, false, ZERO_MV);
383 self.fill(mb_x, mb_y, false, ZERO_MV);
384 } else if mbtype.is_bwd() {
385 self.fill(mb_x, mb_y, true, ZERO_MV);
387 let idx = mb_x * 2 + mb_y * 2 * self.w;
391 self.fill(mb_x, mb_y, true, ZERO_MV/*pred_mv*/);
394 MBType::MBP16x16Mix => {
395 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
396 let new_mv = mvs[0] + pred_mv;
397 self.fill(mb_x, mb_y, true, new_mv);
400 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
401 let new_mv = mvs[0] + pred_mv;
402 self.mv_f[idx + 0] = new_mv;
403 self.mv_f[idx + 1] = new_mv;
405 let idx2 = idx + self.w;
406 let pred_mv = self.pred_mv(idx2, true, true, sstate.has_left, false, sstate.has_left, true);
407 let new_mv = mvs[1] + pred_mv;
408 self.mv_f[idx2 + 0] = new_mv;
409 self.mv_f[idx2 + 1] = new_mv;
412 let pred_mv = self.pred_mv(idx, true, sstate.has_top, sstate.has_left, sstate.has_top, sstate.has_tl, false);
413 let new_mv = mvs[0] + pred_mv;
414 self.mv_f[idx] = new_mv;
415 self.mv_f[idx + self.w] = new_mv;
417 let pred_mv = self.pred_mv(idx + 1, true, sstate.has_top, true, sstate.has_tr, sstate.has_top, false);
418 let new_mv = mvs[1] + pred_mv;
419 self.mv_f[idx + 1] = new_mv;
420 self.mv_f[idx + self.w + 1] = new_mv;
424 let mut has_top = sstate.has_top;
427 let has_left = (x > 0) || sstate.has_left;
428 let has_tr = if y > 0 { x == 0 } else if x == 0 { sstate.has_top } else { sstate.has_tr };
431 has_tl = if x == 0 { sstate.has_tl } else { sstate.has_top };
433 has_tl = if x == 0 { sstate.has_left } else { true };
435 let pred_mv = self.pred_mv(idx8 + x, true, has_top, has_left, has_tr, has_tl, false);
436 let new_mv = mvs[x + y * 2] + pred_mv;
437 self.mv_f[idx8 + x] = new_mv;
443 MBType::MBDirect => {
444 let mut cum_mv_f = ZERO_MV;
445 let mut cum_mv_b = ZERO_MV;
449 let (mv_f, mv_b) = ref_mvi.mv_f[idx8 + x].scale(sstate.trd, sstate.trb);
459 self.fill(mb_x, mb_y, true, cum_mv_f);
460 self.fill(mb_x, mb_y, false, cum_mv_b);
463 let pred_mv_f = ZERO_MV;
464 let new_mv = pred_mv_f + mvs[0];
465 self.fill(mb_x, mb_y, true, new_mv);
466 let pred_mv_b = ZERO_MV;
467 let new_mv = pred_mv_b + mvs[1];
468 self.fill(mb_x, mb_y, false, new_mv);
470 MBType::MBForward => {
471 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
472 let new_mv = mvs[0] + pred_mv;
473 self.fill(mb_x, mb_y, true, new_mv);
475 MBType::MBBackward => {
476 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
477 let new_mv = mvs[0] + pred_mv;
478 self.fill(mb_x, mb_y, false, new_mv);
483 pub fn get_mv(&self, mb_x: usize, mb_y: usize, x: usize, y: usize, fwd: bool) -> MV {
484 let idx = mb_x * 2 + x + (mb_y * 2 + y) * self.w;
485 if fwd { self.mv_f[idx] }
486 else { self.mv_b[idx] }
488 fn mv_gt_3(&self, mb_x: usize, mb_y: usize, x: usize, y: usize, vert: bool) -> bool {
489 let idx = mb_x * 2 + x + (mb_y * 2 + y) * self.w;
490 let off = if vert { self.w } else { 1 };
491 let diffx = self.mv_f[idx].x - self.mv_f[idx - off].x;
492 let diffy = self.mv_f[idx].y - self.mv_f[idx - off].y;
493 (diffx < -3) || (diffx > 3) || (diffy < -3) || (diffy > 3)
497 pub trait RV34BitstreamDecoder {
498 fn decode_slice_header(&mut self, br: &mut BitReader, old_w: usize, old_h: usize) -> DecoderResult<RV34SliceHeader>;
499 fn decode_intra_pred(&mut self, br: &mut BitReader, types: &mut [i8], pos: usize, tstride: usize, has_top: bool) -> DecoderResult<()>;
500 fn quant_dc(&self, is_intra: bool, q: u8) -> u8;
501 fn decode_inter_mb_hdr(&mut self, br: &mut BitReader, ftype: FrameType, mbtype: MBType) -> DecoderResult<MBInfo>;
502 fn predict_b_mv(&self, sstate: &SState, mvi: &MVInfo, mbtype: MBType, mvs: &[MV], mbinfo: &[RV34MBInfo]) -> (MV, MV);
506 fn loop_filter(&self, frame: &mut NAVideoBuffer<u8>, ftype: FrameType, mbinfo: &[RV34MBInfo], mb_w: usize, row: usize);
507 fn do_luma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, mv: MV, use16: bool, avg: bool);
508 fn do_chroma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, comp: usize, mv: MV, use8: bool, avg: bool);
511 fn parse_slice_offsets(src: &[u8], offsets: &mut Vec<usize>) -> DecoderResult<()> {
512 let num_slices = (src[0] as usize) + 1;
513 let ini_off = num_slices * 8 + 1;
516 if ini_off >= src.len() { return Err(DecoderError::ShortData); }
518 let mut br = BitReader::new(&src[1..ini_off], BitReaderMode::BE);
520 for i in 0..num_slices {
522 let off = br.read(32)? as usize;
523 if (i == 0) && (off != 0) {
524 return Err(DecoderError::InvalidData);
526 if (i > 0) && (off <= offsets[i - 1]) {
527 return Err(DecoderError::InvalidData);
535 fn decode_slice_header(br: &mut BitReader, bd: &mut RV34BitstreamDecoder, slice_no: usize, slice_offs: &[usize], old_width: usize, old_height: usize) -> DecoderResult<RV34SliceHeader> {
536 validate!(slice_no < slice_offs.len());
537 br.seek((slice_offs[slice_no] * 8) as u32)?;
538 let mut shdr = bd.decode_slice_header(br, old_width, old_height)?;
539 if slice_no < slice_offs.len() - 1 {
540 let cur_pos = br.tell() as u32;
541 br.seek((slice_offs[slice_no + 1] * 8) as u32)?;
542 if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
543 validate!(nhdr.start > shdr.start);
544 shdr.end = nhdr.start;
546 if slice_no + 2 < slice_offs.len() {
547 br.seek((slice_offs[slice_no + 2] * 8) as u32)?;
548 if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
549 validate!(nhdr.start > shdr.start);
550 shdr.end = nhdr.start;
552 shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
555 shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
560 shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
565 const RV34_MB_MAX_SIZES: [usize; 6] = [ 0x2F, 0x62, 0x18B, 0x62F, 0x18BF, 0x23FF ];
566 const RV34_SLICE_START_BITS: [u8; 6] = [ 6, 7, 9, 11, 13, 14 ];
568 pub fn get_slice_start_offset_bits(w: usize, h: usize) -> u8 {
569 let mb_size = ((w + 15) >> 4) * ((h + 15) >> 4) - 1;
570 let mut idx: usize = 0;
571 while (idx < 5) && (RV34_MB_MAX_SIZES[idx] < mb_size) { idx += 1; }
572 RV34_SLICE_START_BITS[idx]
575 const RV34_DQUANT_TAB: [[i8; 2]; 32] = [
576 [ 0, 0 ], [ 2, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ],
577 [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ],
578 [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -3, 3 ], [ -3, 3 ], [ -3, 3 ],
579 [ -3, 3 ], [ -3, 3 ], [ -3, 3 ], [ -3, 3 ], [ -3, 3 ], [ -3, 2 ], [ -3, 1 ], [ -3,-5 ]
582 const RV34_QUANT_TAB: [u16; 32] = [
583 60, 67, 76, 85, 96, 108, 121, 136,
584 152, 171, 192, 216, 242, 272, 305, 341,
585 383, 432, 481, 544, 606, 683, 767, 854,
586 963, 1074, 1212, 1392, 1566, 1708, 1978, 2211
589 const RV34_CHROMA_QUANT_DC: [u8; 32] = [
590 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
591 14, 15, 15, 16, 17, 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23
593 const RV34_CHROMA_QUANT_AC: [u8; 32] = [
594 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
595 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25
598 fn decode_dquant(br: &mut BitReader, q: u8) -> DecoderResult<u8> {
600 let diff = RV34_DQUANT_TAB[q as usize][br.read(1)? as usize];
601 let qp = (q as i8) + diff;
602 validate!((qp > 0) && (qp < 32));
605 let qp = br.read(5)? as u8;
655 fn new(ftype: FrameType) -> Self { Self { is_p: ftype == FrameType::P, hist: [MBType::Invalid; 4], count: 0 } }
656 fn add(&mut self, mbt: MBType) {
657 let mbt2 = match mbt {
658 MBType::MBSkip if self.is_p => MBType::MBP16x16,
659 MBType::MBSkip if !self.is_p => MBType::MBDirect,
662 self.hist[self.count] = mbt2;
665 fn get_mbtype(&self) -> MBType {
668 } else if self.count == 1 {
670 } else if self.count == 2 {
671 if self.hist[0].get_weight() <= self.hist[1].get_weight() {
677 let mut w: [usize; 12] = [0; 12];
678 for i in 0..self.count { w[self.hist[i].get_weight()] += 1; }
681 if w[i] == self.count { return MBTYPE_FROM_WEIGHT[i]; }
682 if (w[i] > w[nz_idx]) || (w[nz_idx] == 0) { nz_idx = i; }
685 MBTYPE_FROM_WEIGHT[nz_idx]
690 fn decode_mv(br: &mut BitReader) -> DecoderResult<MV> {
691 let x = br.read_code_signed(IntCodeType::Gamma)? as i16;
692 let y = br.read_code_signed(IntCodeType::Gamma)? as i16;
696 fn do_mc_16x16(dsp: &Box<dyn RV34DSP + Send>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, mb_y: usize, mv: MV, avg: bool) {
697 dsp.do_luma_mc (buf, prevbuf, mb_x * 16, mb_y * 16, mv, true, avg);
698 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8, mb_y * 8, 1, mv, true, avg);
699 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8, mb_y * 8, 2, mv, true, avg);
702 fn do_mc_8x8(dsp: &Box<dyn RV34DSP + Send>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, xoff: usize, mb_y: usize, yoff: usize, mv: MV, avg: bool) {
703 dsp.do_luma_mc (buf, prevbuf, mb_x * 16 + xoff * 8, mb_y * 16 + yoff * 8, mv, false, avg);
704 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8 + xoff * 4, mb_y * 8 + yoff * 4, 1, mv, false, avg);
705 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8 + xoff * 4, mb_y * 8 + yoff * 4, 2, mv, false, avg);
708 fn do_avg(cdsp: &RV34CommonDSP, buf: &mut NAVideoBuffer<u8>, avg_buf: &NAVideoBuffer<u8>, mb_x: usize, xb: usize, mb_y: usize, yb: usize, size: usize, ratio1: u32, ratio2: u32) {
710 let xoff = if comp == 0 { mb_x * 16 + xb * 8 } else { mb_x * 8 + xb * 4 };
711 let yoff = if comp == 0 { mb_y * 16 + yb * 8 } else { mb_y * 8 + yb * 4 };
712 let csize = if comp == 0 { size } else { size >> 1 };
713 let dstride = buf.get_stride(comp);
714 let doffset = buf.get_offset(comp) + xoff + yoff * dstride;
715 let data = buf.get_data_mut().unwrap();
716 let dst: &mut [u8] = data.as_mut_slice();
718 let sstride = avg_buf.get_stride(comp);
719 let soffset = avg_buf.get_offset(comp);
720 let data = avg_buf.get_data();
721 let src: &[u8] = data.as_slice();
723 if ratio1 == ratio2 {
724 cdsp.avg(dst, doffset, dstride, src, soffset, sstride, csize);
726 cdsp.weight(dst, doffset, dstride, src, soffset, sstride, ratio2, ratio1, csize);
731 pub struct RV34Decoder {
734 dsp: Box<dyn RV34DSP + Send>,
746 mbinfo: Vec<RV34MBInfo>,
747 avg_buf: NAVideoBufferRef<u8>,
752 pub fn new(is_rv30: bool, dsp: Box<dyn RV34DSP + Send>) -> Self {
753 let tmp_vinfo = NAVideoInfo::new(16, 16, false, YUV420_FORMAT);
754 let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
755 let vb = vt.get_vbuf();
756 let avg_buf = vb.unwrap();
759 coderead: RV34Codes::new(),
761 cdsp: RV34CommonDSP::new(),
762 ipbs: IPBShuffler::new(),
764 ref_mvi: MVInfo::new(),
767 last_ts: 0, next_ts: 0,
768 ratio1: 0, ratio2: 0,
774 fn decode_mb_header_intra(&mut self, bd: &mut RV34BitstreamDecoder, br: &mut BitReader, is_i16: bool, im: &mut IntraModeState, q: u8, has_top: bool, has_dq: bool) -> DecoderResult<MBInfo> {
776 let imode = br.read(2)? as i8;
777 im.fill_block(imode);
778 Ok(MBInfo { mbtype: MBType::MBIntra16, skip_run: 0, dquant: false })
780 let dq = if !has_dq {
781 if !self.is_rv30 { !br.read_bool()? } else { false }
784 decode_dquant(br, q)?;
786 bd.decode_intra_pred(br, im.cache.data.as_mut_slice(), im.cache.xpos, im.cache.stride, has_top)?;
787 Ok(MBInfo { mbtype: MBType::MBIntra, skip_run: 0, dquant: dq })
790 fn decode_mb_header_inter(&mut self, bd: &mut RV34BitstreamDecoder, br: &mut BitReader, ftype: FrameType, mbtype: MBType, im: &mut IntraModeState, q: u8, has_top: bool) -> DecoderResult<MBInfo> {
791 let hdr = bd.decode_inter_mb_hdr(br, ftype, mbtype)?;
792 validate!(hdr.mbtype != MBType::Invalid);
794 decode_dquant(br, q)?;
796 if hdr.mbtype.is_intra() {
797 return self.decode_mb_header_intra(bd, br, hdr.mbtype.is_16(), im, q, has_top, true);
802 fn decode_mb_intra(&mut self, sstate: &SState, imode: &IntraModeState, buf: &mut NAVideoBuffer<u8>, br: &mut BitReader, is_16: bool) -> DecoderResult<()> {
803 let mut cur_cbp = sstate.cbp;
805 let q_dc = RV34_QUANT_TAB[sstate.q_dc as usize];
806 let q_ac = RV34_QUANT_TAB[sstate.q as usize];
807 let luma_set = if is_16 { 2 } else { 1 };
808 let mut coeffs16: [i16; 16] = [0; 16];
810 let has_ac = self.coderead.decode_block(br, &mut coeffs16, 3, 0, q_dc, q_dc, q_ac)?;
812 self.cdsp.transform16(&mut coeffs16);
814 self.cdsp.transform16_dc(&mut coeffs16);
817 let stride = buf.get_stride(0);
818 let mut offset = buf.get_offset(0) + sstate.mb_x * 16 + sstate.mb_y * 16 * stride;
819 let data = buf.get_data_mut().unwrap();
820 let framebuf: &mut [u8] = data.as_mut_slice();
823 let im16 = imode.get_pred16_type(sstate.has_top, sstate.has_left);
824 self.cdsp.ipred16x16[im16 as usize](framebuf, offset, stride);
829 let mut coeffs: [i16; 16] = [0; 16];
831 if (cur_cbp & 1) != 0 {
832 has_ac = self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?;
837 coeffs[0] = coeffs16[x + y * 4];
839 let noright = (sstate.mb_x == sstate.mb_w - 1) && (x == 3);
840 let has_top = sstate.has_top || (y > 0);
841 let im = imode.get_pred4_type(x, y, sstate.has_top, sstate.has_left);
842 let topright: [u8; 4] = if (noright && sstate.has_top && y == 0) || (x == 3 && y > 0) {
843 let i = offset + x * 4 - stride;
844 [framebuf[i + 3], framebuf[i + 3], framebuf[i + 3], framebuf[i + 3]]
846 let i = offset + x * 4 - stride;
847 [framebuf[i + 4], framebuf[i + 5], framebuf[i + 6], framebuf[i + 7]]
851 self.cdsp.ipred4x4[im as usize](framebuf, offset + x*4, stride, &topright);
854 self.cdsp.transform(&mut coeffs);
856 self.cdsp.transform_dc(&mut coeffs);
858 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
861 offset += stride * 4;
864 let q_dc = RV34_QUANT_TAB[RV34_CHROMA_QUANT_DC[sstate.q as usize] as usize];
865 let q_ac = RV34_QUANT_TAB[RV34_CHROMA_QUANT_AC[sstate.q as usize] as usize];
868 let stride = buf.get_stride(comp);
869 let mut offset = buf.get_offset(comp) + sstate.mb_x * 8 + sstate.mb_y * 8 * stride;
870 let data = buf.get_data_mut().unwrap();
871 let framebuf: &mut [u8] = data.as_mut_slice();
873 let im8 = imode.get_pred8_type(sstate.has_top, sstate.has_left);
874 self.cdsp.ipred8x8[im8 as usize](framebuf, offset, stride);
878 let mut coeffs: [i16; 16] = [0; 16];
880 if (cur_cbp & 1) != 0 {
881 has_ac = self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?;
886 let noright = (sstate.mb_x == sstate.mb_w - 1) && (x == 1);
887 let has_top = sstate.has_top || (y > 0);
888 let im = imode.get_pred4_type_chroma(x, y, sstate.has_top, sstate.has_left);
889 let topright: [u8; 4] = if (noright && sstate.has_top && y == 0) || (x == 1 && y > 0) {
890 let i = offset + x * 4 - stride;
891 [framebuf[i + 3], framebuf[i + 3], framebuf[i + 3], framebuf[i + 3]]
893 let i = offset + x * 4 - stride;
894 [framebuf[i + 4], framebuf[i + 5], framebuf[i + 6], framebuf[i + 7]]
898 self.cdsp.ipred4x4[im as usize](framebuf, offset + x*4, stride, &topright);
901 self.cdsp.transform(&mut coeffs);
903 self.cdsp.transform_dc(&mut coeffs);
905 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
908 offset += stride * 4;
914 fn do_mc(&mut self, buf: &mut NAVideoBuffer<u8>, mbh: &MBInfo, sstate: &SState) {
915 let mb_x = sstate.mb_x;
916 let mb_y = sstate.mb_y;
918 MBType::MBP16x16 | MBType::MBP16x16Mix => {
919 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
920 let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
921 do_mc_16x16(&self.dsp, buf, prevbuf, mb_x, mb_y, mv, false);
924 MBType::MBForward => {
925 if let Some(ref fwdbuf) = self.ipbs.get_b_fwdref() {
926 let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
927 do_mc_16x16(&self.dsp, buf, fwdbuf, mb_x, mb_y, mv, false);
930 MBType::MBBackward => {
931 if let Some(ref bwdbuf) = self.ipbs.get_b_bwdref() {
932 let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, false);
933 do_mc_16x16(&self.dsp, buf, bwdbuf, mb_x, mb_y, mv, false);
936 MBType::MBP8x8 | MBType::MBP8x16 | MBType::MBP16x8 => {
937 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
940 let mv = self.mvi.get_mv(mb_x, mb_y, x, y, true);
941 do_mc_8x8(&self.dsp, buf, prevbuf, mb_x, x, mb_y, y, mv, false);
946 MBType::MBSkip if !self.is_b => {
947 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
948 do_mc_16x16(&self.dsp, buf, prevbuf, mb_x, mb_y, ZERO_MV, false);
951 MBType::MBSkip | MBType::MBDirect => {
952 if let (Some(ref fwdbuf), Some(ref bwdbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
955 let (mv_f, mv_b) = self.ref_mvi.get_mv(mb_x, mb_y, x, y, true).scale(sstate.trd, sstate.trb);
956 do_mc_8x8(&self.dsp, buf, fwdbuf, mb_x, x, mb_y, y, mv_f, false);
957 do_mc_8x8(&self.dsp, &mut self.avg_buf, bwdbuf, mb_x, x, mb_y, y, mv_b, true);
958 do_avg(&self.cdsp, buf, &self.avg_buf, mb_x, x, mb_y, y, 8, self.ratio1, self.ratio2);
964 if let (Some(ref fwdbuf), Some(ref bwdbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
965 let mv_f = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
966 let mv_b = self.mvi.get_mv(mb_x, mb_y, 0, 0, false);
967 do_mc_16x16(&self.dsp, buf, fwdbuf, mb_x, mb_y, mv_f, false);
968 do_mc_16x16(&self.dsp, &mut self.avg_buf, bwdbuf, mb_x, mb_y, mv_b, true);
969 do_avg(&self.cdsp, buf, &self.avg_buf, mb_x, 0, mb_y, 0, 16, self.ratio1, self.ratio2);
975 fn decode_mb_inter(&mut self, sstate: &SState, mbh: &MBInfo, buf: &mut NAVideoBuffer<u8>, br: &mut BitReader, is_16: bool) -> DecoderResult<()> {
976 self.do_mc(buf, mbh, sstate);
978 let mut cur_cbp = sstate.cbp;
981 let q_dc = RV34_QUANT_TAB[sstate.q_dc as usize];
982 let q_ac = RV34_QUANT_TAB[sstate.q as usize];
983 let luma_set = if is_16 { 2 } else { 0 };
984 let mut coeffs16: [i16; 16] = [0; 16];
986 let has_ac = self.coderead.decode_block(br, &mut coeffs16, 3, 0, q_dc, q_dc, q_ac)?;
988 self.cdsp.transform16(&mut coeffs16);
990 self.cdsp.transform16_dc(&mut coeffs16);
993 let stride = buf.get_stride(0);
994 let mut offset = buf.get_offset(0) + sstate.mb_x * 16 + sstate.mb_y * 16 * stride;
995 let data = buf.get_data_mut().unwrap();
996 let framebuf: &mut [u8] = data.as_mut_slice();
1000 let mut coeffs: [i16; 16] = [0; 16];
1002 if (cur_cbp & 1) != 0 {
1003 has_ac = self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?;
1008 coeffs[0] = coeffs16[x + y * 4];
1011 self.cdsp.transform(&mut coeffs);
1013 self.cdsp.transform_dc(&mut coeffs);
1015 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
1018 offset += stride * 4;
1022 self.coderead.select_codes(false, sstate.q, sstate.set_idx, false);
1024 let q_dc = RV34_QUANT_TAB[RV34_CHROMA_QUANT_DC[sstate.q as usize] as usize];
1025 let q_ac = RV34_QUANT_TAB[RV34_CHROMA_QUANT_AC[sstate.q as usize] as usize];
1028 let stride = buf.get_stride(comp);
1029 let mut offset = buf.get_offset(comp) + sstate.mb_x * 8 + sstate.mb_y * 8 * stride;
1030 let data = buf.get_data_mut().unwrap();
1031 let framebuf: &mut [u8] = data.as_mut_slice();
1034 let mut coeffs: [i16; 16] = [0; 16];
1036 if (cur_cbp & 1) != 0 {
1037 has_ac = self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?;
1042 self.cdsp.transform(&mut coeffs);
1044 self.cdsp.transform_dc(&mut coeffs);
1046 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
1049 offset += stride * 4;
1054 fn fill_deblock_flags(&self, sstate: &SState, mb_pos: usize, mbinfo: &mut Vec<RV34MBInfo>) {
1055 let mbt = mbinfo[mb_pos].mbtype;
1056 let mut hmvmask = 0;
1057 let mut vmvmask = 0;
1061 let shift = x * 2 + y * 8;
1062 if ((x > 0) || (sstate.mb_x > 0)) && self.mvi.mv_gt_3(sstate.mb_x, sstate.mb_y, x, y, false) {
1063 vmvmask |= 0x11 << shift;
1065 if ((y > 0) || sstate.has_top) && self.mvi.mv_gt_3(sstate.mb_x, sstate.mb_y, x, y, true) {
1066 hmvmask |= 0x03 << shift;
1070 if !sstate.has_top { hmvmask &= !0x000F; }
1071 if sstate.mb_x == 0 { vmvmask &= !0x1111; }
1073 vmvmask |= (vmvmask & 0x4444) >> 1;
1074 hmvmask |= (hmvmask & 0x0F00) >> 4;
1075 if sstate.mb_x > 0 {
1076 mbinfo[mb_pos - 1].deblock |= (vmvmask & 0x1111) << 3;
1080 mbinfo[mb_pos - sstate.mb_w].deblock |= (hmvmask & 0xF) << 12;
1083 if mbt.is_intra_or_16() {
1084 mbinfo[mb_pos].deblock = 0xFFFF;
1085 mbinfo[mb_pos].cbp_c = 0xFF;
1087 mbinfo[mb_pos].deblock = (mbinfo[mb_pos].cbp as u16) | hmvmask | vmvmask;
1088 mbinfo[mb_pos].cbp_c = (mbinfo[mb_pos].cbp >> 16) as u8;
1092 pub fn parse_frame(&mut self, supp: &mut NADecoderSupport, src: &[u8], bd: &mut RV34BitstreamDecoder) -> DecoderResult<(NABufferType, FrameType, u64)> {
1093 let mut slice_offs: Vec<usize> = Vec::new();
1094 parse_slice_offsets(src, &mut slice_offs)?;
1095 let ini_off = slice_offs.len() * 8 + 1;
1097 let mut br = BitReader::new(&src[ini_off..], BitReaderMode::BE);
1098 let hdr0 = decode_slice_header(&mut br, bd, 0, slice_offs.as_slice(), self.width, self.height)?;
1099 validate!((hdr0.width != 0) && (hdr0.height != 0));
1100 self.width = hdr0.width;
1101 self.height = hdr0.height;
1102 let mb_w = (hdr0.width + 15) >> 4;
1103 let mb_h = (hdr0.height + 15) >> 4;
1104 let mut mb_pos: usize = 0;
1105 let mut slice = hdr0;
1106 let mut slice_no: usize = 1;
1107 let is_intra = hdr0.ftype == FrameType::I;
1108 let mut skip_run: usize = 0;
1109 let mut imode = IntraModeState::new(mb_w);
1110 let mut q = hdr0.quant;
1112 let mut sstate = SState::new();
1113 let mut mbinfo: Vec<RV34MBInfo> = Vec::with_capacity(mb_w * mb_h);
1115 self.is_b = hdr0.ftype == FrameType::B;
1116 if hdr0.ftype != FrameType::B {
1117 self.last_ts = self.next_ts;
1118 self.next_ts = hdr0.pts;
1119 if self.last_ts > self.next_ts {
1120 self.base_ts += 1 << 13;
1125 if self.ipbs.get_lastref().is_none() {
1126 return Err(DecoderError::MissingReference);
1130 if self.ipbs.get_lastref().is_none() {
1131 return Err(DecoderError::MissingReference);
1133 if self.ipbs.get_nextref().is_none() {
1134 return Err(DecoderError::MissingReference);
1139 let ts_diff = (self.next_ts << 3).wrapping_sub(hdr0.pts << 3) >> 3;
1140 let ts = self.base_ts + (self.next_ts as u64) - (ts_diff as u64);
1141 sstate.trd = (self.next_ts << 3).wrapping_sub(self.last_ts << 3) >> 3;
1142 sstate.trb = (hdr0.pts << 3).wrapping_sub(self.last_ts << 3) >> 3;
1143 if sstate.trb != 0 {
1144 self.ratio1 = ((sstate.trb as u32) << 14) / (sstate.trd as u32);
1145 self.ratio2 = (((sstate.trd as u32) - (sstate.trb as u32)) << 14) / (sstate.trd as u32);
1147 self.ratio1 = 1 << 14 >> 1;
1148 self.ratio2 = 1 << 14 >> 1;
1150 //todo validate against ref frame
1152 let vinfo = NAVideoInfo::new(hdr0.width, hdr0.height, false, YUV420_FORMAT);
1153 let ret = supp.pool_u8.get_free();
1155 return Err(DecoderError::AllocError);
1157 let mut buf = ret.unwrap();
1158 if buf.get_info() != vinfo {
1160 supp.pool_u8.reset();
1161 supp.pool_u8.prealloc_video(vinfo, 4)?;
1162 let ret = supp.pool_u8.get_free();
1164 return Err(DecoderError::AllocError);
1170 sstate.has_top = false;
1173 sstate.set_idx = hdr0.set_idx;
1175 self.mvi.resize(mb_w, mb_h);
1176 for mb_y in 0..mb_h {
1178 sstate.has_left = false;
1179 for mb_x in 0..mb_w {
1181 if mb_pos == slice.end {
1182 slice = decode_slice_header(&mut br, bd, slice_no, &slice_offs, self.width, self.height)?;
1183 validate!(slice.fits(&hdr0));
1188 sstate.has_top = false;
1189 sstate.has_left = false;
1190 sstate.set_idx = slice.set_idx;
1192 sstate.has_top = (mb_pos - slice.start) >= mb_w;
1193 sstate.has_tl = sstate.has_top && (mb_x > 0) && (mb_pos > slice.start + mb_w);
1194 sstate.has_tr = (mb_x < mb_w - 1) && (mb_pos - slice.start >= mb_w - 1);
1195 imode.set_mb_x(mb_x);
1196 let mbh = if is_intra {
1197 let is_i16 = br.read_bool()?;
1198 self.decode_mb_header_intra(bd, &mut br, is_i16, &mut imode, q, sstate.has_top, false)?
1203 mbtype = MBType::Invalid;
1205 let mut hist = MBHist::new(hdr0.ftype);
1207 hist.add(mbinfo[mb_pos - mb_w].mbtype);
1208 if sstate.has_tr { hist.add(mbinfo[mb_pos - mb_w + 1].mbtype); }
1210 if sstate.has_left { hist.add(mbinfo[mb_pos - 1].mbtype); }
1211 if sstate.has_tl { hist.add(mbinfo[mb_pos - mb_w - 1].mbtype); }
1212 mbtype = hist.get_mbtype();
1214 self.decode_mb_header_inter(bd, &mut br, hdr0.ftype, mbtype, &mut imode, q, sstate.has_top)?
1217 MBInfo { mbtype: MBType::MBSkip, skip_run: 0, dquant: false }
1220 if !mbh.mbtype.is_intra() {
1221 let mut mvs: [MV; 4] = [ZERO_MV; 4];
1222 for i in 0..mbh.mbtype.get_num_mvs() {
1223 mvs[i] = decode_mv(&mut br)?;
1226 self.mvi.set_mb(mb_x, mb_y, mbh.mbtype, &self.ref_mvi, &mvs, &sstate);
1228 let (mv_f, mv_b) = bd.predict_b_mv(&sstate, &self.mvi, mbh.mbtype, &mvs, mbinfo.as_slice());
1229 self.mvi.fill(mb_x, mb_y, true, mv_f);
1230 self.mvi.fill(mb_x, mb_y, false, mv_b);
1234 let is_16 = (mbh.mbtype == MBType::MBIntra16) || (mbh.mbtype == MBType::MBP16x16Mix);
1235 if mbh.mbtype == MBType::MBSkip {
1237 if mbh.skip_run > 0 {
1238 skip_run = mbh.skip_run;
1241 self.coderead.select_codes(mbh.mbtype.is_intra(), q, slice.set_idx, is_16);
1242 if mbh.mbtype == MBType::MBP16x16Mix {
1243 self.coderead.select_codes(true, q, slice.set_idx, true);
1245 cbp = self.coderead.decode_cbp(&mut br)?;
1248 if is_intra || mbh.mbtype.is_intra() {
1249 sstate.q_dc = bd.quant_dc(true, q);
1250 self.decode_mb_intra(&sstate, &imode, &mut buf, &mut br, is_16)?;
1252 imode.fill_block(0);
1253 self.decode_mb_inter(&sstate, &mbh, &mut buf, &mut br, is_16)?;
1256 let mi = RV34MBInfo { cbp, q, mbtype: mbh.mbtype, deblock: 0, cbp_c: 0 };
1259 mbinfo[mb_pos].deblock = 0xFFFF;
1260 mbinfo[mb_pos].cbp_c = 0xFF;
1262 self.fill_deblock_flags(&sstate, mb_pos, &mut mbinfo);
1264 sstate.has_left = true;
1267 if hdr0.deblock && (mb_y >= 1) {
1268 self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_y - 1);
1273 self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_h - 1);
1276 self.ipbs.add_frame(buf.clone());
1277 mem::swap(&mut self.mvi, &mut self.ref_mvi);
1278 mem::swap(&mut self.mbinfo, &mut mbinfo);
1281 Ok((NABufferType::Video(buf), hdr0.ftype, ts))
1283 pub fn flush(&mut self) {