From: Kostya Shishkov Date: Thu, 8 Jun 2017 17:26:55 +0000 (+0200) Subject: preliminary work on Intel I.263 X-Git-Url: https://git.nihav.org/?a=commitdiff_plain;h=cf64af13518ee281beec24f32aa0e36317260b82;p=nihav.git preliminary work on Intel I.263 --- diff --git a/src/codecs/blockdec.rs b/src/codecs/blockdec.rs new file mode 100644 index 0000000..0326f84 --- /dev/null +++ b/src/codecs/blockdec.rs @@ -0,0 +1,440 @@ +use std::mem; +use std::ops::Add; +use super::*; +use super::blockdsp; +use super::h263code::*; +use formats; + +#[derive(Debug,Clone,Copy,PartialEq)] +pub enum Type { + I, P, Skip, Special +} + +#[allow(dead_code)] +#[derive(Debug,Clone,Copy)] +pub struct PicInfo { + w: usize, + h: usize, + mode: Type, + quant: u8, + apm: bool, + umv: bool, + pb: bool, + ts: u8, +} + +#[allow(dead_code)] +impl PicInfo { + pub fn new(w: usize, h: usize, mode: Type, quant: u8, apm: bool, umv: bool, pb: bool, ts: u8) -> Self { + PicInfo{ w: w, h: h, mode: mode, quant: quant, apm: apm, umv: umv, pb: pb, ts: ts } + } + pub fn get_width(&self) -> usize { self.w } + pub fn get_height(&self) -> usize { self.h } + pub fn get_mode(&self) -> Type { self.mode } + pub fn get_quant(&self) -> u8 { self.quant } + pub fn get_apm(&self) -> bool { self.apm } + pub fn get_umv(&self) -> bool { self.umv } + pub fn is_pb(&self) -> bool { self.pb } + pub fn get_ts(&self) -> u8 { self.ts } +} + +#[derive(Debug,Clone,Copy)] +pub struct Slice { + mb_x: usize, + mb_y: usize, + quant: u8, +} + +impl Slice { + pub fn new(mb_x: usize, mb_y: usize, quant: u8) -> Self { + Slice{ mb_x: mb_x, mb_y: mb_y, quant: quant } + } + pub fn get_default_slice(pinfo: &PicInfo) -> Self { + Slice{ mb_x: 0, mb_y: 0, quant: pinfo.get_quant() } + } + pub fn get_quant(&self) -> u8 { self.quant } +} + +#[derive(Debug,Clone,Copy)] +pub struct MV { + x: i16, + y: i16, +} + +impl MV { + pub fn new(x: i16, y: i16) -> Self { MV{ x: x, y: y } } + pub fn pred(a: MV, b: MV, c: MV) -> Self { + let x; + if a.x < b.x { + if b.x < c.x { + x = b.x; + } else { + if a.x < c.x { x = c.x; } else { x = a.x; } + } + } else { + if b.x < c.x { + if a.x < c.x { x = a.x; } else { x = c.x; } + } else { + x = b.x; + } + } + let y; + if a.y < b.y { + if b.y < c.y { + y = b.y; + } else { + if a.y < c.y { y = c.y; } else { y = a.y; } + } + } else { + if b.y < c.y { + if a.y < c.y { y = a.y; } else { y = c.y; } + } else { + y = b.y; + } + } + MV { x: x, y: y } + } + fn add_umv(pred_mv: MV, add: MV, umv: bool) -> Self { + let mut new_mv = pred_mv + add; + if umv { + if pred_mv.x > 32 && new_mv.x > 63 { new_mv.x -= 64; } + if pred_mv.x < -31 && new_mv.x < -63 { new_mv.x += 64; } + if pred_mv.y > 32 && new_mv.y > 63 { new_mv.y -= 64; } + if pred_mv.y < -31 && new_mv.y < -63 { new_mv.y += 64; } + } else { + if new_mv.x > 31 { new_mv.x -= 64; } + else if new_mv.x < -32 { new_mv.x += 64; } + if new_mv.y > 31 { new_mv.y -= 64; } + else if new_mv.y < -32 { new_mv.y += 64; } + } + new_mv + } +} + +pub const ZERO_MV: MV = MV { x: 0, y: 0 }; + +impl Add for MV { + type Output = MV; + fn add(self, other: MV) -> MV { MV { x: self.x + other.x, y: self.y + other.y } } +} + +#[derive(Debug,Clone,Copy)] +pub struct BlockInfo { + intra: bool, + skip: bool, + mode: Type, + cbp: u8, + q: u8, + mv: [MV; 4], + num_mv: usize, + bpart: bool, + b_cbp: u8, + mv2: [MV; 4], + num_mv2: usize, +} + +#[allow(dead_code)] +impl BlockInfo { + pub fn new(mode: Type, cbp: u8, q: u8) -> Self { + BlockInfo { + intra: mode == Type::I, + skip: (cbp == 0) && (mode != Type::I), + mode: mode, + cbp: cbp, + q: q, + mv: [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)], + num_mv: 0, + bpart: false, + b_cbp: 0, + mv2: [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)], + num_mv2: 0, + } + } + pub fn is_intra(&self) -> bool { self.intra } + pub fn is_skipped(&self) -> bool { self.skip } + pub fn get_mode(&self) -> Type { self.mode } + pub fn get_cbp(&self) -> u8 { self.cbp } + pub fn get_q(&self) -> u8 { self.q } + pub fn get_num_mvs(&self) -> usize { self.num_mv } + pub fn get_mv(&self, idx: usize) -> MV { self.mv[idx] } + pub fn has_b_part(&self) -> bool { self.bpart } + pub fn get_cbp_b(&self) -> u8 { self.b_cbp } + pub fn get_num_mvs2(&self) -> usize { self.num_mv2 } + pub fn get_mv2(&self, idx: usize) -> MV { self.mv2[idx] } + pub fn set_mv(&mut self, mvs: &[MV]) { + if mvs.len() > 0 { self.skip = false; } + self.bpart = true; + let mut mv_arr: [MV; 4] = [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)]; + for i in 0..mvs.len() { mv_arr[i] = mvs[i]; } + self.mv = mv_arr; + self.num_mv = mvs.len(); + } + pub fn set_mv2(&mut self, cbp: u8, mvs: &[MV]) { + self.bpart = true; + self.b_cbp = cbp; + let mut mv_arr: [MV; 4] = [MV::new(0, 0), MV::new(0, 0), MV::new(0, 0), MV::new(0, 0)]; + for i in 0..mvs.len() { mv_arr[i] = mvs[i]; } + self.mv2 = mv_arr; + self.num_mv2 = mvs.len(); + } +} + +pub trait BlockDecoder { + fn decode_pichdr(&mut self) -> DecoderResult; + fn decode_slice_header(&mut self, pinfo: &PicInfo) -> DecoderResult; + fn decode_block_header(&mut self, pinfo: &PicInfo, sinfo: &Slice) -> DecoderResult; + fn decode_block_intra(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>; + fn decode_block_inter(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()>; + fn calc_mv(&mut self, vec: MV); + fn is_slice_end(&mut self) -> bool; +} + +#[allow(dead_code)] +struct MVInfo { + mv: Vec, + mb_w: usize, + mb_stride: usize, + mb_start: usize, + top: bool, + umv: bool, +} + +impl MVInfo { + fn new() -> Self { MVInfo{ mv: Vec::new(), mb_w: 0, mb_stride: 0, mb_start: 0, top: true, umv: false } } + fn reset(&mut self, mb_w: usize, mb_start: usize, umv: bool) { + self.mb_start = mb_start; + self.mb_w = mb_w; + self.mb_stride = mb_w * 2; + self.top = true; + self.mv.resize(self.mb_stride * 3, ZERO_MV); + self.umv = umv; + } + fn update_row(&mut self) { + self.mb_start = self.mb_w + 1; + self.top = false; + for i in 0..self.mb_stride { + self.mv[i] = self.mv[self.mb_stride * 2 + i]; + } + } + #[allow(non_snake_case)] + fn predict(&mut self, mb_x: usize, blk_no: usize, use4: bool, diff: MV) -> MV { + let A; + let B; + let C; + let last = mb_x == self.mb_w - 1; +//println!(" pred from {}.{} blk {}.{}/{} top {}", diff.x, diff.y, mb_x, blk_no,self.mb_start,self.top); + match blk_no { + 0 => { + if mb_x != self.mb_start { + A = if mb_x != 0 { self.mv[self.mb_stride + mb_x * 2 - 1] } else { ZERO_MV }; + B = if !self.top { self.mv[ mb_x * 2] } else { A }; + C = if !self.top && !last { self.mv[mb_x * 2 + 2] } else { ZERO_MV }; + } else { + A = ZERO_MV; B = ZERO_MV; C = ZERO_MV; + } + }, + 1 => { + A = self.mv[self.mb_stride + mb_x * 2]; + B = if !self.top { self.mv[mb_x * 2 + 1] } else { A }; + C = if !self.top && !last { self.mv[mb_x * 2 + 2] } else { A }; + }, + 2 => { + A = if mb_x != self.mb_start { self.mv[self.mb_stride * 2 + mb_x * 2 - 1] } else { ZERO_MV }; + B = self.mv[self.mb_stride + mb_x * 2]; + C = self.mv[self.mb_stride + mb_x * 2 + 1]; + }, + 3 => { + A = self.mv[self.mb_stride * 2 + mb_x * 2]; + B = self.mv[self.mb_stride * 1 + mb_x * 2 + 1]; + C = self.mv[self.mb_stride * 1 + mb_x * 2]; + }, + _ => { return ZERO_MV; } + } +//println!(" A = {}.{} B = {}.{} C = {}.{}", A.x,A.y,B.x,B.y,C.x,C.y); + let pred_mv = MV::pred(A, B, C); + let new_mv = MV::add_umv(pred_mv, diff, self.umv); + if !use4 { + self.mv[self.mb_stride * 1 + mb_x * 2 + 0] = new_mv; + self.mv[self.mb_stride * 1 + mb_x * 2 + 1] = new_mv; + self.mv[self.mb_stride * 2 + mb_x * 2 + 0] = new_mv; + self.mv[self.mb_stride * 2 + mb_x * 2 + 1] = new_mv; + } else { + match blk_no { + 0 => { self.mv[self.mb_stride * 1 + mb_x * 2 + 0] = new_mv; }, + 1 => { self.mv[self.mb_stride * 1 + mb_x * 2 + 1] = new_mv; }, + 2 => { self.mv[self.mb_stride * 2 + mb_x * 2 + 0] = new_mv; }, + 3 => { self.mv[self.mb_stride * 2 + mb_x * 2 + 1] = new_mv; }, + _ => {}, + }; + } + + new_mv + } + fn set_zero_mv(&mut self, mb_x: usize) { + self.mv[self.mb_stride * 1 + mb_x * 2 + 0] = ZERO_MV; + self.mv[self.mb_stride * 1 + mb_x * 2 + 1] = ZERO_MV; + self.mv[self.mb_stride * 2 + mb_x * 2 + 0] = ZERO_MV; + self.mv[self.mb_stride * 2 + mb_x * 2 + 1] = ZERO_MV; + } +} + +fn copy_blocks(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, 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); + let mode = ((mv.x & 1) + (mv.y & 1) * 2) as usize; + + blockdsp::copy_blocks(dst, src, xpos, ypos, srcx, srcy, w, h, 0, 1, mode, H263_INTERP_FUNCS); +} + +pub struct DCT8x8VideoDecoder { + w: usize, + h: usize, + mb_w: usize, + mb_h: usize, + num_mb: usize, + ftype: Type, + prev_frm: Option>, + cur_frm: Option>, +} + +#[allow(dead_code)] +impl DCT8x8VideoDecoder { + pub fn new() -> Self { + DCT8x8VideoDecoder{ + w: 0, h: 0, mb_w: 0, mb_h: 0, num_mb: 0, + ftype: Type::Special, + prev_frm: None, cur_frm: None, + } + } + + pub fn is_intra(&self) -> bool { self.ftype == Type::I } + pub fn get_dimensions(&self) -> (usize, usize) { (self.w, self.h) } + + pub fn parse_frame(&mut self, bd: &mut BlockDecoder) -> DecoderResult { + let pinfo = bd.decode_pichdr()?; + let mut mvi = MVInfo::new(); + +//todo handle res change + self.w = pinfo.w; + self.h = pinfo.h; + self.mb_w = (pinfo.w + 15) >> 4; + self.mb_h = (pinfo.h + 15) >> 4; + self.num_mb = self.mb_w * self.mb_h; + self.ftype = pinfo.mode; + + mem::swap(&mut self.cur_frm, &mut self.prev_frm); +// if self.ftype == Type::I && !pinfo.is_pb() { self.prev_frm = None; } + + let fmt = formats::YUV420_FORMAT; + let vinfo = NAVideoInfo::new(self.w, self.h, false, fmt); + let bufret = alloc_video_buffer(vinfo, 4); + if let Err(_) = bufret { return Err(DecoderError::InvalidData); } + let mut bufinfo = bufret.unwrap(); + let mut buf = bufinfo.get_vbuf().unwrap(); + + let mut bbuf; + + if self.prev_frm.is_some() && pinfo.is_pb() { + let bufret = alloc_video_buffer(vinfo, 4); + if let Err(_) = bufret { return Err(DecoderError::InvalidData); } + let mut bbufinfo = bufret.unwrap(); + bbuf = Some(bbufinfo.get_vbuf().unwrap()); + } else { + bbuf = None; + } + + let mut slice = Slice::get_default_slice(&pinfo); + mvi.reset(self.mb_w, 0, pinfo.get_umv()); + + let mut blk: [[i16; 64]; 6] = [[0; 64]; 6]; + for mb_y in 0..self.mb_h { + for mb_x in 0..self.mb_w { + for i in 0..6 { for j in 0..64 { blk[i][j] = 0; } } + + if ((mb_x != 0) || (mb_y != 0)) && bd.is_slice_end() { +//println!("new slice @{}.{}!",mb_x,mb_y); + slice = bd.decode_slice_header(&pinfo)?; + mvi.reset(self.mb_w, mb_x, pinfo.get_umv()); + } + + 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()); + if binfo.is_intra() { + for i in 0..6 { + bd.decode_block_intra(&binfo, i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?; + h263_idct(&mut blk[i]); + } + blockdsp::put_blocks(&mut buf, mb_x, mb_y, &blk); + mvi.set_zero_mv(mb_x); + } else if !binfo.is_skipped() { + if binfo.get_num_mvs() == 1 { + let mv = mvi.predict(mb_x, 0, false, binfo.get_mv(0)); +//println!(" 1MV {}.{}", mv.x, mv.y); + if let Some(ref srcbuf) = self.prev_frm { + copy_blocks(&mut buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, mv); + } + } else { + for blk_no in 0..4 { + let mv = mvi.predict(mb_x, blk_no, true, binfo.get_mv(blk_no)); +//print!(" MV {}.{}", mv.x, mv.y); + if let Some(ref srcbuf) = self.prev_frm { + copy_blocks(&mut buf, srcbuf, + mb_x * 16 + (blk_no & 1) * 8, + mb_y * 16 + (blk_no & 2) * 4, 8, 8, mv); + } + } +//println!(""); + } + for i in 0..6 { + bd.decode_block_inter(&binfo, i, ((cbp >> (5 - i)) & 1) != 0, &mut blk[i])?; + h263_idct(&mut blk[i]); + } + blockdsp::add_blocks(&mut buf, mb_x, mb_y, &blk); + } else { + mvi.set_zero_mv(mb_x); + if let Some(ref srcbuf) = self.prev_frm { + copy_blocks(&mut buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV); + } + } + if pinfo.is_pb() && binfo.has_b_part() { + let mut blk: [[i16; 64]; 6] = [[0; 64]; 6]; + let cbp = binfo.get_cbp_b(); + for i in 0..6 { + bd.decode_block_inter(&binfo, i, (cbp & (1 << (5 - i))) != 0, &mut blk[i])?; + h263_idct(&mut blk[i]); + } + if let Some(ref mut b_buf) = bbuf { +/* let is_fwd = false; + if binfo.get_num_mvs() == 1 { //todo scale + let mv_f = MV::add_umv(binfo.get_mv(0), binfo.get_mv2(0), pinfo.get_umv()); + let mv_b = ZERO_MV//if component = 0 then scaled else mv_f - component + } else { + }*/ + if let Some(ref srcbuf) = self.prev_frm { + copy_blocks(b_buf, srcbuf, mb_x * 16, mb_y * 16, 16, 16, ZERO_MV); + blockdsp::add_blocks(b_buf, mb_x, mb_y, &blk); + } + } + } + + } + mvi.update_row(); + } + self.cur_frm = Some(buf); + if pinfo.is_pb() { + return Ok(NABufferType::Video(bbuf.unwrap())); + } +println!("unpacked all"); + Ok(bufinfo) + } + + pub fn get_stored_pframe(&mut self) -> DecoderResult { + if let Some(_) = self.cur_frm { + let buf = self.cur_frm.clone().unwrap(); + Ok(NABufferType::Video(buf)) + } else { + Err(DecoderError::MissingReference) + } + } +} diff --git a/src/codecs/blockdsp.rs b/src/codecs/blockdsp.rs new file mode 100644 index 0000000..2f02b84 --- /dev/null +++ b/src/codecs/blockdsp.rs @@ -0,0 +1,186 @@ +use frame::*; + +pub fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) { + let stridey = buf.get_stride(0); + let strideu = buf.get_stride(1); + let stridev = buf.get_stride(2); + let mut idxy = buf.get_offset(0) + xpos * 16 + ypos * 16 * stridey; + let mut idxu = buf.get_offset(1) + xpos * 8 + ypos * 8 * strideu; + let mut idxv = buf.get_offset(2) + xpos * 8 + ypos * 8 * stridev; + + let mut data = buf.get_data_mut(); + let mut framebuf: &mut [u8] = data.as_mut_slice(); + + for j in 0..8 { + for k in 0..8 { + let mut v = blk[0][k + j * 8]; + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k] = v as u8; + } + for k in 0..8 { + let mut v = blk[1][k + j * 8]; + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k + 8] = v as u8; + } + idxy += stridey; + } + for j in 0..8 { + for k in 0..8 { + let mut v = blk[2][k + j * 8]; + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k] = v as u8; + } + for k in 0..8 { + let mut v = blk[3][k + j * 8]; + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k + 8] = v as u8; + } + idxy += stridey; + } + + for j in 0..8 { + for k in 0..8 { + let mut v = blk[4][k + j * 8]; + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxu + k] = v as u8; + } + for k in 0..8 { + let mut v = blk[5][k + j * 8]; + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxv + k] = v as u8; + } + idxu += strideu; + idxv += stridev; + } +} + +pub fn add_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i16;64]; 6]) { + let stridey = buf.get_stride(0); + let strideu = buf.get_stride(1); + let stridev = buf.get_stride(2); + let mut idxy = buf.get_offset(0) + xpos * 16 + ypos * 16 * stridey; + let mut idxu = buf.get_offset(1) + xpos * 8 + ypos * 8 * strideu; + let mut idxv = buf.get_offset(2) + xpos * 8 + ypos * 8 * stridev; + + let mut data = buf.get_data_mut(); + let mut framebuf: &mut [u8] = data.as_mut_slice(); + + for j in 0..8 { + for k in 0..8 { + let mut v = blk[0][k + j * 8] + (framebuf[idxy + k] as i16); + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k] = v as u8; + } + for k in 0..8 { + let mut v = blk[1][k + j * 8] + (framebuf[idxy + k + 8] as i16); + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k + 8] = v as u8; + } + idxy += stridey; + } + for j in 0..8 { + for k in 0..8 { + let mut v = blk[2][k + j * 8] + (framebuf[idxy + k] as i16); + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k] = v as u8; + } + for k in 0..8 { + let mut v = blk[3][k + j * 8] + (framebuf[idxy + k + 8] as i16); + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxy + k + 8] = v as u8; + } + idxy += stridey; + } + + for j in 0..8 { + for k in 0..8 { + let mut v = blk[4][k + j * 8] + (framebuf[idxu + k] as i16); + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxu + k] = v as u8; + } + for k in 0..8 { + let mut v = blk[5][k + j * 8] + (framebuf[idxv + k] as i16); + if v < 0 { v = 0; } if v > 255 { v = 255; } + framebuf[idxv + k] = v as u8; + } + idxu += strideu; + idxv += stridev; + } +} + +fn edge_emu(src: &NAVideoBuffer, xpos: isize, ypos: isize, bw: usize, bh: usize, dst: &mut [u8], dstride: usize, comp: usize) { + let stride = src.get_stride(comp); + let offs = src.get_offset(comp); + let (w, h) = src.get_dimensions(comp); + let data = src.get_data(); + let framebuf: &[u8] = data.as_slice(); + + for y in 0..bh { + let srcy; + if (y as isize) + ypos < 0 { srcy = 0; } + else if (y as isize) + ypos >= (h as isize) { srcy = h - 1; } + else { srcy = ((y as isize) + ypos) as usize; } + + for x in 0..bw { + let srcx; + if (x as isize) + xpos < 0 { srcx = 0; } + else if (x as isize) + xpos >= (w as isize) { srcx = w - 1; } + else { srcx = ((x as isize) + xpos) as usize; } + dst[x + y * dstride] = framebuf[offs + srcx + srcy * stride]; + } + } +} + +pub fn copy_blocks(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, + dx: usize, dy: usize, sx: isize, sy: isize, bw: usize, bh: usize, + preborder: usize, postborder: usize, + mode: usize, interp: &[fn(&mut [u8], usize, &[u8], usize, usize, usize)]) +{ + let pre = if mode != 0 { preborder as isize } else { 0 }; + let post = if mode != 0 { postborder as isize } else { 0 }; + let (w, h) = src.get_dimensions(0); + + if (sx - pre < 0) || ((sx >> 1) - pre < 0) || (sx + (bw as isize) + post > (w as isize)) || + (sy - pre < 0) || ((sy >> 1) - pre < 0) || (sy + (bh as isize) + post > (h as isize)) { + let ebuf_stride: usize = 32; + let mut ebuf: Vec = Vec::with_capacity(ebuf_stride * (bh + ((pre + post) as usize))); + ebuf.resize((((pre + post) as usize) + bh) * ebuf_stride, 0); + + for comp in 0..3 { + let dstride = src.get_stride(comp); + let doff = dst.get_offset(comp); + let mut ddta = dst.get_data_mut(); + let mut dbuf: &mut [u8] = ddta.as_mut_slice(); + let x = if comp > 0 { dx/2 } else { dx }; + let y = if comp > 0 { dy/2 } else { dy }; + let sx_ = (if comp > 0 { sx >> 1 } else { sx }) - pre; + let sy_ = (if comp > 0 { sy >> 1 } else { sy }) - pre; + let bw_ = (if comp > 0 { bw/2 } else { bw }) + ((pre + post) as usize); + let bh_ = (if comp > 0 { bh/2 } else { bh }) + ((pre + post) as usize); + edge_emu(src, sx_ - pre, sy_ - pre, bw_, bh_, + ebuf.as_mut_slice(), ebuf_stride, comp); + let bw_ = if comp > 0 { bw/2 } else { bw }; + let bh_ = if comp > 0 { bh/2 } else { bh }; + (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, ebuf.as_slice(), ebuf_stride, bw_, bh_); + } + + } else { + for comp in 0..3 { + let sstride = src.get_stride(comp); + let soff = src.get_offset(comp); + let sdta = src.get_data(); + let sbuf: &[u8] = sdta.as_slice(); + let dstride = src.get_stride(comp); + let doff = dst.get_offset(comp); + let mut ddta = dst.get_data_mut(); + let mut dbuf: &mut [u8] = ddta.as_mut_slice(); + let x = if comp > 0 { dx/2 } else { dx }; + let y = if comp > 0 { dy/2 } else { dy }; + let sx_ = ((if comp > 0 { sx >> 1 } else { sx }) - pre) as usize; + let sy_ = ((if comp > 0 { sy >> 1 } else { sy }) - pre) as usize; + let bw_ = if comp > 0 { bw/2 } else { bw }; + let bh_ = if comp > 0 { bh/2 } else { bh }; + (interp[mode])(&mut dbuf[doff + x + y * dstride..], dstride, &sbuf[(soff + sx_ + sy_ * sstride)..], sstride, bw_, bh_); + } + } +} diff --git a/src/codecs/h263code.rs b/src/codecs/h263code.rs new file mode 100644 index 0000000..d38af95 --- /dev/null +++ b/src/codecs/h263code.rs @@ -0,0 +1,269 @@ +//use super::h263data::*; + +/*const W1: i32 = 22725; +const W2: i32 = 21407; +const W3: i32 = 19266; +const W4: i32 = 16383; +const W5: i32 = 12873; +const W6: i32 = 8867; +const W7: i32 = 4520; + +const ROW_SHIFT: u8 = 11; +const COL_SHIFT: u8 = 20; + +fn idct_row(row: &mut [i16]) { + let in0 = row[0] as i32; + let in1 = row[1] as i32; + let in2 = row[2] as i32; + let in3 = row[3] as i32; + let in4 = row[4] as i32; + let in5 = row[5] as i32; + let in6 = row[6] as i32; + let in7 = row[7] as i32; + + let mut a0 = in0 * W1 + (1 << (ROW_SHIFT - 1)); + let mut a1 = a0; + let mut a2 = a0; + let mut a3 = a0; + + a0 += W2 * in2; + a1 += W6 * in2; + a2 -= W6 * in2; + a3 -= W2 * in2; + + let mut b0 = W1 * in1 + W3 * in3; + let mut b1 = W3 * in1 - W7 * in3; + let mut b2 = W5 * in1 - W1 * in3; + let mut b3 = W7 * in1 - W5 * in3; + + a0 += W4 * in4 + W6 * in6; + a1 -= W4 * in4 + W2 * in6; + a2 -= W4 * in4 - W2 * in6; + a3 += W4 * in4 - W6 * in6; + + b0 += W5 * in5 + W7 * in7; + b1 -= W1 * in5 + W5 * in7; + b2 += W7 * in5 + W3 * in7; + b3 += W3 * in5 - W1 * in7; + + row[0] = ((a0 + b0) >> ROW_SHIFT) as i16; + row[7] = ((a0 - b0) >> ROW_SHIFT) as i16; + row[1] = ((a1 + b1) >> ROW_SHIFT) as i16; + row[6] = ((a1 - b1) >> ROW_SHIFT) as i16; + row[2] = ((a2 + b2) >> ROW_SHIFT) as i16; + row[5] = ((a2 - b2) >> ROW_SHIFT) as i16; + row[3] = ((a3 + b3) >> ROW_SHIFT) as i16; + row[4] = ((a3 - b3) >> ROW_SHIFT) as i16; +} + +fn idct_col(blk: &mut [i16; 64], off: usize) { + let in0 = blk[off + 0*8] as i32; + let in1 = blk[off + 1*8] as i32; + let in2 = blk[off + 2*8] as i32; + let in3 = blk[off + 3*8] as i32; + let in4 = blk[off + 4*8] as i32; + let in5 = blk[off + 5*8] as i32; + let in6 = blk[off + 6*8] as i32; + let in7 = blk[off + 7*8] as i32; + + let mut a0 = in0 * W1 + (1 << (COL_SHIFT - 1)); + let mut a1 = a0; + let mut a2 = a0; + let mut a3 = a0; + + a0 += W2 * in2; + a1 += W6 * in2; + a2 -= W6 * in2; + a3 -= W2 * in2; + + let mut b0 = W1 * in1 + W3 * in3; + let mut b1 = W3 * in1 - W7 * in3; + let mut b2 = W5 * in1 - W1 * in3; + let mut b3 = W7 * in1 - W5 * in3; + + a0 += W4 * in4 + W6 * in6; + a1 -= W4 * in4 + W2 * in6; + a2 -= W4 * in4 - W2 * in6; + a3 += W4 * in4 - W6 * in6; + + b0 += W5 * in5 + W7 * in7; + b1 -= W1 * in5 + W5 * in7; + b2 += W7 * in5 + W3 * in7; + b3 += W3 * in5 - W1 * in7; + + blk[off + 0*8] = ((a0 + b0) >> COL_SHIFT) as i16; + blk[off + 7*8] = ((a0 - b0) >> COL_SHIFT) as i16; + blk[off + 1*8] = ((a1 + b1) >> COL_SHIFT) as i16; + blk[off + 6*8] = ((a1 - b1) >> COL_SHIFT) as i16; + blk[off + 2*8] = ((a2 + b2) >> COL_SHIFT) as i16; + blk[off + 5*8] = ((a2 - b2) >> COL_SHIFT) as i16; + blk[off + 3*8] = ((a3 + b3) >> COL_SHIFT) as i16; + blk[off + 4*8] = ((a3 - b3) >> COL_SHIFT) as i16; +} + +#[allow(dead_code)] +pub fn h263_idct(blk: &mut [i16; 64]) { + for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); } + for i in 0..8 { idct_col(blk, i); } +}*/ + +const W1: i32 = 2841; +const W2: i32 = 2676; +const W3: i32 = 2408; +const W5: i32 = 1609; +const W6: i32 = 1108; +const W7: i32 = 565; +const W8: i32 = 181; + +const ROW_SHIFT: u8 = 8; +const COL_SHIFT: u8 = 14; + +fn idct_row(row: &mut [i16]) { + let in0 = ((row[0] as i32) << 11) + (1 << (ROW_SHIFT - 1)); + let in1 = (row[4] as i32) << 11; + let in2 = row[6] as i32; + let in3 = row[2] as i32; + let in4 = row[1] as i32; + let in5 = row[7] as i32; + let in6 = row[5] as i32; + let in7 = row[3] as i32; + + let tmp = W7 * (in4 + in5); + let a4 = tmp + (W1 - W7) * in4; + let a5 = tmp - (W1 + W7) * in5; + + let tmp = W3 * (in6 + in7); + let a6 = tmp - (W3 - W5) * in6; + let a7 = tmp - (W3 + W5) * in7; + + let tmp = in0 + in1; + + let a0 = in0 - in1; + let t1 = W6 * (in2 + in3); + let a2 = t1 - (W2 + W6) * in2; + let a3 = t1 + (W2 - W6) * in3; + let b1 = a4 + a6; + + let b4 = a4 - a6; + let t2 = a5 - a7; + let b6 = a5 + a7; + let b7 = tmp + a3; + let b5 = tmp - a3; + let b3 = a0 + a2; + let b0 = a0 - a2; + let b2 = (W8 * (b4 + t2) + 128) >> 8; + let b4 = (W8 * (b4 - t2) + 128) >> 8; + + row[0] = ((b7 + b1) >> ROW_SHIFT) as i16; + row[7] = ((b7 - b1) >> ROW_SHIFT) as i16; + row[1] = ((b3 + b2) >> ROW_SHIFT) as i16; + row[6] = ((b3 - b2) >> ROW_SHIFT) as i16; + row[2] = ((b0 + b4) >> ROW_SHIFT) as i16; + row[5] = ((b0 - b4) >> ROW_SHIFT) as i16; + row[3] = ((b5 + b6) >> ROW_SHIFT) as i16; + row[4] = ((b5 - b6) >> ROW_SHIFT) as i16; +} + +fn idct_col(blk: &mut [i16; 64], off: usize) { + let in0 = ((blk[off + 0*8] as i32) << 8) + (1 << (COL_SHIFT - 1)); + let in1 = (blk[off + 4*8] as i32) << 8; + let in2 = blk[off + 6*8] as i32; + let in3 = blk[off + 2*8] as i32; + let in4 = blk[off + 1*8] as i32; + let in5 = blk[off + 7*8] as i32; + let in6 = blk[off + 5*8] as i32; + let in7 = blk[off + 3*8] as i32; + + let tmp = W7 * (in4 + in5); + let a4 = (tmp + (W1 - W7) * in4) >> 3; + let a5 = (tmp - (W1 + W7) * in5) >> 3; + + let tmp = W3 * (in6 + in7); + let a6 = (tmp - (W3 - W5) * in6) >> 3; + let a7 = (tmp - (W3 + W5) * in7) >> 3; + + let tmp = in0 + in1; + + let a0 = in0 - in1; + let t1 = W6 * (in2 + in3); + let a2 = (t1 - (W2 + W6) * in2) >> 3; + let a3 = (t1 + (W2 - W6) * in3) >> 3; + let b1 = a4 + a6; + + let b4 = a4 - a6; + let t2 = a5 - a7; + let b6 = a5 + a7; + let b7 = tmp + a3; + let b5 = tmp - a3; + let b3 = a0 + a2; + let b0 = a0 - a2; + let b2 = (W8 * (b4 + t2) + 128) >> 8; + let b4 = (W8 * (b4 - t2) + 128) >> 8; + + blk[off + 0*8] = ((b7 + b1) >> COL_SHIFT) as i16; + blk[off + 7*8] = ((b7 - b1) >> COL_SHIFT) as i16; + blk[off + 1*8] = ((b3 + b2) >> COL_SHIFT) as i16; + blk[off + 6*8] = ((b3 - b2) >> COL_SHIFT) as i16; + blk[off + 2*8] = ((b0 + b4) >> COL_SHIFT) as i16; + blk[off + 5*8] = ((b0 - b4) >> COL_SHIFT) as i16; + blk[off + 3*8] = ((b5 + b6) >> COL_SHIFT) as i16; + blk[off + 4*8] = ((b5 - b6) >> COL_SHIFT) as i16; +} + +#[allow(dead_code)] +pub fn h263_idct(blk: &mut [i16; 64]) { + for i in 0..8 { idct_row(&mut blk[i*8..(i+1)*8]); } + for i in 0..8 { idct_col(blk, i); } +} + +fn h263_interp00(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { dst[didx + x] = src[sidx + x]; } + didx += dstride; + sidx += sstride; + } +} + +fn h263_interp01(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + 1] as u16) + 1) >> 1) as u8; } + didx += dstride; + sidx += sstride; + } +} + +fn h263_interp10(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { dst[didx + x] = (((src[sidx + x] as u16) + (src[sidx + x + sstride] as u16) + 1) >> 1) as u8; } + didx += dstride; + sidx += sstride; + } +} + +fn h263_interp11(dst: &mut [u8], dstride: usize, src: &[u8], sstride: usize, bw: usize, bh: usize) +{ + let mut didx = 0; + let mut sidx = 0; + for _ in 0..bh { + for x in 0..bw { + dst[didx + x] = (((src[sidx + x] as u16) + + (src[sidx + x + 1] as u16) + + (src[sidx + x + sstride] as u16) + + (src[sidx + x + sstride + 1] as u16) + 2) >> 2) as u8; + } + didx += dstride; + sidx += sstride; + } +} + +pub const H263_INTERP_FUNCS: &[fn(&mut [u8], usize, &[u8], usize, usize, usize)] = &[ + h263_interp00, h263_interp01, h263_interp10, h263_interp11 ]; diff --git a/src/codecs/h263data.rs b/src/codecs/h263data.rs new file mode 100644 index 0000000..76c3c43 --- /dev/null +++ b/src/codecs/h263data.rs @@ -0,0 +1,148 @@ +use io::codebook::CodebookDescReader; + +#[allow(dead_code)] +pub const H263_SCALES: &[u8] = &[ + 0, 1, 2, 3, 4, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15 ]; + +pub const H263_ZIGZAG: &[usize] = &[ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +]; + +pub const H263_SIZES: &[(usize, usize)] = &[ + (0, 0), (128, 96), (176, 144), (352, 288), (704, 576), (1408, 1152) +]; + +pub const H263_INTRA_MCBPC: &[(u8, u8)] = &[ + (1, 1), (1, 3), (2, 3), (3, 3), (1, 4), (1, 6), (2, 6), (3, 6), (1, 9) +]; + +pub const H263_INTER_MCBPC: &[(u8, u8)] = &[ + (1, 1), (3, 4), (2, 4), (5, 6), (3, 5), (4, 8), (3, 8), (3, 7), + (3, 3), (7, 7), (6, 7), (5, 9), (4, 6), (4, 9), (3, 9), (2, 9), + (2, 3), (5, 7), (4, 7), (5, 8), (1, 9), (0, 0), (0, 0), (0, 0), + (2, 11), (12, 13), (14, 13), (15, 13) +]; + +pub const H263_CBPY: &[(u8, u8)] = &[ + ( 3, 4), ( 5, 5), ( 4, 5), ( 9, 4), ( 3, 5), ( 7, 4), ( 2, 6), (11, 4), + ( 2, 5), ( 3, 6), ( 5, 4), (10, 4), ( 4, 4), ( 8, 4), ( 6, 4), ( 3, 2) +]; + +pub const H263_MV: &[(u8, u8)] = &[ + ( 1, 1), ( 1, 2), ( 1, 3), ( 1, 4), ( 3, 6), ( 5, 7), ( 4, 7), ( 3, 7), + (11, 9), (10, 9), ( 9, 9), (17, 10), (16, 10), (15, 10), (14, 10), (13, 10), + (12, 10), (11, 10), (10, 10), ( 9, 10), ( 8, 10), ( 7, 10), ( 6, 10), ( 5, 10), + ( 4, 10), ( 7, 11), ( 6, 11), ( 5, 11), ( 4, 11), ( 3, 11), ( 2, 11), ( 3, 12), + ( 2, 12) +]; + +pub const H263_DQUANT_TAB: &[i8] = &[-1, -2, 1, 2]; + +pub struct H263ShortCodeReader { tab: &'static [(u8, u8)] } + +impl H263ShortCodeReader { + pub fn new(tab: &'static [(u8, u8)]) -> Self { H263ShortCodeReader { tab: tab } } +} + +impl CodebookDescReader for H263ShortCodeReader { + fn bits(&mut self, idx: usize) -> u8 { let (_, bits) = self.tab[idx]; bits } + fn code(&mut self, idx: usize) -> u32 { let (code, _) = self.tab[idx]; code as u32 } + fn sym (&mut self, idx: usize) -> u8 { idx as u8 } + fn len(&mut self) -> usize { self.tab.len() } +} + +#[derive(Clone,Copy)] +pub struct H263RLSym { run: u8, level: i8 } +impl H263RLSym { + pub fn get_run(&self) -> u8 { self.run } + pub fn is_last(&self) -> bool { self.level < 0 } + pub fn is_escape(&self) -> bool { (self.run == 0) && (self.level == 0) } + pub fn get_level(&self) -> i16 { if self.level < 0 { -self.level as i16 } else { self.level as i16 } } +} + +pub struct H263RLCodeDesc { code: u8, bits: u8, sym: H263RLSym } + +macro_rules! rlcodes{ + ($(($c:expr, $b:expr, $r:expr, $l:expr)),*) => { + &[$(H263RLCodeDesc{ code: $c, bits: $b, sym: H263RLSym{ run: $r, level: $l }}),*] + } +} + +pub const H263_RL_CODES: &[H263RLCodeDesc] = rlcodes!( + (0x02, 2, 0, 1), (0x0F, 4, 0, 2), (0x15, 6, 0, 3), (0x17, 7, 0, 4), + (0x1F, 8, 0, 5), (0x25, 9, 0, 6), (0x24, 9, 0, 7), (0x21, 10, 0, 8), + (0x20, 10, 0, 9), (0x07, 11, 0, 10), (0x06, 11, 0, 11), (0x20, 11, 0, 12), + (0x06, 3, 1, 1), (0x14, 6, 1, 2), (0x1E, 8, 1, 3), (0x0F, 10, 1, 4), + (0x21, 11, 1, 5), (0x50, 12, 1, 6), (0x0E, 4, 2, 1), (0x1D, 8, 2, 2), + (0x0E, 10, 2, 3), (0x51, 12, 2, 4), (0x0D, 5, 3, 1), (0x23, 9, 3, 2), + (0x0D, 10, 3, 3), (0x0C, 5, 4, 1), (0x22, 9, 4, 2), (0x52, 12, 4, 3), + (0x0B, 5, 5, 1), (0x0C, 10, 5, 2), (0x53, 12, 5, 3), (0x13, 6, 6, 1), + (0x0B, 10, 6, 2), (0x54, 12, 6, 3), (0x12, 6, 7, 1), (0x0A, 10, 7, 2), + (0x11, 6, 8, 1), (0x09, 10, 8, 2), (0x10, 6, 9, 1), (0x08, 10, 9, 2), + (0x16, 7, 10, 1), (0x55, 12, 10, 2), (0x15, 7, 11, 1), (0x14, 7, 12, 1), + (0x1C, 8, 13, 1), (0x1B, 8, 14, 1), (0x21, 9, 15, 1), (0x20, 9, 16, 1), + (0x1F, 9, 17, 1), (0x1E, 9, 18, 1), (0x1D, 9, 19, 1), (0x1C, 9, 20, 1), + (0x1B, 9, 21, 1), (0x1A, 9, 22, 1), (0x22, 11, 23, 1), (0x23, 11, 24, 1), + (0x56, 12, 25, 1), (0x57, 12, 26, 1), (0x07, 4, 0, -1), (0x19, 9, 0, -2), + (0x05, 11, 0, -3), (0x0F, 6, 1, -1), (0x04, 11, 1, -2), (0x0E, 6, 2, -1), + (0x0D, 6, 3, -1), (0x0C, 6, 4, -1), (0x13, 7, 5, -1), (0x12, 7, 6, -1), + (0x11, 7, 7, -1), (0x10, 7, 8, -1), (0x1A, 8, 9, -1), (0x19, 8, 10, -1), + (0x18, 8, 11, -1), (0x17, 8, 12, -1), (0x16, 8, 13, -1), (0x15, 8, 14, -1), + (0x14, 8, 15, -1), (0x13, 8, 16, -1), (0x18, 9, 17, -1), (0x17, 9, 18, -1), + (0x16, 9, 19, -1), (0x15, 9, 20, -1), (0x14, 9, 21, -1), (0x13, 9, 22, -1), + (0x12, 9, 23, -1), (0x11, 9, 24, -1), (0x07, 10, 25, -1), (0x06, 10, 26, -1), + (0x05, 10, 27, -1), (0x04, 10, 28, -1), (0x24, 11, 29, -1), (0x25, 11, 30, -1), + (0x26, 11, 31, -1), (0x27, 11, 32, -1), (0x58, 12, 33, -1), (0x59, 12, 34, -1), + (0x5A, 12, 35, -1), (0x5B, 12, 36, -1), (0x5C, 12, 37, -1), (0x5D, 12, 38, -1), + (0x5E, 12, 39, -1), (0x5F, 12, 40, -1), (0x03, 7, 0, 0) +); + +pub const H263_RL_CODES_AIC: &[H263RLCodeDesc] = rlcodes!( + (0x02, 2, 0, 1), (0x06, 3, 0, 2), (0x0E, 4, 0, 3), (0x0C, 5, 0, 4), + (0x0D, 5, 0, 5), (0x10, 6, 0, 6), (0x11, 6, 0, 7), (0x12, 6, 0, 8), + (0x16, 7, 0, 9), (0x1B, 8, 0, 10), (0x20, 9, 0, 11), (0x21, 9, 0, 12), + (0x1A, 9, 0, 13), (0x1B, 9, 0, 14), (0x1C, 9, 0, 15), (0x1D, 9, 0, 16), + (0x1E, 9, 0, 17), (0x1F, 9, 0, 18), (0x23, 11, 0, 19), (0x22, 11, 0, 20), + (0x57, 12, 0, 21), (0x56, 12, 0, 22), (0x55, 12, 0, 23), (0x54, 12, 0, 24), + (0x53, 12, 0, 25), (0x0F, 4, 1, 1), (0x14, 6, 1, 2), (0x14, 7, 1, 3), + (0x1E, 8, 1, 4), (0x0F, 10, 1, 5), (0x21, 11, 1, 6), (0x50, 12, 1, 7), + (0x0B, 5, 2, 1), (0x15, 7, 2, 2), (0x0E, 10, 2, 3), (0x09, 10, 2, 4), + (0x15, 6, 3, 1), (0x1D, 8, 3, 2), (0x0D, 10, 3, 3), (0x51, 12, 3, 4), + (0x13, 6, 4, 1), (0x23, 9, 4, 2), (0x07, 11, 4, 3), (0x17, 7, 5, 1), + (0x22, 9, 5, 2), (0x52, 12, 5, 3), (0x1C, 8, 6, 1), (0x0C, 10, 6, 2), + (0x1F, 8, 7, 1), (0x0B, 10, 7, 2), (0x25, 9, 8, 1), (0x0A, 10, 8, 2), + (0x24, 9, 9, 1), (0x06, 11, 9, 2), (0x21, 10, 10, 1), (0x20, 10, 11, 1), + (0x08, 10, 12, 1), (0x20, 11, 13, 1), (0x07, 4, 0, -1), (0x0C, 6, 0, -2), + (0x10, 7, 0, -3), (0x13, 8, 0, -4), (0x11, 9, 0, -5), (0x12, 9, 0, -6), + (0x04, 10, 0, -7), (0x27, 11, 0, -8), (0x26, 11, 0, -9), (0x5F, 12, 0,-10), + (0x0F, 6, 1, -1), (0x13, 9, 1, -2), (0x05, 10, 1, -3), (0x25, 11, 1, -4), + (0x0E, 6, 2, -1), (0x14, 9, 2, -2), (0x24, 11, 2, -3), (0x0D, 6, 3, -1), + (0x06, 10, 3, -2), (0x5E, 12, 3, -3), (0x11, 7, 4, -1), (0x07, 10, 4, -2), + (0x13, 7, 5, -1), (0x5D, 12, 5, -2), (0x12, 7, 6, -1), (0x5C, 12, 6, -2), + (0x14, 8, 7, -1), (0x5B, 12, 7, -2), (0x15, 8, 8, -1), (0x1A, 8, 9, -1), + (0x19, 8, 10, -1), (0x18, 8, 11, -1), (0x17, 8, 12, -1), (0x16, 8, 13, -1), + (0x19, 9, 14, -1), (0x15, 9, 15, -1), (0x16, 9, 16, -1), (0x18, 9, 17, -1), + (0x17, 9, 18, -1), (0x04, 11, 19, -1), (0x05, 11, 20, -1), (0x58, 12, 21, -1), + (0x59, 12, 22, -1), (0x5A, 12, 23, -1), (0x03, 7, 0, 0) +); + +pub struct H263RLCodeReader { tab: &'static [H263RLCodeDesc] } + +impl H263RLCodeReader { + pub fn new(tab: &'static [H263RLCodeDesc]) -> Self { H263RLCodeReader { tab: tab } } +} + +impl CodebookDescReader for H263RLCodeReader { + fn bits(&mut self, idx: usize) -> u8 { self.tab[idx].bits } + fn code(&mut self, idx: usize) -> u32 { self.tab[idx].code as u32 } + fn sym (&mut self, idx: usize) -> H263RLSym { self.tab[idx].sym } + fn len(&mut self) -> usize { self.tab.len() } +} + diff --git a/src/codecs/intel263.rs b/src/codecs/intel263.rs new file mode 100644 index 0000000..bb20262 --- /dev/null +++ b/src/codecs/intel263.rs @@ -0,0 +1,452 @@ +use io::bitreader::*; +use io::codebook::*; +use formats; +use super::*; +use super::blockdec::*; +use super::h263data::*; + +#[allow(dead_code)] +struct Tables { + intra_mcbpc_cb: Codebook, + inter_mcbpc_cb: Codebook, + cbpy_cb: Codebook, + rl_cb: Codebook, + aic_rl_cb: Codebook, + mv_cb: Codebook, +} + +struct Intel263Decoder { + info: Rc, + dec: DCT8x8VideoDecoder, + tables: Tables, +} + +struct Intel263BR<'a> { + br: BitReader<'a>, + tables: &'a Tables, + gob_no: usize, + mb_w: usize, + is_pb: bool, +} + +fn check_marker<'a>(br: &mut BitReader<'a>) -> DecoderResult<()> { + let mark = br.read(1)?; + validate!(mark == 1); + Ok(()) +} + +impl<'a> Intel263BR<'a> { + fn new(src: &'a [u8], tables: &'a Tables) -> Self { + Intel263BR { + br: BitReader::new(src, src.len(), BitReaderMode::BE), + tables: tables, + gob_no: 0, + mb_w: 0, + is_pb: false, + } + } + + fn decode_block(&mut self, quant: u8, intra: bool, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> { + let mut br = &mut self.br; + let mut idx = 0; + if intra { + let mut dc = br.read(8)?; + if dc == 255 { dc = 128; } + blk[0] = (dc as i16) << 3; + idx = 1; + } + if !coded { return Ok(()); } + + let rl_cb = &self.tables.rl_cb; // could be aic too + let q_add = if quant == 0 { 0i16 } else { ((quant - 1) | 1) as i16 }; + let q = (quant * 2) as i16; + while idx < 64 { + let code = br.read_cb(rl_cb)?; + let run; + let mut level; + let last; + if !code.is_escape() { + run = code.get_run(); + level = code.get_level(); + last = code.is_last(); + if br.read_bool()? { level = -level; } + level = (level * q) + q_add; + } else { + last = br.read_bool()?; + run = br.read(6)? as u8; + level = br.read_s(8)? as i16; + if level == -128 { + let low = br.read(5)? as i16; + let top = br.read_s(6)? as i16; + level = (top << 5) | low; + } + level = (level * q) + q_add; + if level < -2048 { level = -2048; } + if level > 2047 { level = 2047; } + } + idx += run; + validate!(idx < 64); + let oidx = H263_ZIGZAG[idx as usize]; + blk[oidx] = level; + idx += 1; + if last { break; } + } + Ok(()) + } +} + +fn decode_mv_component(br: &mut BitReader, mv_cb: &Codebook) -> DecoderResult { + let code = br.read_cb(mv_cb)? as i16; + if code == 0 { return Ok(0) } + if !br.read_bool()? { + Ok(code) + } else { + Ok(-code) + } +} + +fn decode_mv(br: &mut BitReader, mv_cb: &Codebook) -> DecoderResult { + let xval = decode_mv_component(br, mv_cb)?; + let yval = decode_mv_component(br, mv_cb)?; + Ok(MV::new(xval, yval)) +} + +impl<'a> BlockDecoder for Intel263BR<'a> { + +#[allow(unused_variables)] + fn decode_pichdr(&mut self) -> DecoderResult { + let mut br = &mut self.br; + let syncw = br.read(22)?; + validate!(syncw == 0x000020); + let tr = br.read(8)? as u8; + check_marker(br)?; + let id = br.read(1)?; + validate!(id == 0); + br.read(1)?; // split screen indicator + br.read(1)?; // document camera indicator + br.read(1)?; // freeze picture release + let mut sfmt = br.read(3)?; + validate!((sfmt != 0b000) && (sfmt != 0b110)); + let is_intra = !br.read_bool()?; + let umv = br.read_bool()?; + br.read(1)?; // syntax arithmetic coding + let apm = br.read_bool()?; + self.is_pb = br.read_bool()?; + if sfmt == 0b111 { + sfmt = br.read(3)?; + validate!((sfmt != 0b000) && (sfmt != 0b111)); + br.read(2)?; // unknown flags + let 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); + } + let w; let h; + if sfmt == 0b110 { + let par = br.read(4)?; + w = ((br.read(9)? + 1) * 4) as usize; + check_marker(br)?; + h = ((br.read(9)? + 1) * 4) as usize; + if par == 0b1111 { + let pixw = br.read(8)?; + let pixh = br.read(8)?; + validate!((pixw != 0) && (pixh != 0)); + } + } else { + let (w_, h_) = H263_SIZES[sfmt as usize]; + w = w_; + h = h_; + } + let quant = br.read(5)?; + let cpm = br.read_bool()?; + validate!(!cpm); + if self.is_pb { + let trb = br.read(3)?; + let dbquant = br.read(2)?; + } + while br.read_bool()? { // skip PEI + br.read(8)?; + } +println!("frame {}x{} intra: {} q {} pb {} apm {} umv {} @{}", w, h, is_intra, quant, self.is_pb, apm, umv, br.tell()); + self.gob_no = 0; + 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, self.is_pb, tr); + Ok(picinfo) + } + + #[allow(unused_variables)] + fn decode_slice_header(&mut self, info: &PicInfo) -> DecoderResult { + let mut br = &mut self.br; + let gbsc = br.read(17)?; +println!("GBSC = {}", gbsc); + validate!(gbsc == 1); + let gn = br.read(5)?; + let gfid = br.read(2)?; + let gquant = br.read(5)?; +println!("GOB gn {:X} id {} q {}", gn, gfid, gquant); + let ret = Slice::new(0, self.gob_no, gquant as u8); + self.gob_no += 1; + Ok(ret) + } + + fn decode_block_header(&mut self, info: &PicInfo, slice: &Slice) -> DecoderResult { + let mut br = &mut self.br; + let mut q = slice.get_quant(); + match info.get_mode() { + Type::I => { + let mut cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?; + while cbpc == 8 { cbpc = br.read_cb(&self.tables.intra_mcbpc_cb)?; } + let cbpy = br.read_cb(&self.tables.cbpy_cb)?; + let cbp = (cbpy << 2) | (cbpc & 3); + let dquant = (cbpc & 4) != 0; + if dquant { + let idx = br.read(2)? as usize; + q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8; + } +//println!("got cbp {:X}", cbp); + Ok(BlockInfo::new(Type::I, cbp, q)) + }, + Type::P => { +//println!("@{}",br.tell()); + if br.read_bool()? { return Ok(BlockInfo::new(Type::Skip, 0, info.get_quant())); } + let mut cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?; + while cbpc == 20 { cbpc = br.read_cb(&self.tables.inter_mcbpc_cb)?; } + let is_intra = (cbpc & 0x04) != 0; + let dquant = (cbpc & 0x08) != 0; + let is_4x4 = (cbpc & 0x10) != 0; + if is_intra { + let mut mvec: Vec = Vec::new(); + let cbpb; + let pb_mv_count: usize; + if self.is_pb && br.read_bool()? { + let c = br.read_bool()?; + if c { + pb_mv_count = 2 - (br.read(1)? as usize); + cbpb = br.read(6)? as u8; + } else { + pb_mv_count = 2; + cbpb = 0; + } +//println!(" mvc {} cbpb {:02X}", pb_mv_count, cbpb); + } else { + cbpb = 0; + pb_mv_count = 1; + } + let cbpy = br.read_cb(&self.tables.cbpy_cb)?; + let cbp = (cbpy << 2) | (cbpc & 3); + if dquant { + let idx = br.read(2)? as usize; + q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8; + } + let mut binfo = BlockInfo::new(Type::I, cbp, q); + if self.is_pb { + for _ in 0..pb_mv_count { + mvec.push(decode_mv(br, &self.tables.mv_cb)?); + } + binfo.set_mv2(cbpb, mvec.as_slice()); + } +//println!("@{}",br.tell()); + return Ok(binfo); + } + + let cbpb; + let pb_mv_count: usize; + if self.is_pb && br.read_bool()?{ + let c = br.read_bool()?; + if c { + pb_mv_count = 1 - (br.read(1)? as usize); + cbpb = br.read(6)? as u8; + } else { + pb_mv_count = 1; + cbpb = 0; + } + } else { + cbpb = 0; + pb_mv_count = 0; + } + let mut cbpy = br.read_cb(&self.tables.cbpy_cb)?; +// if /* !aiv && */(cbpc & 3) != 3 { + cbpy ^= 0xF; +// } + let cbp = (cbpy << 2) | (cbpc & 3); + if dquant { + let idx = br.read(2)? as usize; + q = ((q as i16) + (H263_DQUANT_TAB[idx] as i16)) as u8; + } + let mut binfo = BlockInfo::new(Type::P, cbp, q); + if !is_4x4 { + let mvec: [MV; 1] = [decode_mv(br, &self.tables.mv_cb)?]; +//println!("@{} CBPB = {:X} mv2 {}",br.tell(), cbpb, pb_mv_count); + binfo.set_mv(&mvec); + } else { + let mvec: [MV; 4] = [ + decode_mv(br, &self.tables.mv_cb)?, + decode_mv(br, &self.tables.mv_cb)?, + decode_mv(br, &self.tables.mv_cb)?, + decode_mv(br, &self.tables.mv_cb)? + ]; + binfo.set_mv(&mvec); + } + if self.is_pb { + let mut mvec: Vec = Vec::with_capacity(pb_mv_count); + for _ in 0..pb_mv_count { + let mv = decode_mv(br, &self.tables.mv_cb)?; + mvec.push(mv); + } + binfo.set_mv2(cbpb, mvec.as_slice()); + } +//println!("@{}",br.tell()); + Ok(binfo) + }, + _ => { Err(DecoderError::InvalidData) }, + } + } + + #[allow(unused_variables)] + fn decode_block_intra(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> { + self.decode_block(info.get_q(), true, coded, blk) + } + + #[allow(unused_variables)] + fn decode_block_inter(&mut self, info: &BlockInfo, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> { + self.decode_block(info.get_q(), 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 } +} + +impl Intel263Decoder { + fn new() -> Self { + let mut coderead = H263ShortCodeReader::new(H263_INTRA_MCBPC); + let intra_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263ShortCodeReader::new(H263_INTER_MCBPC); + let inter_mcbpc_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263ShortCodeReader::new(H263_CBPY); + let cbpy_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263RLCodeReader::new(H263_RL_CODES); + let rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263RLCodeReader::new(H263_RL_CODES_AIC); + let aic_rl_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let mut coderead = H263ShortCodeReader::new(H263_MV); + let mv_cb = Codebook::new(&mut coderead, CodebookMode::MSB).unwrap(); + let tables = Tables { + intra_mcbpc_cb: intra_mcbpc_cb, + inter_mcbpc_cb: inter_mcbpc_cb, + cbpy_cb: cbpy_cb, + rl_cb: rl_cb, + aic_rl_cb: aic_rl_cb, + mv_cb: mv_cb, + }; + + Intel263Decoder{ + info: Rc::new(DUMMY_CODEC_INFO), + dec: DCT8x8VideoDecoder::new(), + tables: tables, + } + } +} + +impl NADecoder for Intel263Decoder { + fn init(&mut self, info: Rc) -> DecoderResult<()> { + if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { + let w = vinfo.get_width(); + let h = vinfo.get_height(); + let fmt = formats::YUV420_FORMAT; + let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, false, fmt)); + self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata())); + Ok(()) + } else { + Err(DecoderError::InvalidData) + } + } + fn decode(&mut self, pkt: &NAPacket) -> DecoderResult { + let src = pkt.get_buffer(); + + if src.len() == 8 { + let bret = self.dec.get_stored_pframe(); + let buftype; + let is_skip; + if let Ok(btype) = bret { + buftype = btype; + is_skip = false; + } else { + buftype = NABufferType::None; + is_skip = true; + } + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), buftype); + frm.set_keyframe(false); + frm.set_frame_type(if is_skip { FrameType::Skip } else { FrameType::P }); + return Ok(Rc::new(RefCell::new(frm))); + } +//println!("frame size {}", src.len()); + let mut ibr = Intel263BR::new(&src, &self.tables); + + let bufinfo = self.dec.parse_frame(&mut ibr)?; + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo); + frm.set_keyframe(self.dec.is_intra()); + frm.set_frame_type(if self.dec.is_intra() { FrameType::I } else { FrameType::P }); + Ok(Rc::new(RefCell::new(frm))) + } +} + + +pub fn get_decoder() -> Box { + Box::new(Intel263Decoder::new()) +} + +#[cfg(test)] +mod test { + use codecs::*; + use demuxers::*; + use io::byteio::*; + + #[test] + fn test_intel263() { + let avi_dmx = find_demuxer("avi").unwrap(); + let mut file = File::open("assets/neal73_saber.avi").unwrap(); + let mut fr = FileReader::new_read(&mut file); + let mut br = ByteReader::new(&mut fr); + let mut dmx = avi_dmx.new_demuxer(&mut br); + dmx.open().unwrap(); + + let mut decs: Vec>> = Vec::new(); + for i in 0..dmx.get_num_streams() { + let s = dmx.get_stream(i).unwrap(); + let info = s.get_info(); + let decfunc = find_decoder(info.get_name()); + if let Some(df) = decfunc { + let mut dec = (df)(); + dec.init(info).unwrap(); + decs.push(Some(dec)); + } else { + decs.push(None); + } + } + + loop { + let pktres = dmx.get_frame(); + if let Err(e) = pktres { + if e == DemuxerError::EOF { break; } + panic!("error"); + } + let pkt = pktres.unwrap(); + //if pkt.get_pts().unwrap() > 263 { break; } + let streamno = pkt.get_stream().get_id() as usize; + if let Some(ref mut dec) = decs[streamno] { + let frm = dec.decode(&pkt).unwrap(); + if pkt.get_stream().get_info().is_video() { + write_pgmyuv("ih263_", streamno, pkt.get_pts().unwrap(), frm); + } + } + } +//panic!("THE END"); + } +} diff --git a/src/codecs/mod.rs b/src/codecs/mod.rs index 625485e..ec67a4d 100644 --- a/src/codecs/mod.rs +++ b/src/codecs/mod.rs @@ -17,7 +17,7 @@ pub enum DecoderError { Bug, } -type DecoderResult = Result; +pub type DecoderResult = Result; impl From for DecoderError { fn from(_: ByteIOError) -> Self { DecoderError::ShortData } @@ -36,6 +36,15 @@ impl From for DecoderError { fn from(_: CodebookError) -> Self { DecoderError::InvalidData } } +macro_rules! validate { + ($a:expr) => { if !$a { return Err(DecoderError::InvalidData); } }; +} + +mod blockdsp; +mod blockdec; +mod h263code; +mod h263data; + #[allow(dead_code)] struct HAMShuffler { lastframe: Option>, @@ -104,16 +113,14 @@ pub struct DecoderInfo { get_decoder: fn () -> Box, } -macro_rules! validate { - ($a:expr) => { if !$a { return Err(DecoderError::InvalidData); } }; -} - #[cfg(feature="decoder_gdvvid")] mod gremlinvideo; #[cfg(feature="decoder_indeo2")] mod indeo2; #[cfg(feature="decoder_indeo3")] mod indeo3; + +mod intel263; #[cfg(feature="decoder_pcm")] mod pcm; @@ -125,6 +132,8 @@ const DECODERS: &[DecoderInfo] = &[ #[cfg(feature="decoder_indeo3")] DecoderInfo { name: "indeo3", get_decoder: indeo3::get_decoder }, + DecoderInfo { name: "intel263", get_decoder: intel263::get_decoder }, + #[cfg(feature="decoder_pcm")] DecoderInfo { name: "pcm", get_decoder: pcm::get_decoder }, ]; @@ -147,6 +156,7 @@ use std::io::prelude::*; #[allow(dead_code)] fn write_pgmyuv(pfx: &str, strno: usize, num: u64, frmref: NAFrameRef) { let frm = frmref.borrow(); + if let NABufferType::None = frm.get_buffer() { return; } let name = format!("assets/{}out{:02}_{:04}.pgm", pfx, strno, num); let mut ofile = File::create(name).unwrap(); let buf = frm.get_buffer().get_vbuf().unwrap();