X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-commonfmt%2Fsrc%2Fcodecs%2Fclearvideo.rs;h=731f8485213a3a16ce99edf92b813b2e9e73b4b3;hb=886cde4847280b96e10d240c2f2d76abec121dc8;hp=67a98639e855b90fb8a4d06cf93df50bd9627bf1;hpb=01613464323864a655c994820d3c43df1954e3b2;p=nihav.git diff --git a/nihav-commonfmt/src/codecs/clearvideo.rs b/nihav-commonfmt/src/codecs/clearvideo.rs index 67a9863..731f848 100644 --- a/nihav-commonfmt/src/codecs/clearvideo.rs +++ b/nihav-commonfmt/src/codecs/clearvideo.rs @@ -3,8 +3,7 @@ use nihav_core::io::bitreader::*; use nihav_core::io::codebook::*; use nihav_core::formats; use nihav_core::codecs::*; -use std::fmt; -use std::ops::{Add, Sub}; +use nihav_codec_support::codecs::{HAMShuffler, MV, ZERO_MV, ZIGZAG}; struct CLVDCCodeReader { } struct CLVACCodeReader { } @@ -13,28 +12,28 @@ struct CLVSym16CodeReader { codes: &'static [u16], bits: &'static [u8], syms: &' impl CodebookDescReader for CLVDCCodeReader { fn bits(&mut self, idx: usize) -> u8 { CLV_DC_BITS[idx] } - fn code(&mut self, idx: usize) -> u32 { CLV_DC_CODES[idx] as u32 } + fn code(&mut self, idx: usize) -> u32 { u32::from(CLV_DC_CODES[idx]) } fn sym (&mut self, idx: usize) -> i8 { (idx as i8) - 63 } fn len(&mut self) -> usize { CLV_DC_BITS.len() } } impl CodebookDescReader for CLVACCodeReader { fn bits(&mut self, idx: usize) -> u8 { CLV_AC_BITS[idx] } - fn code(&mut self, idx: usize) -> u32 { CLV_AC_CODES[idx] as u32 } + fn code(&mut self, idx: usize) -> u32 { u32::from(CLV_AC_CODES[idx]) } fn sym (&mut self, idx: usize) -> u16 { CLV_AC_SYMS[idx] } fn len(&mut self) -> usize { CLV_AC_BITS.len() } } impl CodebookDescReader for CLVFlagsCodeReader { fn bits(&mut self, idx: usize) -> u8 { self.bits[idx] } - fn code(&mut self, idx: usize) -> u32 { self.codes[idx] as u32 } + fn code(&mut self, idx: usize) -> u32 { u32::from(self.codes[idx]) } fn sym (&mut self, idx: usize) -> u8 { idx as u8 } fn len(&mut self) -> usize { self.bits.len() } } impl CodebookDescReader for CLVSym16CodeReader { fn bits(&mut self, idx: usize) -> u8 { self.bits[idx] } - fn code(&mut self, idx: usize) -> u32 { self.codes[idx] as u32 } + fn code(&mut self, idx: usize) -> u32 { u32::from(self.codes[idx]) } fn sym (&mut self, idx: usize) -> u16 { self.syms[idx] } fn len(&mut self) -> usize { self.bits.len() } } @@ -53,83 +52,24 @@ impl LevelCodes { mvd: Option<(&'static [u8], &'static [u16], &'static [u16])>, mv_esc: u16, bias: Option<(&'static [u8], &'static [u16], &'static [u16])>, bias_esc: u16) -> Self { let flags_cb = if let Some((bits, codes)) = flgd { - let mut coderead = CLVFlagsCodeReader { bits: bits, codes: codes }; + let mut coderead = CLVFlagsCodeReader { bits, codes }; Some(Codebook::new(&mut coderead, CodebookMode::MSB).unwrap()) } else { None }; let mv_cb = if let Some((bits, codes, syms)) = mvd { - let mut coderead = CLVSym16CodeReader { bits: bits, codes: codes, syms: syms }; + let mut coderead = CLVSym16CodeReader { bits, codes, syms }; Some(Codebook::new(&mut coderead, CodebookMode::MSB).unwrap()) } else { None }; let bias_cb = if let Some((bits, codes, syms)) = bias { - let mut coderead = CLVSym16CodeReader { bits: bits, codes: codes, syms: syms }; + let mut coderead = CLVSym16CodeReader { bits, codes, syms }; Some(Codebook::new(&mut coderead, CodebookMode::MSB).unwrap()) } else { None }; - LevelCodes { flags_cb: flags_cb, mv_cb: mv_cb, mv_esc: mv_esc, bias_cb: bias_cb, bias_esc: bias_esc } - } -} - -#[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 } - } -} - -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 } } -} - -impl Sub for MV { - type Output = MV; - fn sub(self, other: MV) -> MV { MV { x: self.x - other.x, y: self.y - other.y } } -} - -impl fmt::Display for MV { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{},{}", self.x, self.y) + LevelCodes { flags_cb, mv_cb, mv_esc, bias_cb, bias_esc } } } @@ -208,8 +148,8 @@ fn dct_row(blk: &mut [i32]) { let t7 = ((blk[0] - blk[4]) << dshift) + (1 << (shift - 1)); let t8 = t0 + t2; let t9 = t0 - t2; - let tA = 181 * (t9 + (t1 - t3)) + 0x80 >> 8; - let tB = 181 * (t9 - (t1 - t3)) + 0x80 >> 8; + let tA = (181 * (t9 + (t1 - t3)) + 0x80) >> 8; + let tB = (181 * (t9 - (t1 - t3)) + 0x80) >> 8; let tC = t1 + t3; blk[0] = (t6 + t5 + t8) >> shift; @@ -223,6 +163,8 @@ fn dct_row(blk: &mut [i32]) { } #[allow(non_snake_case)] +#[allow(clippy::erasing_op)] +#[allow(clippy::identity_op)] fn dct_col(blk: &mut [i32; 64], col: usize) { let dshift = 8; let shift = 14; @@ -236,8 +178,8 @@ fn dct_col(blk: &mut [i32; 64], col: usize) { let t7 = ((blk[0*8 + col] - blk[4*8 + col]) << dshift) + (1 << (shift - 1)); let t8 = t0 + t2; let t9 = t0 - t2; - let tA = 181 * (t9 + (t1 - t3)) + 0x80 >> 8; - let tB = 181 * (t9 - (t1 - t3)) + 0x80 >> 8; + let tA = (181 * (t9 + (t1 - t3)) + 0x80) >> 8; + let tB = (181 * (t9 - (t1 - t3)) + 0x80) >> 8; let tC = t1 + t3; blk[0*8 + col] = (t6 + t5 + t8) >> shift; @@ -257,7 +199,7 @@ fn clv_dct(blk: &mut [i32; 64]) { fn clv_dct_dc(blk: &mut [i32; 64]) { let dval = blk[0] >> 3; - for i in 0..64 { blk[i] = dval; } + for el in blk.iter_mut() { *el = dval; } } fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i32;64]; 6]) { @@ -274,12 +216,12 @@ fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i32 for j in 0..8 { for k in 0..8 { let mut v = blk[0][k + j * 8] + 128; - if v < 0 { v = 0; } if v > 255 { v = 255; } + if v < 0 { v = 0; } else if v > 255 { v = 255; } framebuf[idxy + k] = v as u8; } for k in 0..8 { let mut v = blk[1][k + j * 8] + 128; - if v < 0 { v = 0; } if v > 255 { v = 255; } + if v < 0 { v = 0; } else if v > 255 { v = 255; } framebuf[idxy + k + 8] = v as u8; } idxy += stridey; @@ -287,12 +229,12 @@ fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i32 for j in 0..8 { for k in 0..8 { let mut v = blk[2][k + j * 8] + 128; - if v < 0 { v = 0; } if v > 255 { v = 255; } + if v < 0 { v = 0; } else if v > 255 { v = 255; } framebuf[idxy + k] = v as u8; } for k in 0..8 { let mut v = blk[3][k + j * 8] + 128; - if v < 0 { v = 0; } if v > 255 { v = 255; } + if v < 0 { v = 0; } else if v > 255 { v = 255; } framebuf[idxy + k + 8] = v as u8; } idxy += stridey; @@ -301,12 +243,12 @@ fn put_blocks(buf: &mut NAVideoBuffer, xpos: usize, ypos: usize, blk: &[[i32 for j in 0..8 { for k in 0..8 { let mut v = blk[4][k + j * 8] + 128; - if v < 0 { v = 0; } if v > 255 { v = 255; } + if v < 0 { v = 0; } else if v > 255 { v = 255; } framebuf[idxu + k] = v as u8; } for k in 0..8 { let mut v = blk[5][k + j * 8] + 128; - if v < 0 { v = 0; } if v > 255 { v = 255; } + if v < 0 { v = 0; } else if v > 255 { v = 255; } framebuf[idxv + k] = v as u8; } idxu += strideu; @@ -355,7 +297,7 @@ fn copyadd_block(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, let dst = &mut dbuf[doff..][..size]; let src = &sbuf[soff..][..size]; for i in 0..size { - let val = (src[i] as i16) + bias; + let val = i16::from(src[i]) + bias; if val < 0x00 { dst[i] = 0x00; } else if val > 0xFF { dst[i] = 0xFF; } else { dst[i] = val as u8; } @@ -365,6 +307,90 @@ fn copyadd_block(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, } } +fn copy_block_w(dst: &mut WFrame, src: &NAVideoBuffer, + plane: usize, x: usize, y: usize, dx: isize, dy: isize, + size: usize, weights: &[[Vec; 9]]) +{ + let sx: isize = (x as isize) + dx; + let sy: isize = (y as isize) + dy; + + let (w, h) = src.get_dimensions(plane); + let sstride = src.get_stride(plane); + let mut soff = src.get_offset(plane) + (sx as usize) + (sy as usize) * sstride; + let sdta = src.get_data(); + let sbuf: &[u8] = sdta.as_slice(); + let dstride = dst.stride[plane]; + let mut doff = x + y * dstride; + let dbuf = &mut dst.data[plane]; + + let m1 = if x > 0 { if x + size < w { 0 } else { 2 } } else { 1 }; + let m0 = if y > 0 { if y + size < h { 0 } else { 2 } } else { 1 }; + let weight = &weights[size.trailing_zeros() as usize][m0 * 3 + m1]; + let blk_w = if m1 != 0 { size + 1 } else { size + 2 }; + let blk_h = if m0 != 0 { size + 1 } else { size + 2 }; + if m1 != 1 { + soff -= 1; + doff -= 1; + } + if m0 != 1 { + soff -= sstride; + doff -= dstride; + } + + let mut cur_w = weight.iter(); + for _y in 0..blk_h { + for x in 0..blk_w { + let scale = u32::from(*cur_w.next().unwrap()); + let src = u32::from(sbuf[soff + x]); + dbuf[doff + x] += scale | ((src * scale) << 8); + } + soff += sstride; + doff += dstride; + } +} + +fn copyadd_block_w(dst: &mut WFrame, src: &NAVideoBuffer, + plane: usize, x: usize, y: usize, dx: isize, dy: isize, + size: usize, bias: i16, weights: &[[Vec; 9]]) +{ + let sx: isize = (x as isize) + dx; + let sy: isize = (y as isize) + dy; + + let (w, h) = src.get_dimensions(plane); + let sstride = src.get_stride(plane); + let mut soff = src.get_offset(plane) + (sx as usize) + (sy as usize) * sstride; + let sdta = src.get_data(); + let sbuf: &[u8] = sdta.as_slice(); + let dstride = dst.stride[plane]; + let mut doff = x + y * dstride; + let dbuf = &mut dst.data[plane]; + + let m1 = if x > 0 { if x + size < w { 0 } else { 2 } } else { 1 }; + let m0 = if y > 0 { if y + size < h { 0 } else { 2 } } else { 1 }; + let weight = &weights[size.trailing_zeros() as usize][m0 * 3 + m1]; + let blk_w = if m1 != 0 { size + 1 } else { size + 2 }; + let blk_h = if m0 != 0 { size + 1 } else { size + 2 }; + if m1 != 1 { + soff -= 1; + doff -= 1; + } + if m0 != 1 { + soff -= sstride; + doff -= dstride; + } + + let mut cur_w = weight.iter(); + for _y in 0..blk_h { + for x in 0..blk_w { + let scale = u32::from(*cur_w.next().unwrap()); + let val = (i16::from(sbuf[soff + x]) + bias).max(0).min(255) as u32; + dbuf[doff + x] += scale | ((val * scale) << 8); + } + soff += sstride; + doff += dstride; + } +} + fn tile_do_block(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, plane: usize, x: usize, y: usize, dx: i16, dy: i16, size: usize, bias: i16) { @@ -375,6 +401,16 @@ fn tile_do_block(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, } } +fn tile_do_block_w(dst: &mut WFrame, src: &NAVideoBuffer, + plane: usize, x: usize, y: usize, dx: i16, dy: i16, size: usize, bias: i16, weights: &[[Vec; 9]]) +{ + if bias == 0 { + copy_block_w(dst, src, plane, x, y, dx as isize, dy as isize, size, weights); + } else { + copyadd_block_w(dst, src, plane, x, y, dx as isize, dy as isize, size, bias, weights); + } +} + fn restore_tree(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, plane: usize, x: usize, y: usize, size: usize, tile: &TileInfo, root_mv: MV) { let mv = root_mv + tile.mv; @@ -396,6 +432,27 @@ fn restore_tree(dst: &mut NAVideoBuffer, src: &NAVideoBuffer, plane: usi } } +fn restore_tree_weighted(dst: &mut WFrame, src: &NAVideoBuffer, plane: usize, + x: usize, y: usize, size: usize, tile: &TileInfo, root_mv: MV, weights: &[[Vec; 9]]) { + let mv = root_mv + tile.mv; + + if tile.flags == 0 { + tile_do_block_w(dst, src, plane, x, y, mv.x, mv.y, size, tile.bias, weights); + } else { + let hsize = size >> 1; + for i in 0..4 { + let xoff = if (i & 2) == 0 { 0 } else { hsize }; + let yoff = if (i & 1) == 0 { 0 } else { hsize }; + + if let Some(ref subtile) = tile.child[i] { + restore_tree_weighted(dst, src, plane, x + xoff, y + yoff, hsize, subtile, root_mv, weights); + } else { + tile_do_block_w(dst, src, plane, x + xoff, y + yoff, mv.x, mv.y, hsize, tile.bias, weights); + } + } + } +} + fn extend_edges(buf: &mut NAVideoBuffer, tile_size: usize) { for comp in 0..3 { let (w, h) = buf.get_dimensions(comp); @@ -426,17 +483,70 @@ fn extend_edges(buf: &mut NAVideoBuffer, tile_size: usize) { } } +#[derive(Default)] +struct WFrame { + data: [Vec; 3], + stride: [usize; 3], +} + +impl WFrame { + fn new() -> Self { Self::default() } + fn resize(&mut self, w: usize, h: usize, align: u8) { + let mask = (1 << align) - 1; + let wa = (w + mask) & !mask; + let ha = (h + mask) & !mask; + self.data[0].resize(wa * ha, 0); + self.stride[0] = wa; + self.data[1].resize(wa / 2 * ha / 2, 0); + self.stride[1] = wa / 2; + self.data[2].resize(wa / 2 * ha / 2, 0); + self.stride[2] = wa / 2; + } + fn clear(&mut self) { + for plane in self.data.iter_mut() { + for el in plane.iter_mut() { + *el = 0; + } + } + } + fn output(&self, buf: &mut NAVideoBuffer) { + for plane in 0..3 { + let (w, h) = buf.get_dimensions(plane); + let dstride = buf.get_stride(plane); + let doff = buf.get_offset(plane); + let ddta = buf.get_data_mut().unwrap(); + for (dst, src) in ddta[doff..].chunks_mut(dstride).take(h).zip(self.data[plane].chunks(self.stride[plane])) { + for (dst, &src) in dst.iter_mut().take(w).zip(src.iter()) { + let scale = src & 0xFF; + *dst = if scale == 0 { + 0 + } else if scale == 16 { // common case + (src >> 12) as u8 + } else { + let val = src >> 8; + (val / scale) as u8 + }; + } + } + } + } +} + #[allow(dead_code)] struct ClearVideoDecoder { info: NACodecInfoRef, dc_cb: Codebook, ac_cb: Codebook, - frmmgr: HAMShuffler, + frmmgr: HAMShuffler, is_rm: bool, ylev: [LevelCodes; 4], ulev: [LevelCodes; 3], vlev: [LevelCodes; 3], tsize: u8, + + weighted: bool, + weights: Vec<[Vec; 9]>, + wframe: WFrame, } fn decode_dct_block(br: &mut BitReader, blk: &mut [i32; 64], ac_quant: i32, has_ac: bool, @@ -444,7 +554,7 @@ fn decode_dct_block(br: &mut BitReader, blk: &mut [i32; 64], ac_quant: i32, has_ let mut idx = 1; let mut eob = false; - blk[0] = br.read_cb(dc_cb)? as i32; + blk[0] = i32::from(br.read_cb(dc_cb)?); if !has_ac { return Ok(()); } @@ -453,7 +563,7 @@ fn decode_dct_block(br: &mut BitReader, blk: &mut [i32; 64], ac_quant: i32, has_ let (level, skip) = if val != CLV_AC_ESCAPE { eob = ((val >> 12) & 1) != 0; let run = ((val >> 4) & 0xFF) as usize; - let lev = (val & 0xF) as i32; + let lev = i32::from(val & 0xF); if br.read_bool()? { (-lev, run) } else { @@ -495,7 +605,7 @@ fn decode_tile_info(br: &mut BitReader, lc: &[LevelCodes], level: usize) -> Deco let mv = if let Some(ref cb) = lc[level].mv_cb { let mv_code = br.read_cb(cb)?; if mv_code != lc[level].mv_esc { - MV::new(((mv_code & 0xFF) as i8) as i16, (mv_code as i16) >> 8) + MV::new(i16::from((mv_code & 0xFF) as i8), (mv_code as i16) >> 8) } else { let x = br.read_s(8)? as i16; let y = br.read_s(8)? as i16; @@ -514,7 +624,7 @@ fn decode_tile_info(br: &mut BitReader, lc: &[LevelCodes], level: usize) -> Deco } else { 0 }; - let mut ti = TileInfo { flags: flags, mv: mv, bias: bias, child: [None, None, None, None] }; + let mut ti = TileInfo { flags, mv, bias, child: [None, None, None, None] }; if ti.flags != 0 { for i in 0..4 { if (ti.flags & (1 << i)) != 0 { @@ -536,9 +646,9 @@ impl ClearVideoDecoder { ClearVideoDecoder { info: dummy_info, - dc_cb: dc_cb, ac_cb: ac_cb, + dc_cb, ac_cb, frmmgr: HAMShuffler::new(), - is_rm: is_rm, + is_rm, ylev: [ LevelCodes::new(Some((CLV_FLAGSY_0_BITS, CLV_FLAGSY_0_CODES)), Some((CLV_MVY_0_BITS, CLV_MVY_0_CODES, CLV_MVY_0_SYMS)), CLV_MVY_0_ESCAPE, @@ -576,6 +686,10 @@ impl ClearVideoDecoder { Some((CLV_BIASV_2_BITS, CLV_BIASV_2_CODES, CLV_BIASV_2_SYMS)), CLV_BIAS_ESCAPE), ], tsize: 0, + + weighted: false, + weights: Vec::new(), + wframe: WFrame::new(), } } @@ -593,7 +707,7 @@ impl ClearVideoDecoder { let mut blks: [[i32; 64]; 6] = [[0; 64]; 6]; let mut has_ac: [bool; 6] = [false; 6]; - for i in 0..6 { has_ac[i] = br.read_bool()? } + for flag in has_ac.iter_mut() { *flag = br.read_bool()?; } for i in 0..4 { decode_dct_block(br, &mut blks[i], ac_quant, has_ac[i], &self.dc_cb, &self.ac_cb)?; @@ -643,6 +757,10 @@ impl ClearVideoDecoder { let mut mvi = MVInfo::new(); mvi.reset(mb_w, mb_h, mb_size); + if self.weighted { + self.wframe.clear(); + } + for t_y in 0..mb_h { for t_x in 0..mb_w { if !br.read_bool()? { @@ -651,7 +769,11 @@ impl ClearVideoDecoder { let size = 1 << self.tsize; let tile = decode_tile_info(br, &self.ylev, 0)?; let mv = mvi.predict(t_x, t_y, tile.mv); - restore_tree(buf, prev, 0, x, y, size, &tile, mv); + if !self.weighted { + restore_tree(buf, prev, 0, x, y, size, &tile, mv); + } else { + restore_tree_weighted(&mut self.wframe, prev, 0, x, y, size, &tile, mv, &self.weights); + } let x = t_x << (self.tsize - 1); let y = t_y << (self.tsize - 1); let size = 1 << (self.tsize - 1); @@ -659,9 +781,17 @@ impl ClearVideoDecoder { cmv.x /= 2; cmv.y /= 2; let tile = decode_tile_info(br, &self.ulev, 0)?; - restore_tree(buf, prev, 1, x, y, size, &tile, cmv); + if !self.weighted { + restore_tree(buf, prev, 1, x, y, size, &tile, cmv); + } else { + restore_tree_weighted(&mut self.wframe, prev, 1, x, y, size, &tile, cmv, &self.weights); + } let tile = decode_tile_info(br, &self.vlev, 0)?; - restore_tree(buf, prev, 2, x, y, size, &tile, cmv); + if !self.weighted { + restore_tree(buf, prev, 2, x, y, size, &tile, cmv); + } else { + restore_tree_weighted(&mut self.wframe, prev, 2, x, y, size, &tile, cmv, &self.weights); + } } else { let mv = mvi.predict(t_x, t_y, ZERO_MV); for plane in 0..3 { @@ -670,19 +800,86 @@ impl ClearVideoDecoder { let size = if plane == 0 { 1 << self.tsize } else { 1 << (self.tsize - 1) }; let mx = if plane == 0 { mv.x as isize } else { (mv.x >> 1) as isize }; let my = if plane == 0 { mv.y as isize } else { (mv.y >> 1) as isize }; - copy_block(buf, prev, plane, x, y, mx, my, size); + if !self.weighted { + copy_block(buf, prev, plane, x, y, mx, my, size); + } else { + copy_block_w(&mut self.wframe, prev, plane, x, y, mx, my, size, &self.weights); + } } } } mvi.update_row(); } + if self.weighted { + self.wframe.output(buf); + } Ok(()) } } +fn generate_weights(weights: &mut Vec<[Vec; 9]>, depth: u8) { + const WEIGHT2X2: [u8; 9] = [ 1, 2, 1, 2, 4, 2, 1, 2, 1]; + + for d in 0..=depth as usize { + let size = 1 << d; + let hsize = size >> 1; + let dsize = (size + 2) * (size + 2); + let mut cur_w = [Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize), Vec::with_capacity(dsize)]; + for m0 in 0..3 { + let h = if m0 == 0 { size + 2 } else { size + 1 }; + for m1 in 0..3 { + let w = if m1 == 0 { size + 2 } else { size + 1 }; + let idx = m0 * 3 + m1; + if idx == 0 { + if size == 1 { + cur_w[0].extend_from_slice(&WEIGHT2X2); + } else { + cur_w[0].resize(w * h, 0); + let mut idx0 = 0; + let mut idx1 = (size + 2) * hsize; + let mut ref_iter = weights[d - 1][0].iter(); + for _y in 0..(hsize + 2) { + for _x in 0..(hsize + 2) { + let ref_val = ref_iter.next().unwrap(); + cur_w[0][idx0] += ref_val; + cur_w[0][idx0 + hsize] += ref_val; + cur_w[0][idx1] += ref_val; + cur_w[0][idx1 + hsize] += ref_val; + idx0 += 1; + idx1 += 1; + } + idx0 += hsize; + idx1 += hsize; + } + } + } else { + cur_w[idx].resize(w * h, 0); + for y0 in 0..(size + 2) { + let y = match m0 { + 0 => y0, + 1 => y0.saturating_sub(1), + _ => y0.min(h - 1), + }; + for x0 in 0..(size + 2) { + let x = match m1 { + 0 => x0, + 1 => x0.saturating_sub(1), + _ => x0.min(w - 1), + }; + let ref_val = cur_w[0][x0 + y0 * (size + 2)]; + cur_w[idx][x + y * w] += ref_val; + } + } + } + } + } + weights.push(cur_w); + } +} + impl NADecoder for ClearVideoDecoder { + #[allow(clippy::or_fun_call)] fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> { - if info.get_extradata().is_none() { return Err(DecoderError::InvalidData); } if let NACodecTypeInfo::Video(vinfo) = info.get_properties() { let w = vinfo.get_width(); let h = vinfo.get_height(); @@ -691,9 +888,11 @@ impl NADecoder for ClearVideoDecoder { let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, fmt)); self.info = NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()).into_ref(); self.frmmgr.clear(); - let edata = info.get_extradata().unwrap(); + let edata = info.get_extradata().unwrap_or(std::sync::Arc::new(vec![])); //todo detect simply by extradata contents? - if !self.is_rm { + if edata.len() == 0 || edata.len() < 0x60 { // no or short extradata probably comes from MOV + self.tsize = 4; + } else if !self.is_rm { let mut mr = MemoryReader::new_read(edata.as_slice()); let mut br = ByteReader::new(&mut mr); br.read_skip(0x5E).unwrap(); @@ -706,6 +905,8 @@ impl NADecoder for ClearVideoDecoder { let tile_size = br.read_u32be()?; self.tsize = tile_size.trailing_zeros() as u8; } + generate_weights(&mut self.weights, self.tsize); + self.wframe.resize(w, h, self.tsize); Ok(()) } else { Err(DecoderError::InvalidData) @@ -729,13 +930,17 @@ impl NADecoder for ClearVideoDecoder { return Ok(frm.into_ref()); } + if (src[off] & 0xBF) == 5 { + // reset reference frame into grayscale + unimplemented!(); + } + self.weighted = (src[off] & 0x40) != 0; + let is_intra = (src[off] & 2) == 2; - let mut br = BitReader::new(&src[(off + 1)..], src.len() - (off + 1), BitReaderMode::BE); + let mut br = BitReader::new(&src[(off + 1)..], BitReaderMode::BE); let vinfo = self.info.get_properties().get_video_info().unwrap(); - let bufret = alloc_video_buffer(vinfo, self.tsize); - if let Err(_) = bufret { return Err(DecoderError::InvalidData); } - let bufinfo = bufret.unwrap(); + let bufinfo = alloc_video_buffer(vinfo, self.tsize)?; let mut buf = bufinfo.get_vbuf().unwrap(); if is_intra { @@ -744,7 +949,9 @@ impl NADecoder for ClearVideoDecoder { self.decode_frame_intra(&mut br, &mut buf, vinfo.get_width(), vinfo.get_height())?; extend_edges(&mut buf, 1 << self.tsize); } else { - let mut prev = self.frmmgr.clone_ref().unwrap(); + let pref = self.frmmgr.clone_ref(); + if pref.is_none() { return Err(DecoderError::MissingReference); } + let mut prev = pref.unwrap(); extend_edges(&mut prev, 1 << self.tsize); self.decode_frame_inter(&mut br, &mut buf, &mut prev, vinfo.get_width(), vinfo.get_height())?; extend_edges(&mut buf, 1 << self.tsize); @@ -759,13 +966,22 @@ impl NADecoder for ClearVideoDecoder { } Ok(frm.into_ref()) } + fn flush(&mut self) { + self.frmmgr.clear(); + } +} + +impl NAOptionHandler for ClearVideoDecoder { + fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] } + fn set_options(&mut self, _options: &[NAOption]) { } + fn query_option_value(&self, _name: &str) -> Option { None } } -pub fn get_decoder() -> Box { +pub fn get_decoder() -> Box { Box::new(ClearVideoDecoder::new(false)) } -pub fn get_decoder_rm() -> Box { +pub fn get_decoder_rm() -> Box { Box::new(ClearVideoDecoder::new(true)) } @@ -773,18 +989,60 @@ pub fn get_decoder_rm() -> Box { mod test { use nihav_core::codecs::RegisteredDecoders; use nihav_core::demuxers::RegisteredDemuxers; - use nihav_core::test::dec_video::test_file_decoding; - use crate::codecs::generic_register_all_codecs; - use crate::demuxers::generic_register_all_demuxers; + use nihav_codec_support::test::dec_video::*; + use crate::generic_register_all_decoders; + use crate::generic_register_all_demuxers; #[test] fn test_clv() { let mut dmx_reg = RegisteredDemuxers::new(); generic_register_all_demuxers(&mut dmx_reg); let mut dec_reg = RegisteredDecoders::new(); - generic_register_all_codecs(&mut dec_reg); - test_file_decoding("avi", "assets/Misc/TalkingHead_352x288.avi", Some(10), true, false, None/*Some("clv")*/, &dmx_reg, &dec_reg); -// test_file_decoding("avi", "assets/Misc/basketball.avi", None/*Some(10)*/, true, false, Some("clv1")); -//panic!("debug"); + generic_register_all_decoders(&mut dec_reg); + // sample: https://samples.mplayerhq.hu/V-codecs/UCOD/TalkingHead_352x288.avi + test_decoding("avi", "clearvideo", "assets/Misc/TalkingHead_352x288.avi", Some(10), &dmx_reg, + &dec_reg, ExpectedTestResult::MD5Frames(vec![ + [0xb432376c, 0xf1dce57b, 0x8e79c7ee, 0xdd51850d], + [0x76eb9726, 0x7ca1aabd, 0xf3f0740c, 0xf804dd0e], + [0xc639b32c, 0x1f53f1f4, 0x50c34651, 0xc49cd2ac], + [0x55408f2a, 0x37b01de0, 0xcc6aeadd, 0x09768735], + [0xea219c51, 0xed72710c, 0x6c4b2bb0, 0xbfab0cb7], + [0xfbf56708, 0x7f6597c7, 0x08ce894d, 0x9c4c7f60], + [0x3dbf8b57, 0x9e1513ef, 0x209309a6, 0x56f0aca7], + [0xc5fb6cb7, 0x1b9b092f, 0xe11127be, 0xe4fe8f45], + [0x81a4a122, 0xb2b84bcf, 0xa478bd80, 0x12c78fb6], + [0xb5b43c22, 0xd9c457fa, 0xcc5390d8, 0x1201ef22], + [0x27a206e9, 0x88085556, 0x1114fb62, 0x77f1ebed]])); + } + #[test] + fn test_clv_ovl() { + let mut dmx_reg = RegisteredDemuxers::new(); + generic_register_all_demuxers(&mut dmx_reg); + let mut dec_reg = RegisteredDecoders::new(); + generic_register_all_decoders(&mut dec_reg); + // sample: https://samples.mplayerhq.hu/V-codecs/UCOD/Nick%20Pope.avi + test_decoding("avi", "clearvideo", "assets/Misc/Nick Pope.avi", Some(20), &dmx_reg, + &dec_reg, ExpectedTestResult::MD5Frames(vec![ + [0xca265763, 0xd7d40e35, 0x1c27d4fb, 0xbb76b9c6], + [0x42b4728b, 0x8299e532, 0xd9307741, 0xa94003ea], + [0x065f605d, 0x0fcd6be9, 0x7acf00f5, 0xa153298a], + [0x2c1dea59, 0xfca62495, 0x36e87c82, 0xd9e151b5], + [0xa57764f6, 0x0ad30c15, 0x15e65687, 0x1e2b2359], + [0x3d0498ae, 0x3b8a7743, 0x04639817, 0xd7b14313], + [0xf41f3417, 0x8c542118, 0x4c762295, 0xfccc8a28], + [0xdac4a37f, 0x0b42a976, 0xd9b3dc8e, 0xff21062f], + [0x9078fac7, 0x69308953, 0x511942ff, 0x89139f72], + [0xd24c8e85, 0x6c7eda39, 0x07369927, 0x47dc3800], + [0xd5dd7838, 0x572d70d1, 0xae8a6631, 0xce7291b2], + [0x7ce11730, 0x344443c7, 0xa7502185, 0x8940f0c4], + [0x95f93bc1, 0x745b0e69, 0xd69c8208, 0x8bb5bf67], + [0x3b9cf626, 0x33206f48, 0x2314f65b, 0x7833981b], + [0x305578ee, 0x8824d091, 0x17c9510e, 0x2156ef06], + [0xc1efdeaa, 0x79bd6381, 0x5816a81a, 0x902a47d9], + [0xb7724ddb, 0x88dfe176, 0xf1eebfff, 0x16e500db], + [0x86c5972d, 0x9a437142, 0x87189dd7, 0xa92f6bb8], + [0xa60d9732, 0x3a570201, 0x499a5b4c, 0xf234426c], + [0x4f62d7ef, 0x33b3c1cc, 0x6e0fa443, 0x66abe9d0], + [0x7362b65a, 0xc064737b, 0x0e2d199d, 0xead4ca56]])); } } @@ -876,17 +1134,6 @@ const CLV_AC_BITS: &[u8] = &[ const CLV_AC_ESCAPE: u16 = 0x1BFF; -const 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 -]; - const CLV_BIAS_ESCAPE: u16 = 0x100; const CLV_MVY_0_BITS: &[u8] = &[