umv: bool,
pb: Option<PBInfo>,
ts: u8,
+ deblock: bool,
}
#[allow(dead_code)]
impl PicInfo {
- pub fn new(w: usize, h: usize, mode: Type, quant: u8, apm: bool, umv: bool, ts: u8, pb: Option<PBInfo>) -> Self {
- PicInfo{ w: w, h: h, mode: mode, quant: quant, apm: apm, umv: umv, ts: ts, pb: pb }
+ pub fn new(w: usize, h: usize, mode: Type, quant: u8, apm: bool, umv: bool, ts: u8, pb: Option<PBInfo>, deblock: bool) -> Self {
+ PicInfo{ w: w, h: h, mode: mode, quant: quant, apm: apm, umv: umv, ts: ts, pb: pb, deblock: deblock }
}
pub fn get_width(&self) -> usize { self.w }
pub fn get_height(&self) -> usize { self.h }
fn decode_block_header(&mut self, pinfo: &PicInfo, sinfo: &Slice) -> DecoderResult<BlockInfo>;
fn decode_block_intra(&mut self, info: &BlockInfo, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>;
fn decode_block_inter(&mut self, info: &BlockInfo, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>;
- fn calc_mv(&mut self, vec: MV);
fn is_slice_end(&mut self) -> bool;
+
+ fn filter_row(&mut self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo);
}
#[allow(dead_code)]
}
}
+#[allow(dead_code)]
+pub struct CBPInfo {
+ cbp: Vec<u8>,
+ q: Vec<u8>,
+ mb_w: usize,
+}
+
+impl CBPInfo {
+ fn new() -> Self { CBPInfo{ cbp: Vec::new(), q: Vec::new(), mb_w: 0 } }
+ fn reset(&mut self, mb_w: usize) {
+ self.mb_w = mb_w;
+ self.cbp.truncate(0);
+ self.cbp.resize(self.mb_w * 2, 0);
+ self.q.truncate(0);
+ self.q.resize(self.mb_w * 2, 0);
+ }
+ fn update_row(&mut self) {
+ for i in 0..self.mb_w {
+ self.cbp[i] = self.cbp[self.mb_w + i];
+ self.q[i] = self.q[self.mb_w + i];
+ }
+ }
+ fn set_cbp(&mut self, mb_x: usize, cbp: u8) {
+ self.cbp[self.mb_w + mb_x] = cbp;
+ }
+ fn set_q(&mut self, mb_x: usize, q: u8) {
+ self.q[self.mb_w + mb_x] = q;
+ }
+ pub fn get_q(&self, mb_x: usize) -> u8 { self.q[mb_x] }
+ pub fn is_coded(&self, mb_x: usize, blk_no: usize) -> bool {
+ (self.cbp[self.mb_w + mb_x] & (1 << (5 - blk_no))) != 0
+ }
+ pub fn is_coded_top(&self, mb_x: usize, blk_no: usize) -> bool {
+ let cbp = self.cbp[self.mb_w + mb_x];
+ let cbp_top = self.cbp[mb_x];
+ match blk_no {
+ 0 => { (cbp_top & 0b001000) != 0 },
+ 1 => { (cbp_top & 0b000100) != 0 },
+ 2 => { (cbp & 0b100000) != 0 },
+ 3 => { (cbp & 0b010000) != 0 },
+ 4 => { (cbp_top & 0b000010) != 0 },
+ _ => { (cbp_top & 0b000001) != 0 },
+ }
+ }
+}
+
fn copy_blocks(dst: &mut NAVideoBuffer<u8>, src: &NAVideoBuffer<u8>, xpos: usize, ypos: usize, w: usize, h: usize, mv: MV) {
let srcx = ((mv.x >> 1) as isize) + (xpos as isize);
let srcy = ((mv.y >> 1) as isize) + (ypos as isize);
pub fn parse_frame(&mut self, bd: &mut BlockDecoder) -> DecoderResult<NABufferType> {
let pinfo = bd.decode_pichdr()?;
let mut mvi = MVInfo::new();
+ let mut cbpi = CBPInfo::new();
//todo handle res change
self.w = pinfo.w;
}
mem::swap(&mut self.cur_frm, &mut self.prev_frm);
-// if self.ftype == Type::I && !pinfo.is_pb() { self.prev_frm = None; }
let tsdiff = pinfo.ts.wrapping_sub(self.last_ts);
let bsdiff = if pinfo.is_pb() { pinfo.get_pbinfo().get_trb() } else { 0 };
let mut slice = Slice::get_default_slice(&pinfo);
mvi.reset(self.mb_w, 0, pinfo.get_umv());
+ cbpi.reset(self.mb_w);
let mut blk: [[i16; 64]; 6] = [[0; 64]; 6];
for mb_y in 0..self.mb_h {
//println!("new slice @{}.{}!",mb_x,mb_y);
slice = bd.decode_slice_header(&pinfo)?;
mvi.reset(self.mb_w, mb_x, pinfo.get_umv());
+ //cbpi.reset(self.mb_w);
}
let binfo = bd.decode_block_header(&pinfo, &slice)?;
let cbp = binfo.get_cbp();
//println!("mb {}.{} CBP {:X} type {:?}, {} mvs skip {}", mb_x,mb_y, cbp, binfo.get_mode(), binfo.get_num_mvs(),binfo.is_skipped());
+ cbpi.set_cbp(mb_x, cbp);
+ cbpi.set_q(mb_x, binfo.get_q());
if binfo.is_intra() {
for i in 0..6 {
bd.decode_block_intra(&binfo, binfo.get_q(), i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?;
self.b_data.push(b_mb);
}
}
+ if pinfo.deblock {
+ bd.filter_row(&mut buf, mb_y, self.mb_w, &cbpi);
+ }
mvi.update_row();
+ cbpi.update_row();
}
+
self.cur_frm = Some(buf);
self.last_ts = pinfo.ts;
//println!("unpacked all");
fn recon_b_frame(b_buf: &mut NAVideoBuffer<u8>, bck_buf: &NAVideoBuffer<u8>, fwd_buf: &NAVideoBuffer<u8>,
mb_w: usize, mb_h: usize, b_data: &Vec<BMB>) {
+ let mut cbpi = CBPInfo::new();
let mut cur_mb = 0;
+ cbpi.reset(mb_w);
for mb_y in 0..mb_h {
for mb_x in 0..mb_w {
let num_mv = b_data[cur_mb].num_mv;
let is_fwd = b_data[cur_mb].fwd;
- if num_mv == 0 {
- copy_blocks(b_buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV);
- if !is_fwd {
- avg_blocks(b_buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV);
- }
- } else if num_mv == 1 {
+ let cbp = b_data[cur_mb].cbp;
+ cbpi.set_cbp(mb_x, cbp);
+ if num_mv == 1 {
copy_blocks(b_buf, bck_buf, mb_x * 16, mb_y * 16, 16, 16, b_data[cur_mb].mv_f[0]);
if !is_fwd {
avg_blocks(b_buf, fwd_buf, mb_x * 16, mb_y * 16, 16, 16, b_data[cur_mb].mv_b[0]);
}
}
}
- if num_mv != 0 && b_data[cur_mb].cbp != 0 {
+ if cbp != 0 {
blockdsp::add_blocks(b_buf, mb_x, mb_y, &b_data[cur_mb].blk);
}
cur_mb += 1;
}
+ cbpi.update_row();
}
}
br.read(1)?; // syntax arithmetic coding
let apm = br.read_bool()?;
self.is_pb = br.read_bool()?;
+ let deblock;
if sfmt == 0b111 {
sfmt = br.read(3)?;
validate!((sfmt != 0b000) && (sfmt != 0b111));
br.read(2)?; // unknown flags
- let deblock = br.read_bool()?;
+ deblock = br.read_bool()?;
br.read(1)?; // unknown flag
let pbplus = br.read_bool()?;
br.read(5)?; // unknown flags
let marker = br.read(5)?;
validate!(marker == 1);
+ } else {
+ deblock = false;
}
let w; let h;
if sfmt == 0b110 {
self.mb_w = (w + 15) >> 4;
let ftype = if is_intra { Type::I } else { Type::P };
- let picinfo = PicInfo::new(w, h, ftype, quant as u8, apm, umv, tr, pbinfo);
+ let picinfo = PicInfo::new(w, h, ftype, quant as u8, apm, umv, tr, pbinfo, deblock);
Ok(picinfo)
}
self.decode_block(quant, false, coded, blk)
}
-#[allow(unused_variables)]
- fn calc_mv(&mut self, vec: MV) {}
-
fn is_slice_end(&mut self) -> bool { self.br.peek(16) == 0 }
+
+ fn filter_row(&mut self, buf: &mut NAVideoBuffer<u8>, mb_y: usize, mb_w: usize, cbpi: &CBPInfo) {
+ let stride = buf.get_stride(0);
+ let mut off = buf.get_offset(0) + mb_y * 16 * stride;
+ for mb_x in 0..mb_w {
+ let coff = off;
+ let coded0 = cbpi.is_coded(mb_x, 0);
+ let coded1 = cbpi.is_coded(mb_x, 1);
+ let q = cbpi.get_q(mb_w + mb_x);
+ if mb_y != 0 {
+ if coded0 && cbpi.is_coded_top(mb_x, 0) { deblock_hor(buf, 0, q, coff); }
+ if coded1 && cbpi.is_coded_top(mb_x, 1) { deblock_hor(buf, 0, q, coff + 8); }
+ }
+ let coff = off + 8 * stride;
+ if cbpi.is_coded(mb_x, 2) && coded0 { deblock_hor(buf, 0, q, coff); }
+ if cbpi.is_coded(mb_x, 3) && coded1 { deblock_hor(buf, 0, q, coff + 8); }
+ off += 16;
+ }
+ let mut leftt = false;
+ let mut leftc = false;
+ let mut off = buf.get_offset(0) + mb_y * 16 * stride;
+ for mb_x in 0..mb_w {
+ let ctop0 = cbpi.is_coded_top(mb_x, 0);
+ let ctop1 = cbpi.is_coded_top(mb_x, 0);
+ let ccur0 = cbpi.is_coded(mb_x, 0);
+ let ccur1 = cbpi.is_coded(mb_x, 1);
+ let q = cbpi.get_q(mb_w + mb_x);
+ if mb_y != 0 {
+ let coff = off - 8 * stride;
+ let qtop = cbpi.get_q(mb_x);
+ if leftt && ctop0 { deblock_ver(buf, 0, qtop, coff); }
+ if ctop0 && ctop1 { deblock_ver(buf, 0, qtop, coff + 8); }
+ }
+ if leftc && ccur0 { deblock_ver(buf, 0, q, off); }
+ if ccur0 && ccur1 { deblock_ver(buf, 0, q, off + 8); }
+ leftt = ctop1;
+ leftc = ccur1;
+ off += 16;
+ }
+ let strideu = buf.get_stride(1);
+ let stridev = buf.get_stride(2);
+ let offu = buf.get_offset(1) + mb_y * 8 * strideu;
+ let offv = buf.get_offset(2) + mb_y * 8 * stridev;
+ if mb_y != 0 {
+ for mb_x in 0..mb_w {
+ let ctu = cbpi.is_coded_top(mb_x, 4);
+ let ccu = cbpi.is_coded(mb_x, 4);
+ let ctv = cbpi.is_coded_top(mb_x, 5);
+ let ccv = cbpi.is_coded(mb_x, 5);
+ let q = cbpi.get_q(mb_w + mb_x);
+ if ctu && ccu { deblock_hor(buf, 1, q, offu + mb_x * 8); }
+ if ctv && ccv { deblock_hor(buf, 2, q, offv + mb_x * 8); }
+ }
+ let mut leftu = false;
+ let mut leftv = false;
+ let offu = buf.get_offset(1) + (mb_y - 1) * 8 * strideu;
+ let offv = buf.get_offset(2) + (mb_y - 1) * 8 * stridev;
+ for mb_x in 0..mb_w {
+ let ctu = cbpi.is_coded_top(mb_x, 4);
+ let ctv = cbpi.is_coded_top(mb_x, 5);
+ let qt = cbpi.get_q(mb_x);
+ if leftu && ctu { deblock_ver(buf, 1, qt, offu + mb_x * 8); }
+ if leftv && ctv { deblock_ver(buf, 2, qt, offv + mb_x * 8); }
+ leftu = ctu;
+ leftv = ctv;
+ }
+ }
+ }
+}
+
+fn deblock_hor(buf: &mut NAVideoBuffer<u8>, comp: usize, q: u8, off: usize) {
+ let stride = buf.get_stride(comp);
+ let mut dptr = buf.get_data_mut();
+ let mut buf = dptr.as_mut_slice();
+ for x in 0..8 {
+ let a = buf[off - 2 * stride + x] as i16;
+ let b = buf[off - 1 * stride + x] as i16;
+ let c = buf[off + 0 * stride + x] as i16;
+ let d = buf[off + 1 * stride + x] as i16;
+ let diff = ((a - d) * 3 + (c - b) * 8) >> 4;
+ if (diff != 0) && (diff >= -32) && (diff < 32) {
+ let d0 = diff.abs() * 2 - (q as i16);
+ let d1 = if d0 < 0 { 0 } else { d0 };
+ let d2 = diff.abs() - d1;
+ let d3 = if d2 < 0 { 0 } else { d2 };
+
+ let delta = if diff < 0 { -d3 } else { d3 };
+
+ let b1 = b + delta;
+ if b1 < 0 { buf[off - 1 * stride + x] = 0; }
+ else if b1 > 255 { buf[off - 1 * stride + x] = 0xFF; }
+ else { buf[off - 1 * stride + x] = b1 as u8; }
+ let c1 = c - delta;
+ if c1 < 0 { buf[off + x] = 0; }
+ else if c1 > 255 { buf[off + x] = 0xFF; }
+ else { buf[off + x] = c1 as u8; }
+ }
+ }
+}
+
+fn deblock_ver(buf: &mut NAVideoBuffer<u8>, comp: usize, q: u8, off: usize) {
+ let stride = buf.get_stride(comp);
+ let mut dptr = buf.get_data_mut();
+ let mut buf = dptr.as_mut_slice();
+ for y in 0..8 {
+ let a = buf[off - 2 + y * stride] as i16;
+ let b = buf[off - 1 + y * stride] as i16;
+ let c = buf[off + 0 + y * stride] as i16;
+ let d = buf[off + 1 + y * stride] as i16;
+ let diff = ((a - d) * 3 + (c - b) * 8) >> 4;
+ if (diff != 0) && (diff >= -32) && (diff < 32) {
+ let d0 = diff.abs() * 2 - (q as i16);
+ let d1 = if d0 < 0 { 0 } else { d0 };
+ let d2 = diff.abs() - d1;
+ let d3 = if d2 < 0 { 0 } else { d2 };
+
+ let delta = if diff < 0 { -d3 } else { d3 };
+
+ let b1 = b + delta;
+ if b1 < 0 { buf[off - 1 + y * stride] = 0; }
+ else if b1 > 255 { buf[off - 1 + y * stride] = 0xFF; }
+ else { buf[off - 1 + y * stride] = b1 as u8; }
+ let c1 = c - delta;
+ if c1 < 0 { buf[off + y * stride] = 0; }
+ else if c1 > 255 { buf[off + y * stride] = 0xFF; }
+ else { buf[off + y * stride] = c1 as u8; }
+ }
+ }
}
impl Intel263Decoder {