use nihav_core::formats::YUV420_FORMAT;
use nihav_core::frame::{NABufferType, NAVideoInfo, NAVideoBuffer, NAVideoBufferRef, FrameType, alloc_video_buffer};
-use nihav_core::codecs::{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_codec_support::data::GenericCache;
use std::mem;
use super::rv34codes::*;
use super::rv34dsp::*;
-pub struct GenericCache<T: Copy> {
- pub height: usize,
- pub stride: usize,
- pub xpos: usize,
- pub data: Vec<T>,
- pub default: T,
-}
-
-impl<T:Copy> GenericCache<T> {
- pub fn new(height: usize, stride: usize, default: T) -> Self {
- let mut ret = Self {
- stride: stride,
- height: height,
- xpos: 0,
- data: Vec::with_capacity((height + 1) * stride),
- default: default,
- };
- ret.reset();
- ret
- }
- fn full_size(&self) -> usize { self.stride * (self.height + 1) }
- pub fn reset(&mut self) {
- self.data.truncate(0);
- let size = self.full_size();
- self.data.resize(size, self.default);
- self.xpos = self.stride + 1;
- }
- pub fn update_row(&mut self) {
- for i in 0..self.stride {
- self.data[i] = self.data[self.height * self.stride + i];
- }
- self.data.truncate(self.stride);
- let size = self.full_size();
- self.data.resize(size, self.default);
- self.xpos = self.stride + 1;
- }
-}
-
trait RV34MVScale {
fn scale(&self, trd: u16, trb: u16) -> (MV, MV);
}
}
impl MBType {
- pub fn is_intra(&self) -> bool {
- (*self == MBType::MBIntra) || (*self == MBType::MBIntra16)
+ pub fn is_intra(self) -> bool {
+ (self == MBType::MBIntra) || (self == MBType::MBIntra16)
}
- pub fn is_16(&self) -> bool {
- (*self == MBType::MBIntra16) || (*self == MBType::MBP16x16Mix)
+ pub fn is_16(self) -> bool {
+ (self == MBType::MBIntra16) || (self == MBType::MBP16x16Mix)
}
- pub fn is_intra_or_16(&self) -> bool {
+ pub fn is_intra_or_16(self) -> bool {
self.is_intra() || self.is_16()
}
- pub fn get_num_mvs(&self) -> usize {
- match *self {
+ pub fn get_num_mvs(self) -> usize {
+ match self {
MBType::MBIntra | MBType::MBIntra16 |
MBType::MBSkip | MBType::MBDirect => 0,
MBType::MBP16x16 | MBType::MBP16x16Mix |
MBType::Invalid => unreachable!(),
}
}
- pub fn is_fwd(&self) -> bool {
- match *self {
+ pub fn is_fwd(self) -> bool {
+ match self {
MBType::MBP16x16 | MBType::MBP16x16Mix |
MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 |
MBType::MBForward => true,
_ => false,
}
}
- pub fn is_bwd(&self) -> bool {
- match *self {
+ pub fn is_bwd(self) -> bool {
+ match self {
MBType::MBBidir | MBType::MBBackward => true,
_ => false,
}
}
- pub fn has_mv_dir(&self, fwd: bool) -> bool {
- match *self {
+ pub fn has_mv_dir(self, fwd: bool) -> bool {
+ match self {
MBType::MBBidir => true,
MBType::MBForward if fwd => true,
MBType::MBBackward if !fwd => true,
_ => false,
}
}
- pub fn is_nomv(&self) -> bool {
- match *self {
+ pub fn is_nomv(self) -> bool {
+ match self {
MBType::MBIntra | MBType::MBIntra16 | MBType::MBSkip | MBType::MBDirect => true,
_ => false,
}
}
- /*pub fn is_16x16(&self) -> bool {
- match *self {
+ /*pub fn is_16x16(self) -> bool {
+ match self {
MBType::MBP16x8 | MBType::MBP8x16 | MBType::MBP8x8 => false,
_ => true,
}
}*/
- fn get_weight(&self) -> usize {
- match *self {
+ fn get_weight(self) -> usize {
+ match self {
MBType::MBIntra => 0,
MBType::MBIntra16 => 1,
MBType::MBSkip => unreachable!(),
fn decode_intra_pred(&mut self, br: &mut BitReader, types: &mut [i8], pos: usize, tstride: usize, has_top: bool) -> DecoderResult<()>;
fn quant_dc(&self, is_intra: bool, q: u8) -> u8;
fn decode_inter_mb_hdr(&mut self, br: &mut BitReader, ftype: FrameType, mbtype: MBType) -> DecoderResult<MBInfo>;
- fn predict_b_mv(&self, sstate: &SState, mvi: &MVInfo, mbtype: MBType, mvs: &[MV], mbinfo: &Vec<RV34MBInfo>) -> (MV, MV);
+ fn predict_b_mv(&self, sstate: &SState, mvi: &MVInfo, mbtype: MBType, mvs: &[MV], mbinfo: &[RV34MBInfo]) -> (MV, MV);
}
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);
}
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: &Vec<usize>, old_width: usize, old_height: usize) -> DecoderResult<RV34SliceHeader> {
+fn decode_slice_header(br: &mut BitReader, bd: &mut 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; }
fn decode_mv(br: &mut BitReader) -> DecoderResult<MV> {
let x = br.read_code_signed(IntCodeType::Gamma)? as i16;
let y = br.read_code_signed(IntCodeType::Gamma)? as i16;
- Ok(MV{ x: x, y: y })
+ Ok(MV{ x, y })
}
-fn do_mc_16x16(dsp: &Box<RV34DSP>, buf: &mut NAVideoBuffer<u8>, prevbuf: &NAVideoBuffer<u8>, mb_x: usize, mb_y: usize, mv: MV, avg: bool) {
+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) {
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<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: &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) {
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<RV34DSP>,
+ dsp: Box<dyn RV34DSP + Send>,
cdsp: RV34CommonDSP,
width: usize,
height: usize,
}
impl RV34Decoder {
- pub fn new(is_rv30: bool, dsp: Box<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();
let avg_buf = vb.unwrap();
RV34Decoder {
- is_rv30: is_rv30,
+ is_rv30,
coderead: RV34Codes::new(),
- dsp: dsp,
+ dsp,
cdsp: RV34CommonDSP::new(),
ipbs: IPBShuffler::new(),
mvi: MVInfo::new(),
last_ts: 0, next_ts: 0,
ratio1: 0, ratio2: 0,
is_b: false,
- avg_buf: avg_buf,
+ avg_buf,
base_ts: 0,
}
}
if is_i16 {
let imode = br.read(2)? as i8;
im.fill_block(imode);
- return Ok(MBInfo { mbtype: MBType::MBIntra16, skip_run: 0, dquant: false });
+ Ok(MBInfo { mbtype: MBType::MBIntra16, skip_run: 0, dquant: false })
} else {
let dq = if !has_dq {
if !self.is_rv30 { !br.read_bool()? } else { false }
decode_dquant(br, q)?;
}
bd.decode_intra_pred(br, im.cache.data.as_mut_slice(), im.cache.xpos, im.cache.stride, has_top)?;
- return Ok(MBInfo { mbtype: MBType::MBIntra, skip_run: 0, dquant: dq });
+ 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> {
if hdr.mbtype.is_intra() {
return self.decode_mb_header_intra(bd, br, hdr.mbtype.is_16(), im, q, has_top, true);
}
- return Ok(hdr);
+ Ok(hdr)
}
fn decode_mb_intra(&mut self, sstate: &SState, imode: &IntraModeState, buf: &mut NAVideoBuffer<u8>, br: &mut BitReader, is_16: bool) -> DecoderResult<()> {
}
}
- pub fn parse_frame(&mut self, src: &[u8], bd: &mut RV34BitstreamDecoder) -> DecoderResult<(NABufferType, FrameType, u64)> {
+ pub fn parse_frame(&mut self, supp: &mut NADecoderSupport, src: &[u8], bd: &mut 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 hdr0 = decode_slice_header(&mut br, bd, 0, &slice_offs, self.width, self.height)?;
+ 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.height = hdr0.height;
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;
//todo validate against ref frame
let vinfo = NAVideoInfo::new(hdr0.width, hdr0.height, false, YUV420_FORMAT);
- let bufret = alloc_video_buffer(vinfo, 4);
- if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
- let bufinfo = bufret.unwrap();
- let mut buf = bufinfo.get_vbuf().unwrap();
+ let ret = supp.pool_u8.get_free();
+ if ret.is_none() {
+ return Err(DecoderError::AllocError);
+ }
+ let mut buf = ret.unwrap();
+ if buf.get_info() != vinfo {
+ self.ipbs.clear();
+ supp.pool_u8.reset();
+ supp.pool_u8.prealloc_video(vinfo, 4)?;
+ let ret = supp.pool_u8.get_free();
+ if ret.is_none() {
+ return Err(DecoderError::AllocError);
+ }
+ buf = ret.unwrap();
+ }
sstate.q = q;
sstate.has_top = false;
if !self.is_b {
self.mvi.set_mb(mb_x, mb_y, mbh.mbtype, &self.ref_mvi, &mvs, &sstate);
} else {
- let (mv_f, mv_b) = bd.predict_b_mv(&sstate, &self.mvi, mbh.mbtype, &mvs, &mbinfo);
+ let (mv_f, mv_b) = bd.predict_b_mv(&sstate, &self.mvi, mbh.mbtype, &mvs, mbinfo.as_slice());
self.mvi.fill(mb_x, mb_y, true, mv_f);
self.mvi.fill(mb_x, mb_y, false, mv_b);
}
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)?;
}
- let mi = RV34MBInfo { cbp: cbp, q: q, mbtype: mbh.mbtype, deblock: 0, cbp_c: 0 };
+ let mi = RV34MBInfo { cbp, q, mbtype: mbh.mbtype, deblock: 0, cbp_c: 0 };
mbinfo.push(mi);
if is_intra {
mbinfo[mb_pos].deblock = 0xFFFF;
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);
+ self.ipbs.add_frame(buf.clone());
mem::swap(&mut self.mvi, &mut self.ref_mvi);
mem::swap(&mut self.mbinfo, &mut mbinfo);
}
- Ok((bufinfo, hdr0.ftype, ts))
+ Ok((NABufferType::Video(buf), hdr0.ftype, ts))
+ }
+ pub fn flush(&mut self) {
+ self.ipbs.clear();
}
}