use nihav_core::formats::YUV420_FORMAT;
use nihav_core::frame::{NABufferType, NAVideoInfo, NAVideoBuffer, NAVideoBufferRef, FrameType, alloc_video_buffer};
-use nihav_core::codecs::{NADecoderSupport, MV, ZERO_MV, DecoderError, DecoderResult, IPBShuffler};
+use nihav_core::codecs::{NADecoderSupport, DecoderError, DecoderResult};
+use nihav_codec_support::codecs::{MV, ZERO_MV, IPBShuffler};
use nihav_core::io::bitreader::{BitReader,BitReaderMode};
use nihav_core::io::intcode::*;
-use nihav_core::data::GenericCache;
+use nihav_codec_support::data::GenericCache;
use std::mem;
use super::rv34codes::*;
}
}
-#[allow(dead_code)]
#[derive(Debug,Clone,Copy,PartialEq)]
pub enum MBType {
MBIntra,
}
}
pub fn is_fwd(self) -> bool {
- match self {
+ matches!(self,
MBType::MBP16x16 | MBType::MBP16x16Mix |
MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 |
- MBType::MBForward => true,
- _ => false,
- }
+ MBType::MBForward)
}
pub fn is_bwd(self) -> bool {
- match self {
- MBType::MBBidir | MBType::MBBackward => true,
- _ => false,
- }
+ matches!(self, MBType::MBBidir | MBType::MBBackward)
}
pub fn has_mv_dir(self, fwd: bool) -> bool {
match self {
}
}
pub fn is_nomv(self) -> bool {
- match self {
- MBType::MBIntra | MBType::MBIntra16 | MBType::MBSkip | MBType::MBDirect => true,
- _ => false,
- }
+ matches!(self, MBType::MBIntra | MBType::MBIntra16 | MBType::MBSkip | MBType::MBDirect)
}
/*pub fn is_16x16(self) -> bool {
match self {
}
fn reset(&mut self) {
let size = self.w * self.h;
- self.mv_f.truncate(0);
+ self.mv_f.clear();
self.mv_f.resize(size, ZERO_MV);
- self.mv_b.truncate(0);
+ self.mv_b.clear();
self.mv_b.resize(size, ZERO_MV);
- self.has_f.truncate(0);
+ self.has_f.clear();
self.has_f.resize(size >> 2, false);
- self.has_b.truncate(0);
+ self.has_b.clear();
self.has_b.resize(size >> 2, false);
}
+ #[allow(clippy::identity_op)]
fn fill(&mut self, mb_x: usize, mb_y: usize, fwd: bool, mv: MV) {
let idx = mb_x * 2 + mb_y * 2 * self.w;
if fwd {
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 {
self.pred_mv(mb_x * 2 + mb_y * 2 * self.w, fwd, has_top, has_left, has_tr, has_tl, true)
}
+ #[allow(clippy::collapsible_else_if)]
+ #[allow(clippy::identity_op)]
fn set_mb(&mut self, mb_x: usize, mb_y: usize, mbtype: MBType, ref_mvi: &Self, mvs: &[MV], sstate: &SState) {
let mb_idx = mb_x + mb_y * (self.w >> 1);
self.has_f[mb_idx] = mbtype.is_fwd();
for x in 0..2 {
let has_left = (x > 0) || sstate.has_left;
let has_tr = if y > 0 { x == 0 } else if x == 0 { sstate.has_top } else { sstate.has_tr };
- let has_tl;
- if y == 0 {
- has_tl = if x == 0 { sstate.has_tl } else { sstate.has_top };
- } else {
- has_tl = if x == 0 { sstate.has_left } else { true };
- }
+ let has_tl = if y == 0 {
+ if x == 0 { sstate.has_tl } else { sstate.has_top }
+ } else {
+ if x == 0 { sstate.has_left } else { true }
+ };
let pred_mv = self.pred_mv(idx8 + x, true, has_top, has_left, has_tr, has_tl, false);
let new_mv = mvs[x + y * 2] + pred_mv;
self.mv_f[idx8 + x] = new_mv;
let off = if vert { self.w } else { 1 };
let diffx = self.mv_f[idx].x - self.mv_f[idx - off].x;
let diffy = self.mv_f[idx].y - self.mv_f[idx - off].y;
- (diffx < -3) || (diffx > 3) || (diffy < -3) || (diffy > 3)
+ (diffx.abs() > 3) || (diffy.abs() > 3)
}
}
}
pub trait RV34DSP {
- fn loop_filter(&self, frame: &mut NAVideoBuffer<u8>, ftype: FrameType, mbinfo: &[RV34MBInfo], mb_w: usize, row: usize);
+ fn loop_filter(&self, frame: &mut NAVideoBuffer<u8>, ftype: FrameType, mbinfo: &[RV34MBInfo], mb_w: usize, mb_h: usize, row: usize);
fn do_luma_mc(&self, frame: &mut NAVideoBuffer<u8>, prev_frame: &NAVideoBuffer<u8>, x: usize, y: usize, mv: MV, use16: bool, avg: bool);
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);
}
fn parse_slice_offsets(src: &[u8], offsets: &mut Vec<usize>) -> DecoderResult<()> {
let num_slices = (src[0] as usize) + 1;
let ini_off = num_slices * 8 + 1;
- offsets.truncate(0);
+ offsets.clear();
if ini_off >= src.len() { return Err(DecoderError::ShortData); }
- let mut br = BitReader::new(&src[1..], ini_off - 1, BitReaderMode::BE);
+ let mut br = BitReader::new(&src[1..ini_off], BitReaderMode::BE);
for i in 0..num_slices {
br.skip(32)?;
Ok(())
}
-fn decode_slice_header(br: &mut BitReader, bd: &mut RV34BitstreamDecoder, slice_no: usize, slice_offs: &[usize], old_width: usize, old_height: usize) -> DecoderResult<RV34SliceHeader> {
+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> {
validate!(slice_no < slice_offs.len());
br.seek((slice_offs[slice_no] * 8) as u32)?;
let mut shdr = bd.decode_slice_header(br, old_width, old_height)?;
+ if ((shdr.width == 0) || (shdr.height == 0)) && (shdr.ftype != FrameType::I) {
+ return Err(DecoderError::MissingReference);
+ }
if slice_no < slice_offs.len() - 1 {
let cur_pos = br.tell() as u32;
br.seek((slice_offs[slice_no + 1] * 8) as u32)?;
- let nhdr = bd.decode_slice_header(br, shdr.width, shdr.height)?;
+ if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
+ validate!(nhdr.start > shdr.start);
+ shdr.end = nhdr.start;
+ } else if slice_no + 2 < slice_offs.len() {
+ br.seek((slice_offs[slice_no + 2] * 8) as u32)?;
+ if let Ok(nhdr) = bd.decode_slice_header(br, shdr.width, shdr.height) {
+ validate!(nhdr.start > shdr.start);
+ shdr.end = nhdr.start;
+ } else {
+ shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
+ }
+ } else {
+ shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
+ }
br.seek(cur_pos)?;
- validate!(nhdr.start > shdr.start);
- shdr.end = nhdr.start;
} else {
shdr.end = ((shdr.width + 15) >> 4) * ((shdr.height + 15) >> 4);
}
const RV34_SLICE_START_BITS: [u8; 6] = [ 6, 7, 9, 11, 13, 14 ];
pub fn get_slice_start_offset_bits(w: usize, h: usize) -> u8 {
+ if (w == 0) || (h == 0) {
+ return 0;
+ }
let mb_size = ((w + 15) >> 4) * ((h + 15) >> 4) - 1;
let mut idx: usize = 0;
while (idx < 5) && (RV34_MB_MAX_SIZES[idx] < mb_size) { idx += 1; }
Ok(MV{ x, y })
}
-fn do_mc_16x16(dsp: &Box<dyn RV34DSP>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, mb_y: usize, mv: MV, avg: bool) {
+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) {
dsp.do_luma_mc (buf, prevbuf, mb_x * 16, mb_y * 16, mv, true, avg);
dsp.do_chroma_mc(buf, prevbuf, mb_x * 8, mb_y * 8, 1, mv, true, avg);
dsp.do_chroma_mc(buf, prevbuf, mb_x * 8, mb_y * 8, 2, mv, true, avg);
}
-fn do_mc_8x8(dsp: &Box<dyn RV34DSP>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, xoff: usize, mb_y: usize, yoff: usize, mv: MV, avg: bool) {
+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) {
dsp.do_luma_mc (buf, prevbuf, mb_x * 16 + xoff * 8, mb_y * 16 + yoff * 8, mv, false, avg);
dsp.do_chroma_mc(buf, prevbuf, mb_x * 8 + xoff * 4, mb_y * 8 + yoff * 4, 1, mv, false, avg);
dsp.do_chroma_mc(buf, prevbuf, mb_x * 8 + xoff * 4, mb_y * 8 + yoff * 4, 2, mv, false, avg);
pub struct RV34Decoder {
is_rv30: bool,
coderead: RV34Codes,
- dsp: Box<dyn RV34DSP>,
+ dsp: Box<dyn RV34DSP + Send>,
cdsp: RV34CommonDSP,
width: usize,
height: usize,
}
impl RV34Decoder {
- pub fn new(is_rv30: bool, dsp: Box<dyn RV34DSP>) -> Self {
+ pub fn new(is_rv30: bool, dsp: Box<dyn RV34DSP + Send>) -> Self {
let tmp_vinfo = NAVideoInfo::new(16, 16, false, YUV420_FORMAT);
let vt = alloc_video_buffer(tmp_vinfo, 4).unwrap();
let vb = vt.get_vbuf();
base_ts: 0,
}
}
- 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> {
+ 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> {
if is_i16 {
let imode = br.read(2)? as i8;
im.fill_block(imode);
Ok(MBInfo { mbtype: MBType::MBIntra, skip_run: 0, dquant: dq })
}
}
- 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> {
+ 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> {
let hdr = bd.decode_inter_mb_hdr(br, ftype, mbtype)?;
validate!(hdr.mbtype != MBType::Invalid);
if hdr.dquant {
for y in 0..4 {
for x in 0..4 {
let mut coeffs: [i16; 16] = [0; 16];
- let has_ac;
- if (cur_cbp & 1) != 0 {
- has_ac = self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?;
- } else {
- has_ac = false;
- }
+ let has_ac = if (cur_cbp & 1) != 0 {
+ self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?
+ } else {
+ false
+ };
if is_16 {
coeffs[0] = coeffs16[x + y * 4];
} else {
for y in 0..2 {
for x in 0..2 {
let mut coeffs: [i16; 16] = [0; 16];
- let has_ac;
- if (cur_cbp & 1) != 0 {
- has_ac = self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?;
- } else {
- has_ac = false;
- }
+ let has_ac = if (cur_cbp & 1) != 0 {
+ self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?
+ } else {
+ false
+ };
if !is_16 {
let noright = (sstate.mb_x == sstate.mb_w - 1) && (x == 1);
let has_top = sstate.has_top || (y > 0);
MBType::MBP16x16 | MBType::MBP16x16Mix => {
if let Some(ref prevbuf) = self.ipbs.get_lastref() {
let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
- do_mc_16x16(&self.dsp, buf, prevbuf, mb_x, mb_y, mv, false);
+ do_mc_16x16(self.dsp.as_mut(), buf, prevbuf, mb_x, mb_y, mv, false);
}
},
MBType::MBForward => {
if let Some(ref fwdbuf) = self.ipbs.get_b_fwdref() {
let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
- do_mc_16x16(&self.dsp, buf, fwdbuf, mb_x, mb_y, mv, false);
+ do_mc_16x16(self.dsp.as_mut(), buf, fwdbuf, mb_x, mb_y, mv, false);
}
},
MBType::MBBackward => {
if let Some(ref bwdbuf) = self.ipbs.get_b_bwdref() {
let mv = self.mvi.get_mv(mb_x, mb_y, 0, 0, false);
- do_mc_16x16(&self.dsp, buf, bwdbuf, mb_x, mb_y, mv, false);
+ do_mc_16x16(self.dsp.as_mut(), buf, bwdbuf, mb_x, mb_y, mv, false);
}
},
MBType::MBP8x8 | MBType::MBP8x16 | MBType::MBP16x8 => {
for y in 0..2 {
for x in 0..2 {
let mv = self.mvi.get_mv(mb_x, mb_y, x, y, true);
- do_mc_8x8(&self.dsp, buf, prevbuf, mb_x, x, mb_y, y, mv, false);
+ do_mc_8x8(self.dsp.as_mut(), buf, prevbuf, mb_x, x, mb_y, y, mv, false);
}
}
}
},
MBType::MBSkip if !self.is_b => {
if let Some(ref prevbuf) = self.ipbs.get_lastref() {
- do_mc_16x16(&self.dsp, buf, prevbuf, mb_x, mb_y, ZERO_MV, false);
+ do_mc_16x16(self.dsp.as_mut(), buf, prevbuf, mb_x, mb_y, ZERO_MV, false);
}
},
MBType::MBSkip | MBType::MBDirect => {
for y in 0..2 {
for x in 0..2 {
let (mv_f, mv_b) = self.ref_mvi.get_mv(mb_x, mb_y, x, y, true).scale(sstate.trd, sstate.trb);
- do_mc_8x8(&self.dsp, buf, fwdbuf, mb_x, x, mb_y, y, mv_f, false);
- do_mc_8x8(&self.dsp, &mut self.avg_buf, bwdbuf, mb_x, x, mb_y, y, mv_b, true);
+ do_mc_8x8(self.dsp.as_mut(), buf, fwdbuf, mb_x, x, mb_y, y, mv_f, false);
+ do_mc_8x8(self.dsp.as_mut(), &mut self.avg_buf, bwdbuf, mb_x, x, mb_y, y, mv_b, true);
do_avg(&self.cdsp, buf, &self.avg_buf, mb_x, x, mb_y, y, 8, self.ratio1, self.ratio2);
}
}
if let (Some(ref fwdbuf), Some(ref bwdbuf)) = (self.ipbs.get_b_fwdref(), self.ipbs.get_b_bwdref()) {
let mv_f = self.mvi.get_mv(mb_x, mb_y, 0, 0, true);
let mv_b = self.mvi.get_mv(mb_x, mb_y, 0, 0, false);
- do_mc_16x16(&self.dsp, buf, fwdbuf, mb_x, mb_y, mv_f, false);
- do_mc_16x16(&self.dsp, &mut self.avg_buf, bwdbuf, mb_x, mb_y, mv_b, true);
+ do_mc_16x16(self.dsp.as_mut(), buf, fwdbuf, mb_x, mb_y, mv_f, false);
+ do_mc_16x16(self.dsp.as_mut(), &mut self.avg_buf, bwdbuf, mb_x, mb_y, mv_b, true);
do_avg(&self.cdsp, buf, &self.avg_buf, mb_x, 0, mb_y, 0, 16, self.ratio1, self.ratio2);
}
},
for y in 0..4 {
for x in 0..4 {
let mut coeffs: [i16; 16] = [0; 16];
- let has_ac;
- if (cur_cbp & 1) != 0 {
- has_ac = self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?;
- } else {
- has_ac = false;
- }
+ let has_ac = if (cur_cbp & 1) != 0 {
+ self.coderead.decode_block(br, &mut coeffs, luma_set, 0, q_ac, q_ac, q_ac)?
+ } else {
+ false
+ };
if is_16 {
coeffs[0] = coeffs16[x + y * 4];
}
for _ in 0..2 {
for x in 0..2 {
let mut coeffs: [i16; 16] = [0; 16];
- let has_ac;
- if (cur_cbp & 1) != 0 {
- has_ac = self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?;
- } else {
- has_ac = false;
- }
+ let has_ac = if (cur_cbp & 1) != 0 {
+ self.coderead.decode_block(br, &mut coeffs, chroma_set, 1, q_dc, q_ac, q_ac)?
+ } else {
+ false
+ };
if has_ac {
self.cdsp.transform(&mut coeffs);
} else {
}
Ok(())
}
- fn fill_deblock_flags(&self, sstate: &SState, mb_pos: usize, mbinfo: &mut Vec<RV34MBInfo>) {
+ fn fill_deblock_flags(&self, sstate: &SState, mb_pos: usize, mbinfo: &mut [RV34MBInfo]) {
let mbt = mbinfo[mb_pos].mbtype;
let mut hmvmask = 0;
let mut vmvmask = 0;
}
}
- pub fn parse_frame(&mut self, supp: &mut NADecoderSupport, src: &[u8], bd: &mut RV34BitstreamDecoder) -> DecoderResult<(NABufferType, FrameType, u64)> {
+ #[allow(clippy::cognitive_complexity)]
+ #[allow(clippy::collapsible_else_if)]
+ pub fn parse_frame(&mut self, supp: &mut NADecoderSupport, src: &[u8], bd: &mut dyn RV34BitstreamDecoder) -> DecoderResult<(NABufferType, FrameType, u64)> {
let mut slice_offs: Vec<usize> = Vec::new();
parse_slice_offsets(src, &mut slice_offs)?;
let ini_off = slice_offs.len() * 8 + 1;
- let mut br = BitReader::new(&src[ini_off..], src.len() - ini_off, BitReaderMode::BE);
+ let mut br = BitReader::new(&src[ini_off..], BitReaderMode::BE);
let hdr0 = decode_slice_header(&mut br, bd, 0, slice_offs.as_slice(), self.width, self.height)?;
validate!((hdr0.width != 0) && (hdr0.height != 0));
self.width = hdr0.width;
self.base_ts += 1 << 13;
}
}
+ match hdr0.ftype {
+ FrameType::P => {
+ if self.ipbs.get_lastref().is_none() {
+ return Err(DecoderError::MissingReference);
+ }
+ },
+ FrameType::B => {
+ if self.ipbs.get_lastref().is_none() {
+ return Err(DecoderError::MissingReference);
+ }
+ if self.ipbs.get_nextref().is_none() {
+ return Err(DecoderError::MissingReference);
+ }
+ },
+ _ => {},
+ };
let ts_diff = (self.next_ts << 3).wrapping_sub(hdr0.pts << 3) >> 3;
let ts = self.base_ts + (self.next_ts as u64) - (ts_diff as u64);
sstate.trd = (self.next_ts << 3).wrapping_sub(self.last_ts << 3) >> 3;
self.decode_mb_header_intra(bd, &mut br, is_i16, &mut imode, q, sstate.has_top, false)?
} else {
if skip_run == 0 {
- let mbtype;
- if self.is_rv30 {
- mbtype = MBType::Invalid;
- } else {
- let mut hist = MBHist::new(hdr0.ftype);
- if sstate.has_top {
- hist.add(mbinfo[mb_pos - mb_w].mbtype);
- if sstate.has_tr { hist.add(mbinfo[mb_pos - mb_w + 1].mbtype); }
- }
- if sstate.has_left { hist.add(mbinfo[mb_pos - 1].mbtype); }
- if sstate.has_tl { hist.add(mbinfo[mb_pos - mb_w - 1].mbtype); }
- mbtype = hist.get_mbtype();
- }
+ let mbtype = if self.is_rv30 {
+ MBType::Invalid
+ } else {
+ let mut hist = MBHist::new(hdr0.ftype);
+ if sstate.has_top {
+ hist.add(mbinfo[mb_pos - mb_w].mbtype);
+ if sstate.has_tr { hist.add(mbinfo[mb_pos - mb_w + 1].mbtype); }
+ }
+ if sstate.has_left { hist.add(mbinfo[mb_pos - 1].mbtype); }
+ if sstate.has_tl { hist.add(mbinfo[mb_pos - mb_w - 1].mbtype); }
+ hist.get_mbtype()
+ };
self.decode_mb_header_inter(bd, &mut br, hdr0.ftype, mbtype, &mut imode, q, sstate.has_top)?
} else {
skip_run -= 1;
};
if !mbh.mbtype.is_intra() {
let mut mvs: [MV; 4] = [ZERO_MV; 4];
- for i in 0..mbh.mbtype.get_num_mvs() {
- mvs[i] = decode_mv(&mut br)?;
+ for mv in mvs[..mbh.mbtype.get_num_mvs()].iter_mut() {
+ *mv = decode_mv(&mut br)?;
}
if !self.is_b {
self.mvi.set_mb(mb_x, mb_y, mbh.mbtype, &self.ref_mvi, &mvs, &sstate);
sstate.q_dc = bd.quant_dc(true, q);
self.decode_mb_intra(&sstate, &imode, &mut buf, &mut br, is_16)?;
} else {
+ sstate.q_dc = bd.quant_dc(false, q);
imode.fill_block(0);
self.decode_mb_inter(&sstate, &mbh, &mut buf, &mut br, is_16)?;
}
mb_pos += 1;
}
if hdr0.deblock && (mb_y >= 1) {
- self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_y - 1);
+ self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_h, mb_y - 1);
}
imode.update();
}
if hdr0.deblock {
- self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_h - 1);
+ self.dsp.loop_filter(&mut buf, hdr0.ftype, &mbinfo, mb_w, mb_h, mb_h - 1);
}
if !self.is_b {
self.ipbs.add_frame(buf.clone());