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)
54 #[derive(Debug,Clone,Copy,PartialEq)]
72 pub fn is_intra(self) -> bool {
73 (self == MBType::MBIntra) || (self == MBType::MBIntra16)
75 pub fn is_16(self) -> bool {
76 (self == MBType::MBIntra16) || (self == MBType::MBP16x16Mix)
78 pub fn is_intra_or_16(self) -> bool {
79 self.is_intra() || self.is_16()
81 pub fn get_num_mvs(self) -> usize {
83 MBType::MBIntra | MBType::MBIntra16 |
84 MBType::MBSkip | MBType::MBDirect => 0,
85 MBType::MBP16x16 | MBType::MBP16x16Mix |
86 MBType::MBForward | MBType::MBBackward => 1,
87 MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBBidir => 2,
89 MBType::Invalid => unreachable!(),
92 pub fn is_fwd(self) -> bool {
94 MBType::MBP16x16 | MBType::MBP16x16Mix |
95 MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 |
98 pub fn is_bwd(self) -> bool {
99 matches!(self, MBType::MBBidir | MBType::MBBackward)
101 pub fn has_mv_dir(self, fwd: bool) -> bool {
103 MBType::MBBidir => true,
104 MBType::MBForward if fwd => true,
105 MBType::MBBackward if !fwd => true,
109 pub fn is_nomv(self) -> bool {
110 matches!(self, MBType::MBIntra | MBType::MBIntra16 | MBType::MBSkip | MBType::MBDirect)
112 /*pub fn is_16x16(self) -> bool {
114 MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 => false,
118 fn get_weight(self) -> usize {
120 MBType::MBIntra => 0,
121 MBType::MBIntra16 => 1,
122 MBType::MBSkip => unreachable!(),
123 MBType::MBP16x16 => 2,
124 MBType::MBP16x16Mix => 10,
125 MBType::MBP16x8 => 7,
126 MBType::MBP8x16 => 8,
128 MBType::MBDirect => 6,
129 MBType::MBBidir => 9,
130 MBType::MBForward => 4,
131 MBType::MBBackward => 5,
132 MBType::Invalid => unreachable!(),
137 const MBTYPE_FROM_WEIGHT: [MBType; 11] = [
138 MBType::MBIntra, MBType::MBIntra16, MBType::MBP16x16, MBType::MBP8x8,
139 MBType::MBForward, MBType::MBBackward, MBType::MBDirect, MBType::MBP16x8,
140 MBType::MBP8x16, MBType::MBBidir, MBType::MBP16x16Mix,
143 #[derive(Clone,Copy)]
150 #[derive(Clone,Copy)]
151 pub struct RV34MBInfo {
155 pub cbp_c: u8, // for deblocking purposes
159 struct IntraModeState {
160 cache: GenericCache<i8>,
163 const RV34_INTRA_PRED4: [PredType4x4; 9] = [
164 PredType4x4::DC, PredType4x4::Ver, PredType4x4::Hor,
165 PredType4x4::DiagDownRight, PredType4x4::DiagDownLeft,
166 PredType4x4::VerRight, PredType4x4::VerLeft,
167 PredType4x4::HorUp, PredType4x4::HorDown
170 const RV34_INTRA_PRED16: [PredType8x8; 4] = [
171 PredType8x8::DC, PredType8x8::Ver, PredType8x8::Hor, PredType8x8::Plane
174 impl IntraModeState {
175 fn new(mb_w: usize) -> Self {
176 let stride = 1 + mb_w * 4 + 1;
177 IntraModeState { cache: GenericCache::new(4, stride, -1) }
179 fn reset(&mut self) { self.cache.reset(); }
180 fn update(&mut self) { self.cache.update_row(); }
181 fn get_pos(&self, xpos: usize) -> usize {
182 self.cache.stride + 1 + xpos * 4
184 fn set_mb_x(&mut self, mb_x: usize) {
185 self.cache.xpos = self.get_pos(mb_x);
187 fn fill_block(&mut self, val: i8) {
188 let mut pos = self.cache.xpos;
191 self.cache.data[pos + j] = val;
193 pos += self.cache.stride;
196 fn get_pred16_type(&self, has_top: bool, has_left: bool) -> PredType8x8 {
197 if !has_top && !has_left { return PredType8x8::DC128; }
198 let mut im = RV34_INTRA_PRED16[self.cache.data[self.cache.xpos] as usize];
201 PredType8x8::Plane | PredType8x8::Ver => PredType8x8::Hor,
202 PredType8x8::DC => PredType8x8::LeftDC,
205 } else if !has_left {
207 PredType8x8::Plane | PredType8x8::Hor => PredType8x8::Ver,
208 PredType8x8::DC => PredType8x8::TopDC,
214 fn get_pred8_type(&self, has_top: bool, has_left: bool) -> PredType8x8 {
215 if !has_top && !has_left { return PredType8x8::DC128; }
216 let mut im = RV34_INTRA_PRED16[self.cache.data[self.cache.xpos] as usize];
217 im = match im { PredType8x8::Plane => PredType8x8::DC, _ => im };
220 PredType8x8::Plane | PredType8x8::Ver => PredType8x8::Hor,
221 PredType8x8::DC => PredType8x8::LeftDC,
224 } else if !has_left {
226 PredType8x8::Plane | PredType8x8::Hor => PredType8x8::Ver,
227 PredType8x8::DC => PredType8x8::TopDC,
233 fn get_pred4_type(&self, x: usize, y: usize, has_top: bool, has_left: bool) -> PredType4x4 {
234 let no_up = !has_top && (y == 0);
235 let no_left = !has_left && (x == 0);
236 if no_up && no_left { return PredType4x4::DC128; }
237 let no_down = !has_left || (x != 0) || (y == 3);
239 let mut im = RV34_INTRA_PRED4[self.cache.data[self.cache.xpos + x + y * self.cache.stride] as usize];
243 PredType4x4::Ver => PredType4x4::Hor,
244 PredType4x4::DC => PredType4x4::LeftDC,
249 PredType4x4::Hor => PredType4x4::Ver,
250 PredType4x4::DC => PredType4x4::TopDC,
251 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
257 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
258 PredType4x4::HorUp => PredType4x4::HorUpNoDown,
259 PredType4x4::VerLeft => PredType4x4::VerLeftNoDown,
266 fn get_pred4_type_chroma(&self, x: usize, y: usize, has_top: bool, has_left: bool) -> PredType4x4 {
267 let no_up = !has_top && (y == 0);
268 let no_left = !has_left && (x == 0);
269 if no_up && no_left { return PredType4x4::DC128; }
270 let no_down = !has_left || (x != 0) || (y == 1);
272 let mut im = RV34_INTRA_PRED4[self.cache.data[self.cache.xpos + x * 2 + y * 2 * self.cache.stride] as usize];
276 PredType4x4::Ver => PredType4x4::Hor,
277 PredType4x4::DC => PredType4x4::LeftDC,
282 PredType4x4::Hor => PredType4x4::Ver,
283 PredType4x4::DC => PredType4x4::TopDC,
284 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
290 PredType4x4::DiagDownLeft => PredType4x4::DiagDownLeftNoDown,
291 PredType4x4::HorUp => PredType4x4::HorUpNoDown,
292 PredType4x4::VerLeft => PredType4x4::VerLeftNoDown,
305 pub has_b: Vec<bool>,
306 pub has_f: Vec<bool>,
311 Self { mv_b: Vec::new(), mv_f: Vec::new(), w: 0, h: 0, has_b: Vec::new(), has_f: Vec::new() }
313 fn resize(&mut self, mb_w: usize, mb_h: usize) {
318 fn reset(&mut self) {
319 let size = self.w * self.h;
321 self.mv_f.resize(size, ZERO_MV);
323 self.mv_b.resize(size, ZERO_MV);
325 self.has_f.resize(size >> 2, false);
327 self.has_b.resize(size >> 2, false);
329 #[allow(clippy::identity_op)]
330 fn fill(&mut self, mb_x: usize, mb_y: usize, fwd: bool, mv: MV) {
331 let idx = mb_x * 2 + mb_y * 2 * self.w;
333 self.mv_f[idx + 0] = mv;
334 self.mv_f[idx + 1] = mv;
335 self.mv_f[idx + self.w + 0] = mv;
336 self.mv_f[idx + self.w + 1] = mv;
338 self.mv_b[idx + 0] = mv;
339 self.mv_b[idx + 1] = mv;
340 self.mv_b[idx + self.w + 0] = mv;
341 self.mv_b[idx + self.w + 1] = mv;
344 fn get_mv_by_idx(&self, idx: usize, fwd: bool) -> MV {
345 if fwd { self.mv_f[idx] } else { self.mv_b[idx] }
347 fn pred_mv(&self, idx: usize, fwd: bool, has_top: bool, has_left: bool, has_tr: bool, has_tl: bool, is16: bool) -> MV {
348 if !has_top && !has_left { return ZERO_MV; }
349 let left_mv = if has_left { self.get_mv_by_idx(idx - 1, fwd) } else { ZERO_MV };
350 let top_mv = if has_top { self.get_mv_by_idx(idx - self.w, fwd) } else { left_mv };
351 let tr_add = if is16 { 2 } else { 1 };
354 tr_mv = self.get_mv_by_idx(idx - self.w + tr_add, fwd);
356 tr_mv = self.get_mv_by_idx(idx - self.w - 1, fwd);
360 MV::pred(left_mv, top_mv, tr_mv)
362 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 {
363 self.pred_mv(mb_x * 2 + mb_y * 2 * self.w, fwd, has_top, has_left, has_tr, has_tl, true)
365 #[allow(clippy::collapsible_else_if)]
366 #[allow(clippy::identity_op)]
367 fn set_mb(&mut self, mb_x: usize, mb_y: usize, mbtype: MBType, ref_mvi: &Self, mvs: &[MV], sstate: &SState) {
368 let mb_idx = mb_x + mb_y * (self.w >> 1);
369 self.has_f[mb_idx] = mbtype.is_fwd();
370 self.has_b[mb_idx] = mbtype.is_bwd();
371 if mbtype.is_nomv() {
372 self.fill(mb_x, mb_y, true, ZERO_MV);
373 self.fill(mb_x, mb_y, false, ZERO_MV);
377 self.fill(mb_x, mb_y, false, ZERO_MV);
378 } else if mbtype.is_bwd() {
379 self.fill(mb_x, mb_y, true, ZERO_MV);
381 let idx = mb_x * 2 + mb_y * 2 * self.w;
385 self.fill(mb_x, mb_y, true, ZERO_MV/*pred_mv*/);
388 MBType::MBP16x16Mix => {
389 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
390 let new_mv = mvs[0] + pred_mv;
391 self.fill(mb_x, mb_y, true, new_mv);
394 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
395 let new_mv = mvs[0] + pred_mv;
396 self.mv_f[idx + 0] = new_mv;
397 self.mv_f[idx + 1] = new_mv;
399 let idx2 = idx + self.w;
400 let pred_mv = self.pred_mv(idx2, true, true, sstate.has_left, false, sstate.has_left, true);
401 let new_mv = mvs[1] + pred_mv;
402 self.mv_f[idx2 + 0] = new_mv;
403 self.mv_f[idx2 + 1] = new_mv;
406 let pred_mv = self.pred_mv(idx, true, sstate.has_top, sstate.has_left, sstate.has_top, sstate.has_tl, false);
407 let new_mv = mvs[0] + pred_mv;
408 self.mv_f[idx] = new_mv;
409 self.mv_f[idx + self.w] = new_mv;
411 let pred_mv = self.pred_mv(idx + 1, true, sstate.has_top, true, sstate.has_tr, sstate.has_top, false);
412 let new_mv = mvs[1] + pred_mv;
413 self.mv_f[idx + 1] = new_mv;
414 self.mv_f[idx + self.w + 1] = new_mv;
418 let mut has_top = sstate.has_top;
421 let has_left = (x > 0) || sstate.has_left;
422 let has_tr = if y > 0 { x == 0 } else if x == 0 { sstate.has_top } else { sstate.has_tr };
423 let has_tl = if y == 0 {
424 if x == 0 { sstate.has_tl } else { sstate.has_top }
426 if x == 0 { sstate.has_left } else { true }
428 let pred_mv = self.pred_mv(idx8 + x, true, has_top, has_left, has_tr, has_tl, false);
429 let new_mv = mvs[x + y * 2] + pred_mv;
430 self.mv_f[idx8 + x] = new_mv;
436 MBType::MBDirect => {
437 let mut cum_mv_f = ZERO_MV;
438 let mut cum_mv_b = ZERO_MV;
442 let (mv_f, mv_b) = ref_mvi.mv_f[idx8 + x].scale(sstate.trd, sstate.trb);
452 self.fill(mb_x, mb_y, true, cum_mv_f);
453 self.fill(mb_x, mb_y, false, cum_mv_b);
456 let pred_mv_f = ZERO_MV;
457 let new_mv = pred_mv_f + mvs[0];
458 self.fill(mb_x, mb_y, true, new_mv);
459 let pred_mv_b = ZERO_MV;
460 let new_mv = pred_mv_b + mvs[1];
461 self.fill(mb_x, mb_y, false, new_mv);
463 MBType::MBForward => {
464 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
465 let new_mv = mvs[0] + pred_mv;
466 self.fill(mb_x, mb_y, true, new_mv);
468 MBType::MBBackward => {
469 let pred_mv = self.pred_mv(idx, mbtype.is_fwd(), sstate.has_top, sstate.has_left, sstate.has_tr, sstate.has_tl, true);
470 let new_mv = mvs[0] + pred_mv;
471 self.fill(mb_x, mb_y, false, new_mv);
476 pub fn get_mv(&self, mb_x: usize, mb_y: usize, x: usize, y: usize, fwd: bool) -> MV {
477 let idx = mb_x * 2 + x + (mb_y * 2 + y) * self.w;
478 if fwd { self.mv_f[idx] }
479 else { self.mv_b[idx] }
481 fn mv_gt_3(&self, mb_x: usize, mb_y: usize, x: usize, y: usize, vert: bool) -> bool {
482 let idx = mb_x * 2 + x + (mb_y * 2 + y) * self.w;
483 let off = if vert { self.w } else { 1 };
484 let diffx = self.mv_f[idx].x - self.mv_f[idx - off].x;
485 let diffy = self.mv_f[idx].y - self.mv_f[idx - off].y;
486 (diffx.abs() > 3) || (diffy.abs() > 3)
490 pub trait RV34BitstreamDecoder {
491 fn decode_slice_header(&mut self, br: &mut BitReader, old_w: usize, old_h: usize) -> DecoderResult<RV34SliceHeader>;
492 fn decode_intra_pred(&mut self, br: &mut BitReader, types: &mut [i8], pos: usize, tstride: usize, has_top: bool) -> DecoderResult<()>;
493 fn quant_dc(&self, is_intra: bool, q: u8) -> u8;
494 fn decode_inter_mb_hdr(&mut self, br: &mut BitReader, ftype: FrameType, mbtype: MBType) -> DecoderResult<MBInfo>;
495 fn predict_b_mv(&self, sstate: &SState, mvi: &MVInfo, mbtype: MBType, mvs: &[MV], mbinfo: &[RV34MBInfo]) -> (MV, MV);
499 fn loop_filter(&self, frame: &mut NAVideoBuffer<u8>, ftype: FrameType, mbinfo: &[RV34MBInfo], mb_w: usize, mb_h: usize, row: usize);
500 fn do_luma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, mv: MV, use16: bool, avg: bool);
501 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);
504 fn parse_slice_offsets(src: &[u8], offsets: &mut Vec<usize>) -> DecoderResult<()> {
505 let num_slices = (src[0] as usize) + 1;
506 let ini_off = num_slices * 8 + 1;
509 if ini_off >= src.len() { return Err(DecoderError::ShortData); }
511 let mut br = BitReader::new(&src[1..ini_off], BitReaderMode::BE);
513 for i in 0..num_slices {
515 let off = br.read(32)? as usize;
516 if (i == 0) && (off != 0) {
517 return Err(DecoderError::InvalidData);
519 if (i > 0) && (off <= offsets[i - 1]) {
520 return Err(DecoderError::InvalidData);
528 fn decode_slice_header(br: &mut BitReader, bd: &mut dyn RV34BitstreamDecoder, slice_no: usize, slice_offs: &[usize], old_width: usize, old_height: usize) -> DecoderResult<RV34SliceHeader> {
529 validate!(slice_no < slice_offs.len());
530 br.seek((slice_offs[slice_no] * 8) as u32)?;
531 let mut shdr = bd.decode_slice_header(br, old_width, old_height)?;
532 if ((shdr.width == 0) || (shdr.height == 0)) && (shdr.ftype != FrameType::I) {
533 return Err(DecoderError::MissingReference);
535 if slice_no < slice_offs.len() - 1 {
536 let cur_pos = br.tell() as u32;
537 br.seek((slice_offs[slice_no + 1] * 8) as u32)?;
538 if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
539 validate!(nhdr.start > shdr.start);
540 shdr.end = nhdr.start;
541 } else if slice_no + 2 < slice_offs.len() {
542 br.seek((slice_offs[slice_no + 2] * 8) as u32)?;
543 if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
544 validate!(nhdr.start > shdr.start);
545 shdr.end = nhdr.start;
547 shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
550 shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
554 shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
559 const RV34_MB_MAX_SIZES: [usize; 6] = [ 0x2F, 0x62, 0x18B, 0x62F, 0x18BF, 0x23FF ];
560 const RV34_SLICE_START_BITS: [u8; 6] = [ 6, 7, 9, 11, 13, 14 ];
562 pub fn get_slice_start_offset_bits(w: usize, h: usize) -> u8 {
563 if (w == 0) || (h == 0) {
566 let mb_size = ((w + 15) >> 4) * ((h + 15) >> 4) - 1;
567 let mut idx: usize = 0;
568 while (idx < 5) && (RV34_MB_MAX_SIZES[idx] < mb_size) { idx += 1; }
569 RV34_SLICE_START_BITS[idx]
572 const RV34_DQUANT_TAB: [[i8; 2]; 32] = [
573 [ 0, 0 ], [ 2, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -1, 1 ],
574 [ -1, 1 ], [ -1, 1 ], [ -1, 1 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ],
575 [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -2, 2 ], [ -3, 3 ], [ -3, 3 ], [ -3, 3 ],
576 [ -3, 3 ], [ -3, 3 ], [ -3, 3 ], [ -3, 3 ], [ -3, 3 ], [ -3, 2 ], [ -3, 1 ], [ -3,-5 ]
579 const RV34_QUANT_TAB: [u16; 32] = [
580 60, 67, 76, 85, 96, 108, 121, 136,
581 152, 171, 192, 216, 242, 272, 305, 341,
582 383, 432, 481, 544, 606, 683, 767, 854,
583 963, 1074, 1212, 1392, 1566, 1708, 1978, 2211
586 const RV34_CHROMA_QUANT_DC: [u8; 32] = [
587 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
588 14, 15, 15, 16, 17, 18, 18, 19, 20, 20, 21, 21, 22, 22, 23, 23
590 const RV34_CHROMA_QUANT_AC: [u8; 32] = [
591 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
592 16, 17, 17, 18, 19, 20, 20, 21, 22, 22, 23, 23, 24, 24, 25, 25
595 fn decode_dquant(br: &mut BitReader, q: u8) -> DecoderResult<u8> {
597 let diff = RV34_DQUANT_TAB[q as usize][br.read(1)? as usize];
598 let qp = (q as i8) + diff;
599 validate!((qp > 0) && (qp < 32));
602 let qp = br.read(5)? as u8;
652 fn new(ftype: FrameType) -> Self { Self { is_p: ftype == FrameType::P, hist: [MBType::Invalid; 4], count: 0 } }
653 fn add(&mut self, mbt: MBType) {
654 let mbt2 = match mbt {
655 MBType::MBSkip if self.is_p => MBType::MBP16x16,
656 MBType::MBSkip if !self.is_p => MBType::MBDirect,
659 self.hist[self.count] = mbt2;
662 fn get_mbtype(&self) -> MBType {
665 } else if self.count == 1 {
667 } else if self.count == 2 {
668 if self.hist[0].get_weight() <= self.hist[1].get_weight() {
674 let mut w: [usize; 12] = [0; 12];
675 for i in 0..self.count { w[self.hist[i].get_weight()] += 1; }
678 if w[i] == self.count { return MBTYPE_FROM_WEIGHT[i]; }
679 if (w[i] > w[nz_idx]) || (w[nz_idx] == 0) { nz_idx = i; }
682 MBTYPE_FROM_WEIGHT[nz_idx]
687 fn decode_mv(br: &mut BitReader) -> DecoderResult<MV> {
688 let x = br.read_code_signed(IntCodeType::Gamma)? as i16;
689 let y = br.read_code_signed(IntCodeType::Gamma)? as i16;
693 fn do_mc_16x16(dsp: &mut dyn RV34DSP, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, mb_y: usize, mv: MV, avg: bool) {
694 dsp.do_luma_mc (buf, prevbuf, mb_x * 16, mb_y * 16, mv, true, avg);
695 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8, mb_y * 8, 1, mv, true, avg);
696 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8, mb_y * 8, 2, mv, true, avg);
699 fn do_mc_8x8(dsp: &mut dyn RV34DSP, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, xoff: usize, mb_y: usize, yoff: usize, mv: MV, avg: bool) {
700 dsp.do_luma_mc (buf, prevbuf, mb_x * 16 + xoff * 8, mb_y * 16 + yoff * 8, mv, false, avg);
701 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8 + xoff * 4, mb_y * 8 + yoff * 4, 1, mv, false, avg);
702 dsp.do_chroma_mc(buf, prevbuf, mb_x * 8 + xoff * 4, mb_y * 8 + yoff * 4, 2, mv, false, avg);
705 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) {
707 let xoff = if comp == 0 { mb_x * 16 + xb * 8 } else { mb_x * 8 + xb * 4 };
708 let yoff = if comp == 0 { mb_y * 16 + yb * 8 } else { mb_y * 8 + yb * 4 };
709 let csize = if comp == 0 { size } else { size >> 1 };
710 let dstride = buf.get_stride(comp);
711 let doffset = buf.get_offset(comp) + xoff + yoff * dstride;
712 let data = buf.get_data_mut().unwrap();
713 let dst: &mut [u8] = data.as_mut_slice();
715 let sstride = avg_buf.get_stride(comp);
716 let soffset = avg_buf.get_offset(comp);
717 let data = avg_buf.get_data();
718 let src: &[u8] = data.as_slice();
720 if ratio1 == ratio2 {
721 cdsp.avg(dst, doffset, dstride, src, soffset, sstride, csize);
723 cdsp.weight(dst, doffset, dstride, src, soffset, sstride, ratio2, ratio1, csize);
728 pub struct RV34Decoder {
731 dsp: Box<dyn RV34DSP + Send>,
743 mbinfo: Vec<RV34MBInfo>,
744 avg_buf: NAVideoBufferRef<u8>,
749 pub fn new(is_rv30: bool, dsp: Box<dyn RV34DSP + Send>) -> Self {
750 let tmp_vinfo = NAVideoInfo::new(16, 16, false, YUV420_FORMAT);
751 let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
752 let vb = vt.get_vbuf();
753 let avg_buf = vb.unwrap();
756 coderead: RV34Codes::new(),
758 cdsp: RV34CommonDSP::new(),
759 ipbs: IPBShuffler::new(),
761 ref_mvi: MVInfo::new(),
764 last_ts: 0, next_ts: 0,
765 ratio1: 0, ratio2: 0,
771 fn decode_mb_header_intra(&mut self, bd: &mut dyn RV34BitstreamDecoder, br: &mut BitReader, is_i16: bool, im: &mut IntraModeState, q: u8, has_top: bool, has_dq: bool) -> DecoderResult<MBInfo> {
773 let imode = br.read(2)? as i8;
774 im.fill_block(imode);
775 Ok(MBInfo { mbtype: MBType::MBIntra16, skip_run: 0, dquant: false })
777 let dq = if !has_dq {
778 if !self.is_rv30 { !br.read_bool()? } else { false }
781 decode_dquant(br, q)?;
783 bd.decode_intra_pred(br, im.cache.data.as_mut_slice(), im.cache.xpos, im.cache.stride, has_top)?;
784 Ok(MBInfo { mbtype: MBType::MBIntra, skip_run: 0, dquant: dq })
787 fn decode_mb_header_inter(&mut self, bd: &mut dyn RV34BitstreamDecoder, br: &mut BitReader, ftype: FrameType, mbtype: MBType, im: &mut IntraModeState, q: u8, has_top: bool) -> DecoderResult<MBInfo> {
788 let hdr = bd.decode_inter_mb_hdr(br, ftype, mbtype)?;
789 validate!(hdr.mbtype != MBType::Invalid);
791 decode_dquant(br, q)?;
793 if hdr.mbtype.is_intra() {
794 return self.decode_mb_header_intra(bd, br, hdr.mbtype.is_16(), im, q, has_top, true);
799 fn decode_mb_intra(&mut self, sstate: &SState, imode: &IntraModeState, buf: &mut NAVideoBuffer<u8>, br: &mut BitReader, is_16: bool) -> DecoderResult<()> {
800 let mut cur_cbp = sstate.cbp;
802 let q_dc = RV34_QUANT_TAB[sstate.q_dc as usize];
803 let q_ac = RV34_QUANT_TAB[sstate.q as usize];
804 let luma_set = if is_16 { 2 } else { 1 };
805 let mut coeffs16: [i16; 16] = [0; 16];
807 let has_ac = self.coderead.decode_block(br, &mut coeffs16, 3, 0, q_dc, q_dc, q_ac)?;
809 self.cdsp.transform16(&mut coeffs16);
811 self.cdsp.transform16_dc(&mut coeffs16);
814 let stride = buf.get_stride(0);
815 let mut offset = buf.get_offset(0) + sstate.mb_x * 16 + sstate.mb_y * 16 * stride;
816 let data = buf.get_data_mut().unwrap();
817 let framebuf: &mut [u8] = data.as_mut_slice();
820 let im16 = imode.get_pred16_type(sstate.has_top, sstate.has_left);
821 self.cdsp.ipred16x16[im16 as usize](framebuf, offset, stride);
826 let mut coeffs: [i16; 16] = [0; 16];
827 let has_ac = if (cur_cbp & 1) != 0 {
828 self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?
833 coeffs[0] = coeffs16[x + y * 4];
835 let noright = (sstate.mb_x == sstate.mb_w - 1) && (x == 3);
836 let has_top = sstate.has_top || (y > 0);
837 let im = imode.get_pred4_type(x, y, sstate.has_top, sstate.has_left);
838 let topright: [u8; 4] = if (noright && sstate.has_top && y == 0) || (x == 3 && y > 0) {
839 let i = offset + x * 4 - stride;
840 [framebuf[i + 3], framebuf[i + 3], framebuf[i + 3], framebuf[i + 3]]
842 let i = offset + x * 4 - stride;
843 [framebuf[i + 4], framebuf[i + 5], framebuf[i + 6], framebuf[i + 7]]
847 self.cdsp.ipred4x4[im as usize](framebuf, offset + x*4, stride, &topright);
850 self.cdsp.transform(&mut coeffs);
852 self.cdsp.transform_dc(&mut coeffs);
854 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
857 offset += stride * 4;
860 let q_dc = RV34_QUANT_TAB[RV34_CHROMA_QUANT_DC[sstate.q as usize] as usize];
861 let q_ac = RV34_QUANT_TAB[RV34_CHROMA_QUANT_AC[sstate.q as usize] as usize];
864 let stride = buf.get_stride(comp);
865 let mut offset = buf.get_offset(comp) + sstate.mb_x * 8 + sstate.mb_y * 8 * stride;
866 let data = buf.get_data_mut().unwrap();
867 let framebuf: &mut [u8] = data.as_mut_slice();
869 let im8 = imode.get_pred8_type(sstate.has_top, sstate.has_left);
870 self.cdsp.ipred8x8[im8 as usize](framebuf, offset, stride);
874 let mut coeffs: [i16; 16] = [0; 16];
875 let has_ac = if (cur_cbp & 1) != 0 {
876 self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?
881 let noright = (sstate.mb_x == sstate.mb_w - 1) && (x == 1);
882 let has_top = sstate.has_top || (y > 0);
883 let im = imode.get_pred4_type_chroma(x, y, sstate.has_top, sstate.has_left);
884 let topright: [u8; 4] = if (noright && sstate.has_top && y == 0) || (x == 1 && y > 0) {
885 let i = offset + x * 4 - stride;
886 [framebuf[i + 3], framebuf[i + 3], framebuf[i + 3], framebuf[i + 3]]
888 let i = offset + x * 4 - stride;
889 [framebuf[i + 4], framebuf[i + 5], framebuf[i + 6], framebuf[i + 7]]
893 self.cdsp.ipred4x4[im as usize](framebuf, offset + x*4, stride, &topright);
896 self.cdsp.transform(&mut coeffs);
898 self.cdsp.transform_dc(&mut coeffs);
900 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
903 offset += stride * 4;
909 fn do_mc(&mut self, buf: &mut NAVideoBuffer<u8>, mbh: &MBInfo, sstate: &SState) {
910 let mb_x = sstate.mb_x;
911 let mb_y = sstate.mb_y;
913 MBType::MBP16x16 | MBType::MBP16x16Mix => {
914 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
915 let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
916 do_mc_16x16(self.dsp.as_mut(), buf, prevbuf, mb_x, mb_y, mv, false);
919 MBType::MBForward => {
920 if let Some(ref fwdbuf) = self.ipbs.get_b_fwdref() {
921 let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
922 do_mc_16x16(self.dsp.as_mut(), buf, fwdbuf, mb_x, mb_y, mv, false);
925 MBType::MBBackward => {
926 if let Some(ref bwdbuf) = self.ipbs.get_b_bwdref() {
927 let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, false);
928 do_mc_16x16(self.dsp.as_mut(), buf, bwdbuf, mb_x, mb_y, mv, false);
931 MBType::MBP8x8 | MBType::MBP8x16 | MBType::MBP16x8 => {
932 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
935 let mv = self.mvi.get_mv(mb_x, mb_y, x, y, true);
936 do_mc_8x8(self.dsp.as_mut(), buf, prevbuf, mb_x, x, mb_y, y, mv, false);
941 MBType::MBSkip if !self.is_b => {
942 if let Some(ref prevbuf) = self.ipbs.get_lastref() {
943 do_mc_16x16(self.dsp.as_mut(), buf, prevbuf, mb_x, mb_y, ZERO_MV, false);
946 MBType::MBSkip | MBType::MBDirect => {
947 if let (Some(ref fwdbuf), Some(ref bwdbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
950 let (mv_f, mv_b) = self.ref_mvi.get_mv(mb_x, mb_y, x, y, true).scale(sstate.trd, sstate.trb);
951 do_mc_8x8(self.dsp.as_mut(), buf, fwdbuf, mb_x, x, mb_y, y, mv_f, false);
952 do_mc_8x8(self.dsp.as_mut(), &mut self.avg_buf, bwdbuf, mb_x, x, mb_y, y, mv_b, true);
953 do_avg(&self.cdsp, buf, &self.avg_buf, mb_x, x, mb_y, y, 8, self.ratio1, self.ratio2);
959 if let (Some(ref fwdbuf), Some(ref bwdbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
960 let mv_f = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
961 let mv_b = self.mvi.get_mv(mb_x, mb_y, 0, 0, false);
962 do_mc_16x16(self.dsp.as_mut(), buf, fwdbuf, mb_x, mb_y, mv_f, false);
963 do_mc_16x16(self.dsp.as_mut(), &mut self.avg_buf, bwdbuf, mb_x, mb_y, mv_b, true);
964 do_avg(&self.cdsp, buf, &self.avg_buf, mb_x, 0, mb_y, 0, 16, self.ratio1, self.ratio2);
970 fn decode_mb_inter(&mut self, sstate: &SState, mbh: &MBInfo, buf: &mut NAVideoBuffer<u8>, br: &mut BitReader, is_16: bool) -> DecoderResult<()> {
971 self.do_mc(buf, mbh, sstate);
973 let mut cur_cbp = sstate.cbp;
976 let q_dc = RV34_QUANT_TAB[sstate.q_dc as usize];
977 let q_ac = RV34_QUANT_TAB[sstate.q as usize];
978 let luma_set = if is_16 { 2 } else { 0 };
979 let mut coeffs16: [i16; 16] = [0; 16];
981 let has_ac = self.coderead.decode_block(br, &mut coeffs16, 3, 0, q_dc, q_dc, q_ac)?;
983 self.cdsp.transform16(&mut coeffs16);
985 self.cdsp.transform16_dc(&mut coeffs16);
988 let stride = buf.get_stride(0);
989 let mut offset = buf.get_offset(0) + sstate.mb_x * 16 + sstate.mb_y * 16 * stride;
990 let data = buf.get_data_mut().unwrap();
991 let framebuf: &mut [u8] = data.as_mut_slice();
995 let mut coeffs: [i16; 16] = [0; 16];
996 let has_ac = if (cur_cbp & 1) != 0 {
997 self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?
1002 coeffs[0] = coeffs16[x + y * 4];
1005 self.cdsp.transform(&mut coeffs);
1007 self.cdsp.transform_dc(&mut coeffs);
1009 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
1012 offset += stride * 4;
1016 self.coderead.select_codes(false, sstate.q, sstate.set_idx, false);
1018 let q_dc = RV34_QUANT_TAB[RV34_CHROMA_QUANT_DC[sstate.q as usize] as usize];
1019 let q_ac = RV34_QUANT_TAB[RV34_CHROMA_QUANT_AC[sstate.q as usize] as usize];
1022 let stride = buf.get_stride(comp);
1023 let mut offset = buf.get_offset(comp) + sstate.mb_x * 8 + sstate.mb_y * 8 * stride;
1024 let data = buf.get_data_mut().unwrap();
1025 let framebuf: &mut [u8] = data.as_mut_slice();
1028 let mut coeffs: [i16; 16] = [0; 16];
1029 let has_ac = if (cur_cbp & 1) != 0 {
1030 self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?
1035 self.cdsp.transform(&mut coeffs);
1037 self.cdsp.transform_dc(&mut coeffs);
1039 self.cdsp.add_coeffs(framebuf, offset + x * 4, stride, &coeffs);
1042 offset += stride * 4;
1047 fn fill_deblock_flags(&self, sstate: &SState, mb_pos: usize, mbinfo: &mut [RV34MBInfo]) {
1048 let mbt = mbinfo[mb_pos].mbtype;
1049 let mut hmvmask = 0;
1050 let mut vmvmask = 0;
1054 let shift = x * 2 + y * 8;
1055 if ((x > 0) || (sstate.mb_x > 0)) && self.mvi.mv_gt_3(sstate.mb_x, sstate.mb_y, x, y, false) {
1056 vmvmask |= 0x11 << shift;
1058 if ((y > 0) || sstate.has_top) && self.mvi.mv_gt_3(sstate.mb_x, sstate.mb_y, x, y, true) {
1059 hmvmask |= 0x03 << shift;
1063 if !sstate.has_top { hmvmask &= !0x000F; }
1064 if sstate.mb_x == 0 { vmvmask &= !0x1111; }
1066 vmvmask |= (vmvmask & 0x4444) >> 1;
1067 hmvmask |= (hmvmask & 0x0F00) >> 4;
1068 if sstate.mb_x > 0 {
1069 mbinfo[mb_pos - 1].deblock |= (vmvmask & 0x1111) << 3;
1073 mbinfo[mb_pos - sstate.mb_w].deblock |= (hmvmask & 0xF) << 12;
1076 if mbt.is_intra_or_16() {
1077 mbinfo[mb_pos].deblock = 0xFFFF;
1078 mbinfo[mb_pos].cbp_c = 0xFF;
1080 mbinfo[mb_pos].deblock = (mbinfo[mb_pos].cbp as u16) | hmvmask | vmvmask;
1081 mbinfo[mb_pos].cbp_c = (mbinfo[mb_pos].cbp >> 16) as u8;
1085 #[allow(clippy::cognitive_complexity)]
1086 #[allow(clippy::collapsible_else_if)]
1087 pub fn parse_frame(&mut self, supp: &mut NADecoderSupport, src: &[u8], bd: &mut dyn RV34BitstreamDecoder) -> DecoderResult<(NABufferType, FrameType, u64)> {
1088 let mut slice_offs: Vec<usize> = Vec::new();
1089 parse_slice_offsets(src, &mut slice_offs)?;
1090 let ini_off = slice_offs.len() * 8 + 1;
1092 let mut br = BitReader::new(&src[ini_off..], BitReaderMode::BE);
1093 let hdr0 = decode_slice_header(&mut br, bd, 0, slice_offs.as_slice(), self.width, self.height)?;
1094 validate!((hdr0.width != 0) && (hdr0.height != 0));
1095 self.width = hdr0.width;
1096 self.height = hdr0.height;
1097 let mb_w = (hdr0.width + 15) >> 4;
1098 let mb_h = (hdr0.height + 15) >> 4;
1099 let mut mb_pos: usize = 0;
1100 let mut slice = hdr0;
1101 let mut slice_no: usize = 1;
1102 let is_intra = hdr0.ftype == FrameType::I;
1103 let mut skip_run: usize = 0;
1104 let mut imode = IntraModeState::new(mb_w);
1105 let mut q = hdr0.quant;
1107 let mut sstate = SState::new();
1108 let mut mbinfo: Vec<RV34MBInfo> = Vec::with_capacity(mb_w * mb_h);
1110 self.is_b = hdr0.ftype == FrameType::B;
1111 if hdr0.ftype != FrameType::B {
1112 self.last_ts = self.next_ts;
1113 self.next_ts = hdr0.pts;
1114 if self.last_ts > self.next_ts {
1115 self.base_ts += 1 << 13;
1120 if self.ipbs.get_lastref().is_none() {
1121 return Err(DecoderError::MissingReference);
1125 if self.ipbs.get_lastref().is_none() {
1126 return Err(DecoderError::MissingReference);
1128 if self.ipbs.get_nextref().is_none() {
1129 return Err(DecoderError::MissingReference);
1134 let ts_diff = (self.next_ts << 3).wrapping_sub(hdr0.pts << 3) >> 3;
1135 let ts = self.base_ts + (self.next_ts as u64) - (ts_diff as u64);
1136 sstate.trd = (self.next_ts << 3).wrapping_sub(self.last_ts << 3) >> 3;
1137 sstate.trb = (hdr0.pts << 3).wrapping_sub(self.last_ts << 3) >> 3;
1138 if sstate.trb != 0 {
1139 self.ratio1 = ((sstate.trb as u32) << 14) / (sstate.trd as u32);
1140 self.ratio2 = (((sstate.trd as u32) - (sstate.trb as u32)) << 14) / (sstate.trd as u32);
1142 self.ratio1 = 1 << 14 >> 1;
1143 self.ratio2 = 1 << 14 >> 1;
1145 //todo validate against ref frame
1147 let vinfo = NAVideoInfo::new(hdr0.width, hdr0.height, false, YUV420_FORMAT);
1148 let ret = supp.pool_u8.get_free();
1150 return Err(DecoderError::AllocError);
1152 let mut buf = ret.unwrap();
1153 if buf.get_info() != vinfo {
1155 supp.pool_u8.reset();
1156 supp.pool_u8.prealloc_video(vinfo, 4)?;
1157 let ret = supp.pool_u8.get_free();
1159 return Err(DecoderError::AllocError);
1165 sstate.has_top = false;
1168 sstate.set_idx = hdr0.set_idx;
1170 self.mvi.resize(mb_w, mb_h);
1171 for mb_y in 0..mb_h {
1173 sstate.has_left = false;
1174 for mb_x in 0..mb_w {
1176 if mb_pos == slice.end {
1177 slice = decode_slice_header(&mut br, bd, slice_no, &slice_offs, self.width, self.height)?;
1178 validate!(slice.fits(&hdr0));
1183 sstate.has_top = false;
1184 sstate.has_left = false;
1185 sstate.set_idx = slice.set_idx;
1187 sstate.has_top = (mb_pos - slice.start) >= mb_w;
1188 sstate.has_tl = sstate.has_top && (mb_x > 0) && (mb_pos > slice.start + mb_w);
1189 sstate.has_tr = (mb_x < mb_w - 1) && (mb_pos - slice.start >= mb_w - 1);
1190 imode.set_mb_x(mb_x);
1191 let mbh = if is_intra {
1192 let is_i16 = br.read_bool()?;
1193 self.decode_mb_header_intra(bd, &mut br, is_i16, &mut imode, q, sstate.has_top, false)?
1196 let mbtype = if self.is_rv30 {
1199 let mut hist = MBHist::new(hdr0.ftype);
1201 hist.add(mbinfo[mb_pos - mb_w].mbtype);
1202 if sstate.has_tr { hist.add(mbinfo[mb_pos - mb_w + 1].mbtype); }
1204 if sstate.has_left { hist.add(mbinfo[mb_pos - 1].mbtype); }
1205 if sstate.has_tl { hist.add(mbinfo[mb_pos - mb_w - 1].mbtype); }
1208 self.decode_mb_header_inter(bd, &mut br, hdr0.ftype, mbtype, &mut imode, q, sstate.has_top)?
1211 MBInfo { mbtype: MBType::MBSkip, skip_run: 0, dquant: false }
1214 if !mbh.mbtype.is_intra() {
1215 let mut mvs: [MV; 4] = [ZERO_MV; 4];
1216 for mv in mvs[..mbh.mbtype.get_num_mvs()].iter_mut() {
1217 *mv = decode_mv(&mut br)?;
1220 self.mvi.set_mb(mb_x, mb_y, mbh.mbtype, &self.ref_mvi, &mvs, &sstate);
1222 let (mv_f, mv_b) = bd.predict_b_mv(&sstate, &self.mvi, mbh.mbtype, &mvs, mbinfo.as_slice());
1223 self.mvi.fill(mb_x, mb_y, true, mv_f);
1224 self.mvi.fill(mb_x, mb_y, false, mv_b);
1228 let is_16 = (mbh.mbtype == MBType::MBIntra16) || (mbh.mbtype == MBType::MBP16x16Mix);
1229 if mbh.mbtype == MBType::MBSkip {
1231 if mbh.skip_run > 0 {
1232 skip_run = mbh.skip_run;
1235 self.coderead.select_codes(mbh.mbtype.is_intra(), q, slice.set_idx, is_16);
1236 if mbh.mbtype == MBType::MBP16x16Mix {
1237 self.coderead.select_codes(true, q, slice.set_idx, true);
1239 cbp = self.coderead.decode_cbp(&mut br)?;
1242 if is_intra || mbh.mbtype.is_intra() {
1243 sstate.q_dc = bd.quant_dc(true, q);
1244 self.decode_mb_intra(&sstate, &imode, &mut buf, &mut br, is_16)?;
1246 sstate.q_dc = bd.quant_dc(false, q);
1247 imode.fill_block(0);
1248 self.decode_mb_inter(&sstate, &mbh, &mut buf, &mut br, is_16)?;
1251 let mi = RV34MBInfo { cbp, q, mbtype: mbh.mbtype, deblock: 0, cbp_c: 0 };
1254 mbinfo[mb_pos].deblock = 0xFFFF;
1255 mbinfo[mb_pos].cbp_c = 0xFF;
1257 self.fill_deblock_flags(&sstate, mb_pos, &mut mbinfo);
1259 sstate.has_left = true;
1262 if hdr0.deblock && (mb_y >= 1) {
1263 self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_h, mb_y - 1);
1268 self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_h, mb_h - 1);
1271 self.ipbs.add_frame(buf.clone());
1272 mem::swap(&mut self.mvi, &mut self.ref_mvi);
1273 mem::swap(&mut self.mbinfo, &mut mbinfo);
1276 Ok((NABufferType::Video(buf), hdr0.ftype, ts))
1278 pub fn flush(&mut self) {