aboutsummaryrefslogtreecommitdiffstats
path: root/nihav-indeo/src/codecs
diff options
context:
space:
mode:
authorKostya Shishkov <kostya.shishkov@gmail.com>2019-01-17 12:25:49 +0100
committerKostya Shishkov <kostya.shishkov@gmail.com>2019-01-17 12:25:49 +0100
commit5641dccfbf2a70d589cf094a0d4ed5a10f919f00 (patch)
treeab444f3e91b46723187546b1b2820924fb332513 /nihav-indeo/src/codecs
parentb74ff9fac35d41737d71d97227fad233aa4a4b49 (diff)
downloadnihav-5641dccfbf2a70d589cf094a0d4ed5a10f919f00.tar.gz
split NihAV into subcrates
Diffstat (limited to 'nihav-indeo/src/codecs')
-rw-r--r--nihav-indeo/src/codecs/imc.rs1123
-rw-r--r--nihav-indeo/src/codecs/indeo2.rs378
-rw-r--r--nihav-indeo/src/codecs/indeo3.rs1463
-rw-r--r--nihav-indeo/src/codecs/indeo4.rs775
-rw-r--r--nihav-indeo/src/codecs/indeo5.rs729
-rw-r--r--nihav-indeo/src/codecs/intel263.rs423
-rw-r--r--nihav-indeo/src/codecs/ivi.rs287
-rw-r--r--nihav-indeo/src/codecs/ivibr.rs1293
-rw-r--r--nihav-indeo/src/codecs/ividsp.rs467
-rw-r--r--nihav-indeo/src/codecs/mod.rs50
10 files changed, 6988 insertions, 0 deletions
diff --git a/nihav-indeo/src/codecs/imc.rs b/nihav-indeo/src/codecs/imc.rs
new file mode 100644
index 0000000..5840846
--- /dev/null
+++ b/nihav-indeo/src/codecs/imc.rs
@@ -0,0 +1,1123 @@
+use std::mem;
+use std::ptr;
+use std::f32::consts;
+use std::rc::Rc;
+use std::cell::RefCell;
+
+use nihav_core::formats::*;
+use nihav_core::frame::*;
+use nihav_core::codecs::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_core::dsp::fft::*;
+use nihav_core::dsp::window::*;
+
+const BANDS: usize = 32;
+const COEFFS: usize = 256;
+const BLOCK_SIZE: usize = 64;
+
+struct IMDCTContext {
+ pretwiddle1: [f32; COEFFS/2],
+ pretwiddle2: [f32; COEFFS/2],
+ posttwiddle: [FFTComplex; COEFFS/2],
+ tmp: [FFTComplex; COEFFS/2],
+ fft: FFT,
+ window: [f32; COEFFS],
+}
+
+struct IMCChannel {
+ old_floor: [f32; BANDS],
+ new_floor: [f32; BANDS],
+ log_floor: [f32; BANDS],
+ log_floor2: [f32; BANDS],
+ bit_est: [f32; BANDS],
+ mask_wght: [f32; BANDS],
+ adj_floor: [f32; BANDS],
+ cw: [f32; COEFFS],
+ last_im: [f32; COEFFS/2],
+}
+
+struct BitAlloc {
+ band_width: [usize; BANDS],
+ band_present: [bool; BANDS],
+ band_skip: [bool; BANDS],
+ band_bits: [u8; BANDS],
+ cw_len: [u8; COEFFS],
+ band_bitsum: [usize; BANDS],
+ skip_flag: [bool; COEFFS],
+ skip_flag_bits: [u8; BANDS],
+ skips_per_band: [usize; BANDS],
+ keep_flag: [bool; BANDS],
+ coeff: [u8; COEFFS],
+}
+
+impl IMCChannel {
+ fn new() -> Self {
+ IMCChannel {
+ old_floor: [0.0; BANDS],
+ new_floor: [0.0; BANDS],
+ log_floor: [0.0; BANDS],
+ log_floor2: [0.0; BANDS],
+ bit_est: [0.0; BANDS],
+ mask_wght: [0.0; BANDS],
+ adj_floor: [0.0; BANDS],
+ cw: [0.0; COEFFS],
+ last_im: [0.0; COEFFS/2],
+ }
+ }
+ fn reset(&mut self) {
+ for i in 0..self.old_floor.len() { self.old_floor[i] = 1.0; }
+ for i in 0..self.cw.len() { self.cw[i] = 0.0; }
+ }
+}
+
+const BITALLOC_LIMIT: f32 = -1.0e20;
+const BITALLOC_TOP_LIMIT: f32 = 1.0e20;
+impl BitAlloc {
+ fn new() -> Self {
+ BitAlloc {
+ band_width: [0; BANDS],
+ band_present: [false; BANDS],
+ band_skip: [false; BANDS],
+ band_bits: [0; BANDS],
+ cw_len: [0; COEFFS],
+ band_bitsum: [0; BANDS],
+ skip_flag: [false; COEFFS],
+ skip_flag_bits: [0; BANDS],
+ skips_per_band: [0; BANDS],
+ keep_flag: [false; BANDS],
+ coeff: [0; COEFFS],
+ }
+ }
+ fn reset(&mut self) {
+ for i in 0..BANDS {
+ self.band_width[i] = 0;
+ self.band_present[i] = false;
+ self.band_skip[i] = false;
+ self.band_bits[i] = 0;
+ self.keep_flag[i] = false;
+ self.band_bitsum[i] = 0;
+ self.skips_per_band[i] = 0;
+ self.skip_flag_bits[i] = 0;
+ }
+ for i in 0..COEFFS {
+ self.cw_len[i] = 0;
+ self.skip_flag[i] = false;
+ }
+ }
+ fn calculate_bit_allocation(&mut self, ch_data: &mut IMCChannel, bits: usize, fixed_head: bool, adj_idx: usize) -> DecoderResult<()> {
+
+ let mut peak = 0.0;
+ for coef in ch_data.new_floor.iter() { if *coef > peak { peak = *coef; } }
+ peak *= 0.25;
+
+ for band in 0..BANDS-1 {
+ ch_data.bit_est[band] = ch_data.log_floor2[band] - ch_data.mask_wght[band].log2();
+ }
+ ch_data.bit_est[BANDS - 1] = BITALLOC_LIMIT;
+
+ for band in 0..BANDS {
+ let mut idx = 42;
+ let band_w = IMC_BANDS[band + 1] - IMC_BANDS[band];
+ if band_w == self.band_width[band] { idx = 0; }
+ if band_w > self.band_width[band] { idx = 1; }
+ if band_w/2 >= self.band_width[band] { idx = 2; }
+ validate!(idx <= 2);
+ idx *= 2;
+ if ch_data.new_floor[band] < peak { idx += 1; }
+ ch_data.bit_est[band] += IMC_BITALLOC_ADJ[adj_idx][idx];
+ }
+
+ if fixed_head {
+ for i in 0..4 {
+ ch_data.bit_est[i] = BITALLOC_LIMIT;
+ }
+ }
+
+ let start = if fixed_head { 4 } else { 0 };
+
+ let mut a_width = 0;
+ let mut pool = 0.0;
+ for band in start..BANDS-1 {
+ a_width += self.band_width[band];
+ pool += (self.band_width[band] as f32) * ch_data.bit_est[band];
+ }
+ validate!(a_width > 0);
+
+ self.band_width[BANDS - 1] = 0;
+ pool = (pool * 0.5 - (bits as f32)) / (a_width as f32);
+
+ let free_bits = bits as i32;
+ let mut cur_bits: i32 = 0;
+ let mut flag = 1;
+ let mut mmcount = 0;
+ for i in 0..BANDS/2 {
+ let diff = cur_bits - free_bits;
+ if diff.abs() <= 8 { break; }
+
+ cur_bits = 0;
+ let mut acc = 0;
+ for band in start..BANDS {
+ let mut len = (ch_data.bit_est[band] * 0.5 - pool + 0.5) as i32;
+ if len < 0 { len = 0; }
+ if len > 6 { len = 6; }
+ self.band_bits[band] = len as u8;
+ cur_bits += (self.band_width[band] as i32) * (len as i32);
+ if len > 0 {
+ acc += self.band_width[band] as i32;
+ }
+ }
+
+ let mut lflag = flag;
+ flag = 1;
+ if free_bits < cur_bits { flag = -1; }
+ if i == 0 { lflag = flag; }
+ if flag != lflag {
+ mmcount += 1;
+ }
+ pool += ((cur_bits - free_bits) as f32) / (((mmcount + 1) * acc) as f32);
+ }
+
+ for band in start..BANDS {
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ self.cw_len[i] = self.band_bits[band];
+ }
+ }
+
+ if free_bits > cur_bits {
+ let mut tmp: [f32; BANDS] = [BITALLOC_LIMIT; BANDS];
+ for band in 0..BANDS {
+ if self.band_bits[band] != 6 {
+ tmp[band] = (self.band_bits[band] as f32) * -2.0 + ch_data.bit_est[band] - 0.415;
+ }
+ }
+ let mut peak = 0.0;
+ while (peak > BITALLOC_LIMIT) && (cur_bits < free_bits) {
+ peak = BITALLOC_LIMIT;
+ let mut idx: Option<usize> = None;
+ for band in 0..BANDS {
+ if tmp[band] > peak {
+ peak = tmp[band];
+ idx = Some(band);
+ }
+ }
+ if let Some(band) = idx {
+ tmp[band] -= 2.0;
+ self.band_bits[band] += 1;
+ if self.band_bits[band] == 6 {
+ tmp[band] = BITALLOC_LIMIT;
+ }
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ self.cw_len[i] += 1;
+ cur_bits += 1;
+ if cur_bits >= free_bits {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if cur_bits > free_bits {
+ let mut tmp: [f32; BANDS] = [BITALLOC_TOP_LIMIT; BANDS];
+ for band in start..BANDS {
+ if self.band_bits[band] != 0 {
+ tmp[band] = (self.band_bits[band] as f32) * -2.0 + ch_data.bit_est[band] - 0.415 + 2.0;
+ }
+ }
+ while free_bits < cur_bits {
+ let mut low = BITALLOC_TOP_LIMIT;
+ let mut idx = 0;
+ for band in 0..BANDS {
+ if tmp[band] < low {
+ low = tmp[band];
+ idx = band;
+ }
+ }
+ tmp[idx] += 2.0;
+ self.band_bits[idx] -= 1;
+ if self.band_bits[idx] == 0 {
+ tmp[idx] = BITALLOC_TOP_LIMIT;
+ }
+ for i in IMC_BANDS[idx]..IMC_BANDS[idx + 1] {
+ if self.cw_len[i] > 0 {
+ self.cw_len[i] -= 1;
+ cur_bits -= 1;
+ if cur_bits <= free_bits {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn adjust_bit_allocation(&mut self, ch_data: &mut IMCChannel, free_bits: i32) {
+ let mut tmp: [f32; BANDS] = [BITALLOC_LIMIT; BANDS];
+ for band in 0..BANDS {
+ if self.band_bits[band] != 6 {
+ tmp[band] = (self.band_bits[band] as f32) * -2.0 + ch_data.bit_est[band] - 0.415;
+ }
+ }
+ let mut used_bits: i32 = 0;
+ let mut peak = 0.0;
+ while (peak > BITALLOC_LIMIT) && (used_bits < free_bits) {
+ peak = BITALLOC_LIMIT;
+ let mut idx: Option<usize> = None;
+ for band in 0..BANDS {
+ if tmp[band] > peak {
+ peak = tmp[band];
+ idx = Some(band);
+ }
+ }
+ if let Some(band) = idx {
+ tmp[band] -= 2.0;
+ self.band_bits[band] += 1;
+ if self.band_bits[band] == 6 {
+ tmp[band] = BITALLOC_LIMIT;
+ }
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ if self.cw_len[i] >= 6 { continue; }
+ self.cw_len[i] += 1;
+ used_bits += 1;
+ if used_bits >= free_bits {
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+struct LUTs {
+ exp_lev: [f32; 16],
+ exp_10: [f32; 32],
+ sqrt_tab: [f32; 32],
+}
+
+impl LUTs {
+ fn new() -> Self {
+ let mut exp_lev: [f32; 16] = [0.0; 16];
+ for lev in 0..16 {
+ exp_lev[lev] = 10.0f32.powf(-(lev as f32) * 0.4375);
+ }
+
+ let mut exp_10: [f32; 32] = [0.0; 32];
+ for i in 0..32 {
+ exp_10[i] = 10.0f32.powf(((i as f32) - 16.0) * 0.25);
+ }
+
+ let mut sqrt_tab: [f32; 32] = [0.0; 32];
+ for i in 0..32 {
+ sqrt_tab[i] = (i as f32).sqrt();
+ }
+
+ LUTs { exp_lev: exp_lev, exp_10: exp_10, sqrt_tab: sqrt_tab }
+ }
+}
+
+struct IMCDecoder {
+ is_imc: bool,
+
+ chmap: NAChannelMap,
+ ainfo: NAAudioInfo,
+ info: Rc<NACodecInfo>,
+
+ codes: [[Codebook<u8>; 4]; 4],
+ ch_data: [IMCChannel; 2],
+ ba: BitAlloc,
+ imdct: IMDCTContext,
+
+ cycle1: [usize; BANDS],
+ cycle2: [usize; BANDS],
+ weights1: [f32; BANDS-1],
+ weights2: [f32; BANDS-1],
+
+ luts: LUTs,
+}
+
+fn freq2bark(freq: f32) -> f32 {
+ 3.5 * ((freq / 7500.0) * (freq / 7500.0)).atan() + 13.0 * (freq * 0.00076).atan()
+}
+
+fn calc_maxcoef(coef: f32) -> (f32, f32) {
+ let c1 = 20000.0 / 10.0f32.powf(coef * 0.057031251);
+ (c1, c1.log2())
+}
+
+impl IMCDecoder {
+ fn new(is_imc: bool) -> Self {
+ let mut codes: [[Codebook<u8>; 4]; 4];
+ let mut cycle1: [usize; BANDS] = [0; BANDS];
+ let mut cycle2: [usize; BANDS] = [0; BANDS];
+ let mut weights1: [f32; BANDS-1] = [0.0; BANDS-1];
+ let mut weights2: [f32; BANDS-1] = [0.0; BANDS-1];
+ if is_imc {
+ cycle1.copy_from_slice(&IMC_CYCLE1);
+ cycle2.copy_from_slice(&IMC_CYCLE2);
+ weights1.copy_from_slice(&IMC_WEIGHTS1);
+ weights2.copy_from_slice(&IMC_WEIGHTS2);
+ }
+ unsafe {
+ codes = mem::uninitialized();
+ for i in 0..4 {
+ for j in 0..4 {
+ let mut cr = IMCCodeReader::new(i, j);
+ ptr::write(&mut codes[i][j], Codebook::new(&mut cr, CodebookMode::MSB).unwrap());
+ }
+ }
+ }
+ IMCDecoder {
+ is_imc: is_imc,
+ chmap: NAChannelMap::new(),
+ ainfo: NAAudioInfo::new(0, 0, SND_F32P_FORMAT, 0),
+ info: NACodecInfo::new_dummy(),
+
+ codes: codes,
+ ch_data: [IMCChannel::new(), IMCChannel::new()],
+ ba: BitAlloc::new(),
+ imdct: IMDCTContext::new(),
+ luts: LUTs::new(),
+
+ cycle1: cycle1,
+ cycle2: cycle2,
+ weights1: weights1,
+ weights2: weights2,
+ }
+ }
+
+ fn generate_iac_tables(&mut self, sample_rate: f32) {
+ let scale = sample_rate / 256.0 / 2.0 * 0.5;
+ let nyq_freq = sample_rate / 2.0;
+ let mut last_bark = 0.0;
+ let mut freq_max: [f32; BANDS] = [0.0; BANDS];
+ let mut freq_mid: [f32; BANDS] = [0.0; BANDS];
+ let mut freq_min: [f32; BANDS] = [0.0; BANDS];
+ for band in 0..BANDS {
+ let freq = ((IMC_BANDS[band] + IMC_BANDS[band + 1] - 1) as f32) * scale;
+ let bark = freq2bark(freq);
+ if band > 0 {
+ let bark_diff = bark - last_bark;
+ self.weights1[band - 1] = 10.0f32.powf(-1.0 * bark_diff);
+ self.weights2[band - 1] = 10.0f32.powf(-2.7 * bark_diff);
+ }
+ last_bark = bark;
+ freq_mid[band] = freq;
+
+ let mut tmp_freq = freq;
+ while tmp_freq < nyq_freq {
+ tmp_freq += 0.5;
+ if freq2bark(tmp_freq) > bark + 0.5 { break; }
+ }
+ freq_max[band] = tmp_freq;
+
+ let mut tmp_freq = freq;
+ while tmp_freq > 0.0 {
+ tmp_freq -= 0.5;
+ if freq2bark(tmp_freq) < bark - 0.5 { break; }
+ }
+ freq_min[band] = tmp_freq;
+ }
+
+ for band in 0..BANDS {
+ let mut s_band = BANDS - 1;
+ while s_band > 0 && freq_max[band] <= freq_mid[s_band] { s_band -= 1; }
+ self.cycle1[band] = s_band + 1;
+ }
+
+ self.cycle2[0] = 0;
+ for band in 1..BANDS {
+ let mut s_band = 0;
+ while s_band < BANDS-1 && freq_min[band] >= freq_mid[s_band] { s_band += 1; }
+ self.cycle2[band] = s_band - 1;
+ }
+ }
+
+ fn read_level_coeffs_raw(&mut self, br: &mut BitReader, ch: usize) -> DecoderResult<()> {
+ let ch_data = &mut self.ch_data[ch];
+ let maxc_pos = br.read(5)? as usize;
+ let max_coef = br.read(7)? as u8;
+
+ let (c1, c2) = calc_maxcoef(max_coef as f32);
+ for i in 0..BANDS {
+ if i != maxc_pos {
+ let level = br.read(4)?;
+ ch_data.new_floor[i] = c1 * self.luts.exp_lev[level as usize];
+ ch_data.log_floor[i] = c2 - 1.4533435415 * (level as f32);
+ } else {
+ ch_data.new_floor[i] = c1;
+ ch_data.log_floor[i] = c2;
+ }
+ self.ba.band_width[i] = IMC_BANDS[i + 1] - IMC_BANDS[i];
+
+ ch_data.log_floor2[i] = ch_data.log_floor[i] * 2.0;
+ ch_data.mask_wght[i] = 1.0;
+ }
+
+ Ok(())
+ }
+
+ fn calculate_channel_values(&mut self, ch: usize) {
+ let ch_data = &mut self.ch_data[ch];
+ let mut tmp2: [f32; BANDS+1] = [0.0; BANDS+1];
+ let mut tmp3: [f32; BANDS] = [0.0; BANDS];
+
+ for band in 0..BANDS {
+ ch_data.mask_wght[band] = 0.0;
+ let val;
+ if self.ba.band_width[band] > 0 {
+ val = (ch_data.new_floor[band] as f64).powi(2);
+ ch_data.log_floor2[band] = 2.0 * ch_data.log_floor[band];
+ } else {
+ val = 0.0;
+ ch_data.log_floor2[band] = -30000.0;
+ }
+ let tmp = val * (self.ba.band_width[band] as f64) * 0.01;
+ if val <= 1.0e-30 { tmp3[band] = 0.0; }
+ else { tmp3[band] = tmp as f32; }
+ }
+
+ for band in 0..BANDS {
+ let next_band = self.cycle1[band];
+ for band2 in band..next_band {
+ ch_data.mask_wght[band2] += tmp3[band];
+ }
+ tmp2[next_band] += tmp3[band];
+ }
+
+ let mut accum = 0.0;
+ for band in 1..BANDS {
+ accum = (tmp2[band] + accum) * self.weights1[band - 1];
+ ch_data.mask_wght[band] += accum;
+ }
+
+ let mut tmp2: [f32; BANDS] = [0.0; BANDS];
+ tmp2[0] = tmp3[0];
+ for band in 1..BANDS {
+ let prev_band = self.cycle2[band];
+ for band2 in prev_band+1..band {
+ ch_data.mask_wght[band2] += tmp3[band];
+ }
+ tmp2[prev_band + 1] += tmp3[band];
+ }
+
+ let mut accum = 0.0;
+ for i in 0..BANDS-1 {
+ let band = BANDS - 2 - i;
+ accum = (tmp2[band + 1] + accum) * self.weights2[band];
+ ch_data.mask_wght[band] += accum;
+ }
+ }
+
+ fn read_level_coeffs(&mut self, br: &mut BitReader, reset: bool, sel_idx: usize, ch: usize) -> DecoderResult<()> {
+ let mut level: [i8; BANDS] = [0; BANDS];
+ let start;
+ if reset {
+ start = 1;
+ level[0] = br.read(7)? as i8;
+ } else {
+ start = 0;
+ }
+ for i in start..BANDS {
+ level[i] = br.read_cb(&self.codes[sel_idx][IMC_CB_SELECTOR[sel_idx][i]])? as i8;
+ if level[i] == 17 {
+ level[i] += br.read(4)? as i8;
+ }
+ self.ba.keep_flag[i] = level[i] == 16;
+ }
+ if reset {
+ let ch_data = &mut self.ch_data[ch];
+ let (mut c1, mut c2) = calc_maxcoef(level[0] as f32);
+ ch_data.new_floor[0] = c1;
+ ch_data.log_floor[0] = c2;
+ for i in 1..BANDS {
+ if level[i] == 16 {
+ ch_data.new_floor[i] = 1.0;
+ ch_data.log_floor[i] = 0.0;
+ } else {
+ let lval;
+ if level[i] < 17 {
+ lval = level[i] - 7;
+ } else if level[i] < 25 {
+ lval = level[i] - 32;
+ } else {
+ lval = level[i] - 16;
+ }
+ c1 *= self.luts.exp_10[(lval + 16) as usize];
+ c2 += 0.83048 * (lval as f32);
+ ch_data.new_floor[i] = c1;
+ ch_data.log_floor[i] = c2;
+ }
+ }
+ } else {
+ let ch_data = &mut self.ch_data[ch];
+ for i in 0..BANDS {
+ if level[i] < 16 {
+ let lval = level[i] - 7;
+ ch_data.new_floor[i] = self.luts.exp_10[(lval + 16) as usize] * ch_data.old_floor[i];
+ ch_data.log_floor[i] += (lval as f32) * 0.83048;
+ } else {
+ ch_data.new_floor[i] = ch_data.old_floor[i];
+ }
+ }
+ }
+
+ self.ba.band_width[0] = IMC_BANDS[1] - IMC_BANDS[0];
+ for i in 1..BANDS {
+ if level[i] != 16 {
+ self.ba.band_width[i] = IMC_BANDS[i + 1] - IMC_BANDS[i];
+ } else {
+ self.ba.band_width[i] = 0;
+ }
+ }
+
+ for i in 0..BANDS-1 {
+ if self.ba.band_width[i] > 0 {
+ self.ba.band_present[i] = br.read_bool()?;
+ }
+ }
+ self.calculate_channel_values(ch);
+
+ Ok(())
+ }
+
+ fn read_skip_flags(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+ let ba = &mut self.ba;
+ for band in 0..BANDS {
+ if !ba.band_present[band] || ba.band_width[band] == 0 { continue; }
+
+ if !ba.band_skip[band] {
+ ba.skip_flag_bits[band] = (IMC_BANDS[band + 1] - IMC_BANDS[band]) as u8;
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ ba.skip_flag[i] = br.read_bool()?;
+ if ba.skip_flag[i] {
+ ba.skips_per_band[band] += 1;
+ }
+ }
+ } else {
+ let mut i = IMC_BANDS[band];
+ while i < IMC_BANDS[band + 1] - 1 {
+ if !br.read_bool()? {
+ ba.skip_flag_bits[band] += 1;
+ ba.skip_flag[i] = true;
+ ba.skip_flag[i + 1] = true;
+ ba.skips_per_band[band] += 2;
+ } else {
+ if br.read_bool()? {
+ ba.skip_flag_bits[band] += 2;
+ ba.skip_flag[i] = false;
+ ba.skip_flag[i + 1] = true;
+ ba.skips_per_band[band] += 1;
+ } else {
+ ba.skip_flag_bits[band] += 3;
+ if !br.read_bool()? {
+ ba.skip_flag[i] = true;
+ ba.skips_per_band[band] += 1;
+ } else {
+ ba.skip_flag[i] = false;
+ }
+ ba.skip_flag[i + 1] = false;
+ }
+ }
+ i += 2;
+ }
+ if i != IMC_BANDS[band + 1] {
+ ba.skip_flag_bits[band] += 1;
+ ba.skip_flag[i] = br.read_bool()?;
+ if ba.skip_flag[i] {
+ ba.skips_per_band[band] += 1;
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn read_bitalloc_delta(&mut self, br: &mut BitReader, ch: usize) -> DecoderResult<()> {
+ for band in 0..BANDS {
+ self.ba.band_bitsum[band] = 0;
+ self.ba.band_skip[band] = false;
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ self.ba.band_bitsum[band] += self.ba.cw_len[i] as usize;
+ }
+ if self.ba.band_present[band] {
+ let band_w = IMC_BANDS[band + 1] - IMC_BANDS[band];
+ let bitsum = self.ba.band_bitsum[band] as usize;
+ if (bitsum > 0) && (((band_w * 3) >> 1) > bitsum) {
+ self.ba.band_skip[band] = true;
+ }
+ }
+ }
+
+ self.read_skip_flags(br)?;
+
+ let mut ch_data = &mut self.ch_data[ch];
+ for band in 0..BANDS {
+ ch_data.adj_floor[band] = ch_data.new_floor[band];
+ let band_w = IMC_BANDS[band + 1] - IMC_BANDS[band];
+ let nonskip = band_w - self.ba.skips_per_band[band];
+ if self.ba.band_present[band] && nonskip > 0 {
+ ch_data.adj_floor[band] *= self.luts.sqrt_tab[band_w] / self.luts.sqrt_tab[nonskip];
+ }
+ }
+
+ let mut bits_freed: i32 = 0;
+ for band in 0..BANDS {
+ if !self.ba.band_present[band] { continue; }
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ if self.ba.skip_flag[i] {
+ bits_freed += self.ba.cw_len[i] as i32;
+ self.ba.cw_len[i] = 0;
+ }
+ }
+ bits_freed -= self.ba.skip_flag_bits[band] as i32;
+ }
+
+ if bits_freed < 0 { return Err(DecoderError::Bug); }
+ self.ba.adjust_bit_allocation(&mut ch_data, bits_freed);
+
+ Ok(())
+ }
+
+ fn read_coeffs(&mut self, br: &mut BitReader) -> DecoderResult<()> {
+ for band in 0..BANDS {
+ if self.ba.band_bitsum[band] == 0 { continue; }
+ if !self.ba.band_present[band] && (self.ba.band_width[band] == 0) { continue; }
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ let len = self.ba.cw_len[i];
+ if len > 0 && (!self.ba.band_present[band] || !self.ba.skip_flag[i]) {
+ self.ba.coeff[i] = br.read(len)? as u8;
+ } else {
+ self.ba.coeff[i] = 0;
+ }
+ }
+ }
+ Ok(())
+ }
+
+ fn inv_quant(&mut self, ch: usize, raw_coeffs: bool) {
+ let qidx: usize = if raw_coeffs { 1 } else { 0 };
+ let ch_data = &mut self.ch_data[ch];
+ for band in 0..BANDS {
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ ch_data.cw[i] = 0.0;
+ let cw_len = self.ba.cw_len[i];
+ if cw_len == 0 || self.ba.skip_flag[i] { continue; }
+
+ let val = self.ba.coeff[i] as usize;
+ let mid = 1 << (cw_len - 1);
+ let max = (1 << cw_len) - 1;
+ if cw_len >= 4 {
+ let quant = &IMC_QUANT_LARGE[qidx];
+ if val >= mid {
+ ch_data.cw[i] = quant[val - 8] * ch_data.adj_floor[band];
+ } else {
+ ch_data.cw[i] = -quant[max - val - 8] * ch_data.adj_floor[band];
+ }
+ } else {
+ let idx = qidx + (if self.ba.band_present[band] { 2 } else { 0 });
+ let quant = &IMC_QUANT_SMALL[idx];
+ if val >= mid {
+ ch_data.cw[i] = quant[val - 1] * ch_data.adj_floor[band];
+ } else {
+ ch_data.cw[i] = -quant[max - val - 1] * ch_data.adj_floor[band];
+ }
+ }
+ }
+ }
+ }
+
+ fn decode_block(&mut self, data: &[u8], ch: usize, dst: &mut [f32]) -> DecoderResult<()> {
+ let mut br = BitReader::new(&data[BLOCK_SIZE*ch..], BLOCK_SIZE, BitReaderMode::LE16MSB);
+ let hdr = br.read(9)?;
+ validate!((hdr & 0x18) == 0);
+
+ let reset = br.read_bool()?;
+ let fixed_head = br.read_bool()?;
+ let raw_coeffs = br.read_bool()?;
+ let weight_idx = br.read(1)? as usize;
+
+ if reset {
+ self.ch_data[ch].reset();
+ }
+
+ self.ba.reset();
+
+ if raw_coeffs {
+ self.read_level_coeffs_raw(&mut br, ch)?;
+ } else {
+ let cb_idx = (if reset { 2 } else { 0 }) + (if fixed_head { 1 } else { 0 });
+ self.read_level_coeffs(&mut br, reset, cb_idx, ch)?;
+ }
+
+ self.ch_data[ch].old_floor.copy_from_slice(&self.ch_data[ch].new_floor);
+
+ let mut bitcount: usize = 0;
+ if fixed_head {
+ bitcount += 15;
+ self.ba.band_bits[0] = 5;
+ for i in 0..3 {
+ self.ba.cw_len[i] = 5;
+ }
+ for band in 1..4 {
+ let bits: u8;
+ if raw_coeffs || !self.ba.keep_flag[band]{
+ bits = 5;
+ } else {
+ bits = 0;
+ }
+ self.ba.band_bits[band] = bits;
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ self.ba.cw_len[i] = bits;
+ bitcount += bits as usize;
+ }
+ }
+ }
+
+ if !self.is_imc {
+ if self.ba.band_width[BANDS - 1] != 0 {
+ bitcount += 1;
+ }
+ bitcount += 16;
+ } else {
+ if self.ba.band_width[BANDS - 1] != 0 {
+ bitcount += 1;
+ }
+ }
+
+ validate!(br.tell() + bitcount < BLOCK_SIZE * 8);
+ self.ba.calculate_bit_allocation(&mut self.ch_data[ch], 512 - bitcount - br.tell(), fixed_head, weight_idx)?;
+
+ if !raw_coeffs {
+ self.read_bitalloc_delta(&mut br, ch)?;
+ }
+
+ for band in 0..BANDS {
+ self.ba.band_bitsum[band] = 0;
+ for i in IMC_BANDS[band]..IMC_BANDS[band + 1] {
+ if !self.ba.skip_flag[i] {
+ self.ba.band_bitsum[band] += self.ba.cw_len[i] as usize;
+ }
+ }
+ }
+
+ self.read_coeffs(&mut br)?;
+ self.inv_quant(ch, raw_coeffs);
+ self.imdct.imdct(&self.ch_data[ch].cw, dst, &mut self.ch_data[ch].last_im);
+
+ Ok(())
+ }
+}
+
+impl IMDCTContext {
+ fn new() -> Self {
+ let mut window: [f32; COEFFS] = [0.0; COEFFS];
+ generate_window(WindowType::Sine, 1.0, COEFFS, true, &mut window);
+ let mut pretwiddle1: [f32; COEFFS/2] = [0.0; COEFFS/2];
+ let mut pretwiddle2: [f32; COEFFS/2] = [0.0; COEFFS/2];
+ let mut posttwiddle: [FFTComplex; COEFFS/2] = [FFTC_ZERO; COEFFS/2];
+ for i in 0..COEFFS/2 {
+ let n = i as f32;
+ let base = (n * 4.0 + 1.0) / 1024.0 * consts::PI;
+ let r1 = base.sin();
+ let r2 = base.cos();
+ if (i & 1) == 0 {
+ pretwiddle1[i] = -(r1 + r2) * consts::SQRT_2;
+ pretwiddle2[i] = (r1 - r2) * consts::SQRT_2;
+ } else {
+ pretwiddle1[i] = (r1 + r2) * consts::SQRT_2;
+ pretwiddle2[i] = -(r1 - r2) * consts::SQRT_2;
+ }
+ posttwiddle[i] = FFTComplex::exp(consts::PI / 256.0 * n).scale(1.0/32768.0);
+ }
+ IMDCTContext {
+ pretwiddle1: pretwiddle1,
+ pretwiddle2: pretwiddle2,
+ posttwiddle: posttwiddle,
+ tmp: [FFTC_ZERO; COEFFS/2],
+ fft: FFTBuilder::new_fft(FFTMode::SplitRadix, COEFFS/2),
+ window: window,
+ }
+ }
+ fn imdct(&mut self, coeffs: &[f32; COEFFS], dst: &mut [f32], last_im: &mut [f32; COEFFS/2]) {
+ for i in 0..COEFFS/2 {
+ let in2 = coeffs[i * 2];
+ let in1 = coeffs[COEFFS - 1 - i * 2];
+ let c2 = self.pretwiddle1[i];
+ let c1 = self.pretwiddle2[i];
+ self.tmp[i].re = -(c2 * in1 + c1 * in2);
+ self.tmp[i].im = c1 * in1 - c2 * in2;
+ }
+ self.fft.do_fft_inplace(&mut self.tmp, false);
+ for i in 0..COEFFS/2 {
+ let tmp = !(self.tmp[i] * self.posttwiddle[i]);
+ let c1 = self.window[i * 2];
+ let c2 = self.window[COEFFS - 1 - i * 2];
+ let im = last_im[i];
+ dst[i * 2] = c2 * im + c1 * tmp.re;
+ dst[COEFFS - 1 - i * 2] = c1 * im - c2 * tmp.re;
+ last_im[i] = tmp.im;
+ }
+ }
+}
+
+const CHMAP_MONO: [NAChannelType; 1] = [NAChannelType::C];
+const CHMAP_STEREO: [NAChannelType; 2] = [NAChannelType::L, NAChannelType::R];
+
+impl NADecoder for IMCDecoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
+ self.chmap = NAChannelMap::new();
+ match ainfo.get_channels() {
+ 1 => { self.chmap.add_channels(&CHMAP_MONO); },
+ 2 => { self.chmap.add_channels(&CHMAP_STEREO); },
+ _ => { return Err(DecoderError::InvalidData); },
+ };
+ self.ainfo = NAAudioInfo::new(ainfo.get_sample_rate(),
+ ainfo.get_channels(),
+ SND_F32P_FORMAT, 0);
+ self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo.clone()));
+
+ if !self.is_imc {
+ self.generate_iac_tables(ainfo.get_sample_rate() as f32);
+ }
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ validate!(info.get_properties().is_audio());
+ let pktbuf = pkt.get_buffer();
+
+ let nblocks = pktbuf.len() / BLOCK_SIZE / (self.ainfo.get_channels() as usize);
+ let duration = COEFFS * nblocks;
+
+ let mut abuf = alloc_audio_buffer(self.ainfo, duration, self.chmap.clone())?;
+ let mut adata = abuf.get_abuf_f32().unwrap();
+ let mut dst = adata.get_data_mut();
+
+ let mut start: usize = 0;
+ let channels = self.ainfo.get_channels() as usize;
+ for chunk in pktbuf.chunks(BLOCK_SIZE * channels) {
+ for ch in 0..channels {
+ let off = abuf.get_offset(ch as usize) + start;
+ self.decode_block(chunk, ch as usize, &mut dst[off..off+COEFFS])?;
+ }
+ if (channels == 2) && ((chunk[1] & 0x20) != 0) {
+ let off1 = abuf.get_offset(0) + start;
+ let off2 = abuf.get_offset(1) + start;
+ for i in 0..COEFFS {
+ let l = dst[off1 + i];
+ let r = dst[off2 + i];
+ dst[off1 + i] = l + r;
+ dst[off2 + i] = l - r;
+ }
+ }
+ start += COEFFS;
+ }
+
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
+ frm.set_keyframe(true);
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+}
+
+pub fn get_decoder_imc() -> Box<NADecoder> {
+ Box::new(IMCDecoder::new(true))
+}
+
+pub fn get_decoder_iac() -> Box<NADecoder> {
+ Box::new(IMCDecoder::new(false))
+}
+
+struct IMCCodeReader { sel1: usize, sel2: usize }
+
+impl IMCCodeReader {
+ fn new(sel1: usize, sel2: usize) -> Self { IMCCodeReader { sel1: sel1, sel2: sel2 } }
+}
+
+impl CodebookDescReader<u8> for IMCCodeReader {
+ fn bits(&mut self, idx: usize) -> u8 { IMC_CODE_LENGTHS[self.sel1][self.sel2][idx] }
+ fn code(&mut self, idx: usize) -> u32 { IMC_CODE_CODES[self.sel1][self.sel2][idx] as u32 }
+ fn sym (&mut self, idx: usize) -> u8 { idx as u8 }
+ fn len(&mut self) -> usize { IMC_CODE_LENGTHS[0][0].len() }
+}
+
+static IMC_BANDS: [usize; 33] = [
+ 0, 3, 6, 9, 12, 16, 20, 24, 29, 34, 40, 46, 53, 60, 68, 76,
+ 84, 93, 102, 111, 121, 131, 141, 151, 162, 173, 184, 195, 207, 219, 231, 243,
+ 256,
+];
+
+const IMC_QUANT_SMALL: &[[f32; 8]; 4] = &[
+ [ 8.4431201e-1, 4.7358301e-1, 1.448354, 2.7073899e-1,
+ 7.4449003e-1, 1.241991, 1.845484, 0.0 ],
+ [ 8.6876702e-1, 4.7659001e-1, 1.478224, 2.5672799e-1,
+ 7.55777e-1, 1.3229851, 2.03438, 0.0 ],
+ [ 7.5891501e-1, 6.2272799e-1, 1.271322, 3.47904e-1,
+ 7.5317699e-1, 1.150767, 1.628476, 0.0 ],
+ [ 7.65257e-1, 6.44647e-1, 1.263824, 3.4548101e-1,
+ 7.6384902e-1, 1.214466, 1.7638789, 0.0 ]
+];
+
+const IMC_QUANT_LARGE: &[[f32; 56]; 2] = &[
+ [ 1.39236e-1, 3.50548e-1, 5.9547901e-1, 8.5772401e-1,
+ 1.121545, 1.3882281, 1.695882, 2.1270809,
+ 7.2221003e-2, 1.85177e-1, 2.9521701e-1, 4.12568e-1,
+ 5.4068601e-1, 6.7679501e-1, 8.1196898e-1, 9.4765198e-1,
+ 1.0779999, 1.203415, 1.337265, 1.481871,
+ 1.639982, 1.814766, 2.0701399, 2.449862,
+ 3.7533998e-2, 1.02722e-1, 1.6021401e-1, 2.16043e-1,
+ 2.7231601e-1, 3.3025399e-1, 3.9022601e-1, 4.52849e-1,
+ 5.1794899e-1, 5.8529502e-1, 6.53956e-1, 7.2312802e-1,
+ 7.9150802e-1, 8.5891002e-1, 9.28141e-1, 9.9706203e-1,
+ 1.062153, 1.12564, 1.189834, 1.256122,
+ 1.324469, 1.3955311, 1.468906, 1.545084,
+ 1.6264729, 1.711524, 1.802705, 1.91023,
+ 2.0533991, 2.22333, 2.4830019, 3.253329 ],
+ [ 1.11654e-1, 3.54469e-1, 6.4232099e-1, 9.6128798e-1,
+ 1.295053, 1.61777, 1.989839, 2.51107,
+ 5.7721999e-2, 1.69879e-1, 2.97589e-1, 4.3858799e-1,
+ 5.9039903e-1, 7.4934798e-1, 9.1628098e-1, 1.087297,
+ 1.262751, 1.4288321, 1.6040879, 1.79067,
+ 2.000668, 2.2394669, 2.649332, 5.2760072,
+ 2.9722e-2, 8.7316997e-2, 1.4445201e-1, 2.04247e-1,
+ 2.6879501e-1, 3.3716801e-1, 4.08811e-1, 4.8306999e-1,
+ 5.6049401e-1, 6.3955498e-1, 7.2044599e-1, 8.0427998e-1,
+ 8.8933599e-1, 9.7537601e-1, 1.062461, 1.1510431,
+ 1.240236, 1.326715, 1.412513, 1.500502,
+ 1.591749, 1.686413, 1.785239, 1.891233,
+ 2.0051291, 2.127681, 2.2709141, 2.475826,
+ 2.7219379, 3.101985, 4.686213, 6.2287788 ]
+];
+
+static IMC_CYCLE1: [usize; BANDS] = [
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32,
+];
+
+static IMC_CYCLE2: [usize; BANDS] = [
+ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29
+];
+
+static IMC_WEIGHTS1: [f32; BANDS-1] = [
+ 0.119595, 0.123124, 0.129192, 9.97377e-2,
+ 8.1923e-2, 9.61153e-2, 8.77885e-2, 8.61174e-2,
+ 9.00882e-2, 9.91658e-2, 0.112991, 0.131126,
+ 0.152886, 0.177292, 0.221782, 0.244917,
+ 0.267386, 0.306816, 0.323046, 0.33729,
+ 0.366773, 0.392557, 0.398076, 0.403302,
+ 0.42451, 0.444777, 0.449188, 0.455445,
+ 0.477853, 0.500669, 0.510395
+];
+
+static IMC_WEIGHTS2: [f32; BANDS-1] = [
+ 3.23466e-3, 3.49886e-3, 3.98413e-3, 1.98116e-3,
+ 1.16465e-3, 1.79283e-3, 1.40372e-3, 1.33274e-3,
+ 1.50523e-3, 1.95064e-3, 2.77472e-3, 4.14725e-3,
+ 6.2776e-3, 9.36401e-3, 1.71397e-2, 2.24052e-2,
+ 2.83971e-2, 4.11689e-2, 4.73165e-2, 5.31631e-2,
+ 6.66614e-2, 8.00824e-2, 8.31588e-2, 8.61397e-2,
+ 9.89229e-2, 0.112197, 0.115227, 0.119613,
+ 0.136174, 0.15445, 0.162685
+];
+
+static IMC_BITALLOC_ADJ: [[f32; 7]; 2] = [
+ [ 7.6, 4.4, 6.1, 2.3, 6.2, 1.8, 0.0 ],
+ [ 3.6, 3.7, 5.1, 1.6, 1.5, 1.2, 0.0 ]
+];
+
+static IMC_CODE_LENGTHS: &[[[u8; 18]; 4]; 4] = &[
+ [
+ [ 16, 15, 13, 11, 8, 5, 3, 1, 2, 4, 6, 9, 10, 12, 14, 16, 7, 0 ],
+ [ 10, 8, 7, 6, 4, 4, 3, 2, 2, 3, 4, 6, 7, 9, 11, 11, 7, 0 ],
+ [ 15, 15, 14, 11, 8, 6, 4, 2, 1, 4, 5, 7, 9, 10, 12, 13, 4, 0 ],
+ [ 13, 11, 10, 8, 6, 4, 2, 2, 2, 3, 5, 7, 9, 12, 15, 15, 14, 0 ],
+ ], [
+ [ 14, 12, 10, 8, 7, 4, 2, 2, 2, 3, 5, 7, 9, 11, 13, 14, 7, 0 ],
+ [ 14, 13, 11, 8, 6, 4, 3, 2, 2, 3, 5, 7, 9, 10, 12, 14, 3, 0 ],
+ [ 13, 12, 10, 7, 5, 4, 3, 2, 2, 3, 4, 6, 8, 9, 11, 13, 4, 0 ],
+ [ 13, 12, 10, 7, 5, 4, 3, 2, 2, 3, 4, 6, 8, 9, 11, 13, 4, 0 ],
+ ], [
+ [ 16, 14, 12, 10, 8, 5, 3, 1, 2, 4, 7, 9, 11, 13, 15, 17, 6, 17 ],
+ [ 15, 13, 11, 8, 6, 4, 2, 2, 2, 3, 5, 7, 10, 12, 14, 16, 9, 16 ],
+ [ 14, 12, 11, 9, 8, 6, 3, 1, 2, 5, 7, 10, 13, 15, 16, 17, 4, 17 ],
+ [ 16, 14, 12, 9, 7, 5, 2, 2, 2, 3, 4, 6, 8, 11, 13, 15, 10, 16 ],
+ ], [
+ [ 13, 11, 10, 8, 7, 5, 2, 2, 2, 4, 6, 9, 12, 14, 15, 16, 3, 16 ],
+ [ 11, 11, 10, 9, 8, 7, 5, 4, 3, 3, 3, 3, 3, 3, 4, 5, 6, 5 ],
+ [ 9, 9, 7, 6, 5, 4, 3, 3, 2, 3, 4, 5, 4, 5, 5, 6, 8, 6 ],
+ [ 13, 12, 10, 8, 5, 3, 3, 2, 2, 3, 4, 7, 9, 11, 14, 15, 6, 15 ]
+ ]
+];
+
+static IMC_CODE_CODES: &[[[u16; 18]; 4]; 4] = &[
+ [
+ [ 0xCC32, 0x6618, 0x1987, 0x0660, 0x00CD, 0x0018, 0x0007, 0x0000, 0x0002,
+ 0x000D, 0x0032, 0x0199, 0x0331, 0x0CC2, 0x330D, 0xCC33, 0x0067, 0x0000 ],
+ [ 0x02FE, 0x00BE, 0x005E, 0x002D, 0x000A, 0x0009, 0x0003, 0x0003, 0x0000,
+ 0x0002, 0x0008, 0x002C, 0x005D, 0x017E, 0x05FE, 0x05FF, 0x005C, 0x0000 ],
+ [ 0x5169, 0x5168, 0x28B5, 0x0517, 0x00A3, 0x0029, 0x0008, 0x0003, 0x0000,
+ 0x0009, 0x0015, 0x0050, 0x0144, 0x028A, 0x0A2C, 0x145B, 0x000B, 0x0000 ],
+ [ 0x1231, 0x048D, 0x0247, 0x0090, 0x0025, 0x0008, 0x0001, 0x0003, 0x0000,
+ 0x0005, 0x0013, 0x0049, 0x0122, 0x0919, 0x48C3, 0x48C2, 0x2460, 0x0000 ]
+ ], [
+ [ 0x2D1D, 0x0B46, 0x02D0, 0x00B5, 0x0059, 0x000A, 0x0003, 0x0001, 0x0000,
+ 0x0004, 0x0017, 0x005B, 0x0169, 0x05A2, 0x168F, 0x2D1C, 0x0058, 0x0000 ],
+ [ 0x1800, 0x0C01, 0x0301, 0x0061, 0x0019, 0x0007, 0x0004, 0x0003, 0x0000,
+ 0x0005, 0x000D, 0x0031, 0x00C1, 0x0181, 0x0601, 0x1801, 0x0002, 0x0000 ],
+ [ 0x1556, 0x0AAA, 0x02AB, 0x0054, 0x0014, 0x000B, 0x0002, 0x0003, 0x0000,
+ 0x0003, 0x0008, 0x002B, 0x00AB, 0x0154, 0x0554, 0x1557, 0x0009, 0x0000 ],
+ [ 0x1556, 0x0AAA, 0x02AB, 0x0054, 0x0014, 0x000B, 0x0002, 0x0003, 0x0000,
+ 0x0003, 0x0008, 0x002B, 0x00AB, 0x0154, 0x0554, 0x1557, 0x0009, 0x0000 ]
+ ], [
+ [ 0x2993, 0x0A65, 0x0298, 0x00A7, 0x0028, 0x0004, 0x0000, 0x0001, 0x0001,
+ 0x0003, 0x0015, 0x0052, 0x014D, 0x0533, 0x14C8, 0x5324, 0x000B, 0x5325 ],
+ [ 0x09B8, 0x026F, 0x009A, 0x0012, 0x0005, 0x0000, 0x0001, 0x0002, 0x0003,
+ 0x0001, 0x0003, 0x0008, 0x004C, 0x0136, 0x04DD, 0x1373, 0x0027, 0x1372 ],
+ [ 0x0787, 0x01E0, 0x00F1, 0x003D, 0x001F, 0x0006, 0x0001, 0x0001, 0x0001,
+ 0x0002, 0x000E, 0x0079, 0x03C2, 0x0F0D, 0x1E19, 0x3C30, 0x0000, 0x3C31 ],
+ [ 0x4B06, 0x12C0, 0x04B1, 0x0097, 0x0024, 0x0008, 0x0002, 0x0003, 0x0000,
+ 0x0003, 0x0005, 0x0013, 0x004A, 0x0259, 0x0961, 0x2582, 0x012D, 0x4B07 ]
+ ], [
+ [ 0x0A5A, 0x0297, 0x014A, 0x0053, 0x0028, 0x000B, 0x0003, 0x0000, 0x0002,
+ 0x0004, 0x0015, 0x00A4, 0x052C, 0x14B7, 0x296C, 0x52DB, 0x0003, 0x52DA ],
+ [ 0x0193, 0x0192, 0x00C8, 0x0065, 0x0033, 0x0018, 0x0007, 0x0004, 0x0000,
+ 0x0004, 0x0005, 0x0007, 0x0006, 0x0003, 0x0005, 0x0005, 0x000D, 0x0004 ],
+ [ 0x0012, 0x0013, 0x0005, 0x0003, 0x0000, 0x0003, 0x0005, 0x0004, 0x0003,
+ 0x0003, 0x0005, 0x0005, 0x0004, 0x0004, 0x0003, 0x0005, 0x0008, 0x0004 ],
+ [ 0x0D66, 0x06B2, 0x01AD, 0x006A, 0x000C, 0x0005, 0x0004, 0x0000, 0x0003,
+ 0x0002, 0x0007, 0x0034, 0x00D7, 0x0358, 0x1ACF, 0x359C, 0x001B, 0x359D ]
+ ]
+];
+
+const IMC_CB_SELECTOR: [[usize; BANDS]; 4] = [
+ [ 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2 ],
+ [ 0, 2, 0, 3, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ],
+ [ 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2 ],
+ [ 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
+];
+
+#[cfg(test)]
+mod test {
+ use crate::test::dec_video::*;
+ #[test]
+ fn test_imc() {
+// let file = "assets/neal73_saber.avi";
+// let file = "assets/IMC/hvalen.avi";
+ let file = "assets/IMC/8khz.avi";
+// let file = "assets/STsKlassFist-1a.avi";
+// let file = "assets/IMC/Angel Bday.avi";
+ test_decode_audio("avi", file, None, "imc");
+ //test_file_decoding("avi", file, None, false, true, None);
+ }
+}
diff --git a/nihav-indeo/src/codecs/indeo2.rs b/nihav-indeo/src/codecs/indeo2.rs
new file mode 100644
index 0000000..ffd36c6
--- /dev/null
+++ b/nihav-indeo/src/codecs/indeo2.rs
@@ -0,0 +1,378 @@
+use std::rc::Rc;
+use std::cell::RefCell;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_core::formats;
+use nihav_core::codecs::*;
+use nihav_core::frame::*;
+
+static INDEO2_DELTA_TABLE: [[u8; 256]; 4] = [
+ [
+ 0x80, 0x80, 0x84, 0x84, 0x7C, 0x7C, 0x7F, 0x85,
+ 0x81, 0x7B, 0x85, 0x7F, 0x7B, 0x81, 0x8C, 0x8C,
+ 0x74, 0x74, 0x83, 0x8D, 0x7D, 0x73, 0x8D, 0x83,
+ 0x73, 0x7D, 0x77, 0x89, 0x89, 0x77, 0x89, 0x77,
+ 0x77, 0x89, 0x8C, 0x95, 0x74, 0x6B, 0x95, 0x8C,
+ 0x6B, 0x74, 0x7C, 0x90, 0x84, 0x70, 0x90, 0x7C,
+ 0x70, 0x84, 0x96, 0x96, 0x6A, 0x6A, 0x82, 0x98,
+ 0x7E, 0x68, 0x98, 0x82, 0x68, 0x7E, 0x97, 0xA2,
+ 0x69, 0x5E, 0xA2, 0x97, 0x5E, 0x69, 0xA2, 0xA2,
+ 0x5E, 0x5E, 0x8B, 0xA3, 0x75, 0x5D, 0xA3, 0x8B,
+ 0x5D, 0x75, 0x71, 0x95, 0x8F, 0x6B, 0x95, 0x71,
+ 0x6B, 0x8F, 0x78, 0x9D, 0x88, 0x63, 0x9D, 0x78,
+ 0x63, 0x88, 0x7F, 0xA7, 0x81, 0x59, 0xA7, 0x7F,
+ 0x59, 0x81, 0xA4, 0xB1, 0x5C, 0x4F, 0xB1, 0xA4,
+ 0x4F, 0x5C, 0x96, 0xB1, 0x6A, 0x4F, 0xB1, 0x96,
+ 0x4F, 0x6A, 0xB2, 0xB2, 0x4E, 0x4E, 0x65, 0x9B,
+ 0x9B, 0x65, 0x9B, 0x65, 0x65, 0x9B, 0x89, 0xB4,
+ 0x77, 0x4C, 0xB4, 0x89, 0x4C, 0x77, 0x6A, 0xA3,
+ 0x96, 0x5D, 0xA3, 0x6A, 0x5D, 0x96, 0x73, 0xAC,
+ 0x8D, 0x54, 0xAC, 0x73, 0x54, 0x8D, 0xB4, 0xC3,
+ 0x4C, 0x3D, 0xC3, 0xB4, 0x3D, 0x4C, 0xA4, 0xC3,
+ 0x5C, 0x3D, 0xC3, 0xA4, 0x3D, 0x5C, 0xC4, 0xC4,
+ 0x3C, 0x3C, 0x96, 0xC6, 0x6A, 0x3A, 0xC6, 0x96,
+ 0x3A, 0x6A, 0x7C, 0xBA, 0x84, 0x46, 0xBA, 0x7C,
+ 0x46, 0x84, 0x5B, 0xAB, 0xA5, 0x55, 0xAB, 0x5B,
+ 0x55, 0xA5, 0x63, 0xB4, 0x9D, 0x4C, 0xB4, 0x63,
+ 0x4C, 0x9D, 0x86, 0xCA, 0x7A, 0x36, 0xCA, 0x86,
+ 0x36, 0x7A, 0xB6, 0xD7, 0x4A, 0x29, 0xD7, 0xB6,
+ 0x29, 0x4A, 0xC8, 0xD7, 0x38, 0x29, 0xD7, 0xC8,
+ 0x29, 0x38, 0xA4, 0xD8, 0x5C, 0x28, 0xD8, 0xA4,
+ 0x28, 0x5C, 0x6C, 0xC1, 0x94, 0x3F, 0xC1, 0x6C,
+ 0x3F, 0x94, 0xD9, 0xD9, 0x27, 0x27, 0x80, 0x80,
+ ], [
+ 0x80, 0x80, 0x85, 0x85, 0x7B, 0x7B, 0x7E, 0x87,
+ 0x82, 0x79, 0x87, 0x7E, 0x79, 0x82, 0x8F, 0x8F,
+ 0x71, 0x71, 0x84, 0x8F, 0x7C, 0x71, 0x8F, 0x84,
+ 0x71, 0x7C, 0x75, 0x8B, 0x8B, 0x75, 0x8B, 0x75,
+ 0x75, 0x8B, 0x8E, 0x9A, 0x72, 0x66, 0x9A, 0x8E,
+ 0x66, 0x72, 0x7B, 0x93, 0x85, 0x6D, 0x93, 0x7B,
+ 0x6D, 0x85, 0x9B, 0x9B, 0x65, 0x65, 0x82, 0x9D,
+ 0x7E, 0x63, 0x9D, 0x82, 0x63, 0x7E, 0x9B, 0xA8,
+ 0x65, 0x58, 0xA8, 0x9B, 0x58, 0x65, 0xA9, 0xA9,
+ 0x57, 0x57, 0x8D, 0xAA, 0x73, 0x56, 0xAA, 0x8D,
+ 0x56, 0x73, 0x6E, 0x99, 0x92, 0x67, 0x99, 0x6E,
+ 0x67, 0x92, 0x76, 0xA2, 0x8A, 0x5E, 0xA2, 0x76,
+ 0x5E, 0x8A, 0x7F, 0xAF, 0x81, 0x51, 0xAF, 0x7F,
+ 0x51, 0x81, 0xAB, 0xBA, 0x55, 0x46, 0xBA, 0xAB,
+ 0x46, 0x55, 0x9A, 0xBB, 0x66, 0x45, 0xBB, 0x9A,
+ 0x45, 0x66, 0xBB, 0xBB, 0x45, 0x45, 0x60, 0xA0,
+ 0xA0, 0x60, 0xA0, 0x60, 0x60, 0xA0, 0x8B, 0xBE,
+ 0x75, 0x42, 0xBE, 0x8B, 0x42, 0x75, 0x66, 0xAA,
+ 0x9A, 0x56, 0xAA, 0x66, 0x56, 0x9A, 0x70, 0xB5,
+ 0x90, 0x4B, 0xB5, 0x70, 0x4B, 0x90, 0xBE, 0xCF,
+ 0x42, 0x31, 0xCF, 0xBE, 0x31, 0x42, 0xAB, 0xD0,
+ 0x55, 0x30, 0xD0, 0xAB, 0x30, 0x55, 0xD1, 0xD1,
+ 0x2F, 0x2F, 0x9A, 0xD3, 0x66, 0x2D, 0xD3, 0x9A,
+ 0x2D, 0x66, 0x7B, 0xC5, 0x85, 0x3B, 0xC5, 0x7B,
+ 0x3B, 0x85, 0x54, 0xB4, 0xAC, 0x4C, 0xB4, 0x54,
+ 0x4C, 0xAC, 0x5E, 0xBE, 0xA2, 0x42, 0xBE, 0x5E,
+ 0x42, 0xA2, 0x87, 0xD8, 0x79, 0x28, 0xD8, 0x87,
+ 0x28, 0x79, 0xC0, 0xE8, 0x40, 0x18, 0xE8, 0xC0,
+ 0x18, 0x40, 0xD5, 0xE8, 0x2B, 0x18, 0xE8, 0xD5,
+ 0x18, 0x2B, 0xAB, 0xE9, 0x55, 0x17, 0xE9, 0xAB,
+ 0x17, 0x55, 0x68, 0xCD, 0x98, 0x33, 0xCD, 0x68,
+ 0x33, 0x98, 0xEA, 0xEA, 0x16, 0x16, 0x80, 0x80,
+ ], [
+ 0x80, 0x80, 0x86, 0x86, 0x7A, 0x7A, 0x7E, 0x88,
+ 0x82, 0x78, 0x88, 0x7E, 0x78, 0x82, 0x92, 0x92,
+ 0x6E, 0x6E, 0x85, 0x92, 0x7B, 0x6E, 0x92, 0x85,
+ 0x6E, 0x7B, 0x73, 0x8D, 0x8D, 0x73, 0x8D, 0x73,
+ 0x73, 0x8D, 0x91, 0x9E, 0x6F, 0x62, 0x9E, 0x91,
+ 0x62, 0x6F, 0x79, 0x97, 0x87, 0x69, 0x97, 0x79,
+ 0x69, 0x87, 0xA0, 0xA0, 0x60, 0x60, 0x83, 0xA2,
+ 0x7D, 0x5E, 0xA2, 0x83, 0x5E, 0x7D, 0xA0, 0xB0,
+ 0x60, 0x50, 0xB0, 0xA0, 0x50, 0x60, 0xB1, 0xB1,
+ 0x4F, 0x4F, 0x8F, 0xB2, 0x71, 0x4E, 0xB2, 0x8F,
+ 0x4E, 0x71, 0x6B, 0x9E, 0x95, 0x62, 0x9E, 0x6B,
+ 0x62, 0x95, 0x74, 0xA9, 0x8C, 0x57, 0xA9, 0x74,
+ 0x57, 0x8C, 0x7F, 0xB8, 0x81, 0x48, 0xB8, 0x7F,
+ 0x48, 0x81, 0xB4, 0xC5, 0x4C, 0x3B, 0xC5, 0xB4,
+ 0x3B, 0x4C, 0x9F, 0xC6, 0x61, 0x3A, 0xC6, 0x9F,
+ 0x3A, 0x61, 0xC6, 0xC6, 0x3A, 0x3A, 0x59, 0xA7,
+ 0xA7, 0x59, 0xA7, 0x59, 0x59, 0xA7, 0x8D, 0xCA,
+ 0x73, 0x36, 0xCA, 0x8D, 0x36, 0x73, 0x61, 0xB2,
+ 0x9F, 0x4E, 0xB2, 0x61, 0x4E, 0x9F, 0x6D, 0xBF,
+ 0x93, 0x41, 0xBF, 0x6D, 0x41, 0x93, 0xCA, 0xDF,
+ 0x36, 0x21, 0xDF, 0xCA, 0x21, 0x36, 0xB3, 0xDF,
+ 0x4D, 0x21, 0xDF, 0xB3, 0x21, 0x4D, 0xE1, 0xE1,
+ 0x1F, 0x1F, 0x9F, 0xE3, 0x61, 0x1D, 0xE3, 0x9F,
+ 0x1D, 0x61, 0x7A, 0xD3, 0x86, 0x2D, 0xD3, 0x7A,
+ 0x2D, 0x86, 0x4C, 0xBE, 0xB4, 0x42, 0xBE, 0x4C,
+ 0x42, 0xB4, 0x57, 0xCA, 0xA9, 0x36, 0xCA, 0x57,
+ 0x36, 0xA9, 0x88, 0xE9, 0x78, 0x17, 0xE9, 0x88,
+ 0x17, 0x78, 0xCC, 0xFB, 0x34, 0x05, 0xFB, 0xCC,
+ 0x05, 0x34, 0xE6, 0xFB, 0x1A, 0x05, 0xFB, 0xE6,
+ 0x05, 0x1A, 0xB4, 0xFD, 0x4C, 0x03, 0xFD, 0xB4,
+ 0x03, 0x4C, 0x63, 0xDC, 0x9D, 0x24, 0xDC, 0x63,
+ 0x24, 0x9D, 0xFE, 0xFE, 0x02, 0x02, 0x80, 0x80,
+ ], [
+ 0x80, 0x80, 0x87, 0x87, 0x79, 0x79, 0x7E, 0x89,
+ 0x82, 0x77, 0x89, 0x7E, 0x77, 0x82, 0x95, 0x95,
+ 0x6B, 0x6B, 0x86, 0x96, 0x7A, 0x6A, 0x96, 0x86,
+ 0x6A, 0x7A, 0x70, 0x90, 0x90, 0x70, 0x90, 0x70,
+ 0x70, 0x90, 0x94, 0xA4, 0x6C, 0x5C, 0xA4, 0x94,
+ 0x5C, 0x6C, 0x78, 0x9B, 0x88, 0x65, 0x9B, 0x78,
+ 0x65, 0x88, 0xA6, 0xA6, 0x5A, 0x5A, 0x83, 0xA9,
+ 0x7D, 0x57, 0xA9, 0x83, 0x57, 0x7D, 0xA6, 0xB9,
+ 0x5A, 0x47, 0xB9, 0xA6, 0x47, 0x5A, 0xBA, 0xBA,
+ 0x46, 0x46, 0x92, 0xBC, 0x6E, 0x44, 0xBC, 0x92,
+ 0x44, 0x6E, 0x67, 0xA3, 0x99, 0x5D, 0xA3, 0x67,
+ 0x5D, 0x99, 0x72, 0xB0, 0x8E, 0x50, 0xB0, 0x72,
+ 0x50, 0x8E, 0x7F, 0xC3, 0x81, 0x3D, 0xC3, 0x7F,
+ 0x3D, 0x81, 0xBE, 0xD2, 0x42, 0x2E, 0xD2, 0xBE,
+ 0x2E, 0x42, 0xA5, 0xD4, 0x5B, 0x2C, 0xD4, 0xA5,
+ 0x2C, 0x5B, 0xD4, 0xD4, 0x2C, 0x2C, 0x52, 0xAE,
+ 0xAE, 0x52, 0xAE, 0x52, 0x52, 0xAE, 0x8F, 0xD8,
+ 0x71, 0x28, 0xD8, 0x8F, 0x28, 0x71, 0x5B, 0xBB,
+ 0xA5, 0x45, 0xBB, 0x5B, 0x45, 0xA5, 0x69, 0xCB,
+ 0x97, 0x35, 0xCB, 0x69, 0x35, 0x97, 0xD8, 0xF0,
+ 0x28, 0x10, 0xF0, 0xD8, 0x10, 0x28, 0xBD, 0xF1,
+ 0x43, 0x0F, 0xF1, 0xBD, 0x0F, 0x43, 0xF3, 0xF3,
+ 0x0D, 0x0D, 0xA5, 0xF6, 0x5B, 0x0A, 0xF6, 0xA5,
+ 0x0A, 0x5B, 0x78, 0xE2, 0x88, 0x1E, 0xE2, 0x78,
+ 0x1E, 0x88, 0x42, 0xC9, 0xBE, 0x37, 0xC9, 0x42,
+ 0x37, 0xBE, 0x4F, 0xD8, 0xB1, 0x28, 0xD8, 0x4F,
+ 0x28, 0xB1, 0x8A, 0xFD, 0x76, 0x03, 0xFD, 0x8A,
+ 0x03, 0x76, 0xDB, 0xFF, 0x25, 0x01, 0xFF, 0xDB,
+ 0x01, 0x25, 0xF9, 0xFF, 0x07, 0x01, 0xFF, 0xF9,
+ 0x01, 0x07, 0xBE, 0xFF, 0x42, 0x01, 0xFF, 0xBE,
+ 0x01, 0x42, 0x5E, 0xED, 0xA2, 0x13, 0xED, 0x5E,
+ 0x13, 0xA2, 0xFF, 0xFF, 0x01, 0x01, 0x80, 0x80,
+ ]
+];
+
+static INDEO2_CODE_CODES: &[u16] = &[
+ 0x0000, 0x0004, 0x0006, 0x0001, 0x0009, 0x0019, 0x000D, 0x001D,
+ 0x0023, 0x0013, 0x0033, 0x000B, 0x002B, 0x001B, 0x0007, 0x0087,
+ 0x0027, 0x00A7, 0x0067, 0x00E7, 0x0097, 0x0057, 0x0037, 0x00B7,
+ 0x00F7, 0x000F, 0x008F, 0x018F, 0x014F, 0x00CF, 0x002F, 0x012F,
+ 0x01AF, 0x006F, 0x00EF, 0x01EF, 0x001F, 0x021F, 0x011F, 0x031F,
+ 0x009F, 0x029F, 0x019F, 0x039F, 0x005F, 0x025F, 0x015F, 0x035F,
+ 0x00DF, 0x02DF, 0x01DF, 0x03DF, 0x003F, 0x103F, 0x083F, 0x183F,
+ 0x043F, 0x143F, 0x0C3F, 0x1C3F, 0x023F, 0x123F, 0x0A3F, 0x1A3F,
+ 0x063F, 0x163F, 0x0E3F, 0x1E3F, 0x013F, 0x113F, 0x093F, 0x193F,
+ 0x053F, 0x153F, 0x0D3F, 0x1D3F, 0x033F, 0x133F, 0x0B3F, 0x1B3F,
+ 0x073F, 0x173F, 0x0F3F, 0x1F3F, 0x00BF, 0x10BF, 0x08BF, 0x18BF,
+ 0x04BF, 0x14BF, 0x0CBF, 0x1CBF, 0x02BF, 0x12BF, 0x0ABF, 0x1ABF,
+ 0x06BF, 0x16BF, 0x0EBF, 0x1EBF, 0x01BF, 0x11BF, 0x09BF, 0x19BF,
+ 0x05BF, 0x15BF, 0x0DBF, 0x1DBF, 0x03BF, 0x13BF, 0x0BBF, 0x1BBF,
+ 0x07BF, 0x17BF, 0x0FBF, 0x1FBF, 0x007F, 0x207F, 0x107F, 0x307F,
+ 0x087F, 0x287F, 0x187F, 0x387F, 0x047F, 0x247F, 0x147F, 0x0002,
+ 0x0011, 0x0005, 0x0015, 0x0003, 0x003B, 0x0047, 0x00C7, 0x0017,
+ 0x00D7, 0x0077, 0x010F, 0x004F, 0x01CF, 0x00AF, 0x016F
+];
+
+static INDEO2_CODE_LENGTHS: &[u8] = &[
+ 3, 3, 3, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 3,
+ 5, 5, 5, 6, 6, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9
+];
+
+struct IR2CodeReader { }
+
+impl CodebookDescReader<u8> for IR2CodeReader {
+ fn bits(&mut self, idx: usize) -> u8 { INDEO2_CODE_LENGTHS[idx] }
+ fn code(&mut self, idx: usize) -> u32 { INDEO2_CODE_CODES[idx] as u32 }
+ fn sym (&mut self, idx: usize) -> u8 {
+ if idx < 0x7F { (idx + 1) as u8 } else { (idx + 2) as u8 }
+ }
+ fn len(&mut self) -> usize { INDEO2_CODE_LENGTHS.len() }
+}
+
+struct Indeo2Decoder {
+ info: Rc<NACodecInfo>,
+ cb: Codebook<u8>,
+ frmmgr: HAMShuffler,
+}
+
+impl Indeo2Decoder {
+ fn new() -> Self {
+ let dummy_info = Rc::new(DUMMY_CODEC_INFO);
+ let mut coderead = IR2CodeReader{};
+ let cb = Codebook::new(&mut coderead, CodebookMode::LSB).unwrap();
+ Indeo2Decoder { info: dummy_info, cb: cb, frmmgr: HAMShuffler::new() }
+ }
+
+ fn decode_plane_intra(&self, br: &mut BitReader,
+ buf: &mut NAVideoBuffer<u8>, planeno: usize,
+ tableno: usize) -> DecoderResult<()> {
+ let offs = buf.get_offset(planeno);
+ let (w, h) = buf.get_dimensions(planeno);
+ let stride = buf.get_stride(planeno);
+ let cb = &self.cb;
+
+ let mut data = buf.get_data_mut();
+ let framebuf: &mut [u8] = data.as_mut_slice();
+
+ let table = &INDEO2_DELTA_TABLE[tableno];
+
+ let mut base = offs;
+ let mut x: usize = 0;
+ while x < w {
+ let idx = br.read_cb(cb)? as usize;
+ if idx >= 0x80 {
+ let run = (idx - 0x80) * 2;
+ if x + run > w { return Err(DecoderError::InvalidData); }
+ for i in 0..run {
+ framebuf[base + x + i] = 0x80;
+ }
+ x += run;
+ } else {
+ framebuf[base + x + 0] = table[(idx * 2 + 0) as usize];
+ framebuf[base + x + 1] = table[(idx * 2 + 1) as usize];
+ x += 2;
+ }
+ }
+ base += stride;
+ for _ in 1..h {
+ let mut x: usize = 0;
+ while x < w {
+ let idx = br.read_cb(cb)? as usize;
+ if idx >= 0x80 {
+ let run = (idx - 0x80) * 2;
+ if x + run > w { return Err(DecoderError::InvalidData); }
+ for i in 0..run {
+ framebuf[base + x + i] = framebuf[base + x + i - stride];
+ }
+ x += run;
+ } else {
+ let delta0 = (table[idx * 2 + 0] as i16) - 0x80;
+ let delta1 = (table[idx * 2 + 1] as i16) - 0x80;
+ let mut pix0 = framebuf[base + x + 0 - stride] as i16;
+ let mut pix1 = framebuf[base + x + 1 - stride] as i16;
+ pix0 += delta0;
+ pix1 += delta1;
+ if pix0 < 0 { pix0 = 0; }
+ if pix1 < 0 { pix1 = 0; }
+ if pix0 > 255 { pix0 = 255; }
+ if pix1 > 255 { pix1 = 255; }
+ framebuf[base + x + 0] = pix0 as u8;
+ framebuf[base + x + 1] = pix1 as u8;
+ x += 2;
+ }
+ }
+ base += stride;
+ }
+ Ok(())
+ }
+
+ fn decode_plane_inter(&self, br: &mut BitReader,
+ buf: &mut NAVideoBuffer<u8>, planeno: usize,
+ tableno: usize) -> DecoderResult<()> {
+ let offs = buf.get_offset(planeno);
+ let (w, h) = buf.get_dimensions(planeno);
+ let stride = buf.get_stride(planeno);
+ let cb = &self.cb;
+
+ let mut data = buf.get_data_mut();
+ let framebuf: &mut [u8] = data.as_mut_slice();
+
+ let table = &INDEO2_DELTA_TABLE[tableno];
+
+ let mut base = offs;
+ for _ in 0..h {
+ let mut x: usize = 0;
+ while x < w {
+ let idx = br.read_cb(cb)? as usize;
+ if idx >= 0x80 {
+ let run = (idx - 0x80) * 2;
+ if x + run > w { return Err(DecoderError::InvalidData); }
+ x += run;
+ } else {
+ let delta0 = (table[idx * 2 + 0] as i16) - 0x80;
+ let delta1 = (table[idx * 2 + 1] as i16) - 0x80;
+ let mut pix0 = framebuf[base + x + 0] as i16;
+ let mut pix1 = framebuf[base + x + 1] as i16;
+ pix0 += delta0 * 3 >> 2;
+ pix1 += delta1 * 3 >> 2;
+ if pix0 < 0 { pix0 = 0; }
+ if pix1 < 0 { pix1 = 0; }
+ if pix0 > 255 { pix0 = 255; }
+ if pix1 > 255 { pix1 = 255; }
+ framebuf[base + x + 0] = pix0 as u8;
+ framebuf[base + x + 1] = pix1 as u8;
+ x += 2;
+ }
+ }
+ base += stride;
+ }
+ Ok(())
+ }
+}
+
+const IR2_START: usize = 48;
+
+impl NADecoder for Indeo2Decoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ let w = vinfo.get_width();
+ let h = vinfo.get_height();
+ let f = vinfo.is_flipped();
+ let fmt = formats::YUV410_FORMAT;
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, fmt));
+ self.info = Rc::new(NACodecInfo::new_ref(info.get_name(), myinfo, info.get_extradata()));
+ self.frmmgr.clear();
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ if src.len() <= IR2_START { return Err(DecoderError::ShortData); }
+ let interframe = src[18];
+ let tabs = src[34];
+ let mut br = BitReader::new(&src[IR2_START..], src.len() - IR2_START, BitReaderMode::LE);
+ let luma_tab = tabs & 3;
+ let chroma_tab = (tabs >> 2) & 3;
+ if interframe != 0 {
+ let vinfo = self.info.get_properties().get_video_info().unwrap();
+ let bufret = alloc_video_buffer(vinfo, 2);
+ if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
+ let mut bufinfo = bufret.unwrap();
+ let mut buf = bufinfo.get_vbuf().unwrap();
+ for plane in 0..3 {
+ let tabidx = (if plane == 0 { luma_tab } else { chroma_tab }) as usize;
+ self.decode_plane_intra(&mut br, &mut buf, plane, tabidx)?;
+ }
+ self.frmmgr.add_frame(buf);
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(true);
+ frm.set_frame_type(FrameType::I);
+ Ok(Rc::new(RefCell::new(frm)))
+ } else {
+ let bufret = self.frmmgr.clone_ref();
+ if let None = bufret { return Err(DecoderError::MissingReference); }
+ let mut buf = bufret.unwrap();
+
+ for plane in 0..3 {
+ let tabidx = (if plane == 0 { luma_tab } else { chroma_tab }) as usize;
+ self.decode_plane_inter(&mut br, &mut buf, plane, tabidx)?;
+ }
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), NABufferType::Video(buf));
+ frm.set_keyframe(false);
+ frm.set_frame_type(FrameType::P);
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+ }
+}
+
+pub fn get_decoder() -> Box<NADecoder> {
+ Box::new(Indeo2Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use crate::test::dec_video::test_file_decoding;
+ #[test]
+ fn test_indeo2() {
+ test_file_decoding("avi", "assets/laser05.avi", Some(10), true, false, None);
+ }
+}
diff --git a/nihav-indeo/src/codecs/indeo3.rs b/nihav-indeo/src/codecs/indeo3.rs
new file mode 100644
index 0000000..e17c118
--- /dev/null
+++ b/nihav-indeo/src/codecs/indeo3.rs
@@ -0,0 +1,1463 @@
+use std::rc::Rc;
+use std::cell::RefCell;
+use nihav_core::formats;
+use nihav_core::codecs::*;
+use nihav_core::frame::*;
+use nihav_core::io::byteio::*;
+use std::io::SeekFrom;
+use std::mem;
+
+struct IviDeltaCB {
+ quad_radix: u8,
+ data: &'static [i8],
+}
+
+#[derive(Clone, Copy)]
+struct MV {
+ x: i8,
+ y: i8
+}
+
+struct Buffers {
+ width: usize,
+ height: usize,
+ buf1: Vec<u8>,
+ buf2: Vec<u8>,
+ fbuf: bool,
+}
+
+const DEFAULT_PIXEL: u8 = 0x40;
+
+impl Buffers {
+ fn new() -> Self { Buffers { width: 0, height: 0, buf1: Vec::new(), buf2: Vec::new(), fbuf: true } }
+ fn reset(&mut self) {
+ self.width = 0;
+ self.height = 0;
+ self.buf1.truncate(0);
+ self.buf2.truncate(0);
+ }
+ fn alloc(&mut self, w: usize, h: usize) {
+ self.width = w;
+ self.height = h;
+ self.buf1.resize(w * h + (w >> 2) * (h >> 2) * 2, DEFAULT_PIXEL);
+ self.buf2.resize(w * h + (w >> 2) * (h >> 2) * 2, DEFAULT_PIXEL);
+ }
+ fn flip(&mut self) { self.fbuf = !self.fbuf; }
+ fn get_stride(&mut self, planeno: usize) -> usize {
+ if planeno == 0 { self.width } else { self.width >> 2 }
+ }
+ fn get_offset(&mut self, planeno: usize) -> usize {
+ match planeno {
+ 1 => self.width * self.height,
+ 2 => self.width * self.height + (self.width >> 2) * (self.height >> 2),
+ _ => 0,
+ }
+ }
+ fn fill_framebuf(&mut self, fbuf: &mut NAVideoBuffer<u8>) {
+ for planeno in 0..3 {
+ let mut soff = self.get_offset(planeno);
+ let mut doff = fbuf.get_offset(planeno);
+ let sstride = self.get_stride(planeno);
+ let dstride = fbuf.get_stride(planeno);
+ let width = if planeno == 0 { self.width } else { self.width >> 2 };
+ let height = if planeno == 0 { self.height } else { self.height >> 2 };
+ let src = if self.fbuf { &self.buf1[0..] } else { &self.buf2[0..] };
+ let mut dst = fbuf.get_data_mut();
+ for _ in 0..height {
+ for x in 0..width {
+ dst[doff + x] = src[soff + x] * 2;
+ }
+ soff += sstride;
+ doff += dstride;
+ }
+ }
+ }
+ fn copy_block(&mut self, doff: usize, soff: usize, stride: usize, w: usize, h: usize) {
+ let mut sidx = soff;
+ let mut didx = doff;
+ if self.fbuf {
+ for _ in 0..h {
+ for i in 0..w { self.buf1[didx + i] = self.buf2[sidx + i]; }
+ sidx += stride;
+ didx += stride;
+ }
+ } else {
+ for _ in 0..h {
+ for i in 0..w { self.buf2[didx + i] = self.buf1[sidx + i]; }
+ sidx += stride;
+ didx += stride;
+ }
+ }
+ }
+ fn fill_block(&mut self, doff: usize, stride: usize, w: usize, h: usize, topline: bool) {
+ let mut didx = doff;
+ let mut buf: [u8; 8] = [0; 8];
+ if topline {
+ if self.fbuf {
+ for _ in 0..h {
+ for i in 0..w { self.buf1[didx + i] = DEFAULT_PIXEL; }
+ didx += stride;
+ }
+ } else {
+ for _ in 0..h {
+ for i in 0..w { self.buf2[didx + i] = DEFAULT_PIXEL; }
+ didx += stride;
+ }
+ }
+ } else {
+ if self.fbuf {
+ for i in 0..w { buf[i] = self.buf1[didx - stride + i]; }
+ for _ in 0..h {
+ for i in 0..w { self.buf1[didx + i] = buf[i]; }
+ didx += stride;
+ }
+ } else {
+ for i in 0..w { buf[i] = self.buf2[didx - stride + i]; }
+ for _ in 0..h {
+ for i in 0..w { self.buf2[didx + i] = buf[i]; }
+ didx += stride;
+ }
+ }
+ }
+ }
+}
+
+#[allow(unused_variables)]
+fn apply_delta4x4(bufs: &mut Buffers, off: usize, stride: usize,
+ deltas: &[u8], topline: bool, first_line: bool) {
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + 4)] }
+ else { &mut bufs.buf2[off..(off + 4)] };
+ for i in 0..4 { dst[i] = dst[i].wrapping_add(deltas[i]) & 0x7F; }
+}
+
+#[allow(unused_variables)]
+fn apply_delta4x8(bufs: &mut Buffers, off: usize, stride: usize,
+ deltas: &[u8], topline: bool, first_line: bool) {
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + 4 + stride)] }
+ else { &mut bufs.buf2[off..(off + 4 + stride)] };
+ for i in 0..4 { dst[i + stride] = dst[i].wrapping_add(deltas[i]) & 0x7F; }
+ if !topline {
+ for i in 0..4 { dst[i] = (dst[i + stride] + dst[i]) >> 1; }
+ } else {
+ for i in 0..4 { dst[i] = dst[i + stride]; }
+ }
+}
+
+#[allow(unused_variables)]
+fn apply_delta4x8m11(bufs: &mut Buffers, off: usize, stride: usize,
+ deltas: &[u8], topline: bool, first_line: bool) {
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + 4 + stride)] }
+ else { &mut bufs.buf2[off..(off + 4 + stride)] };
+ for i in 0..4 { dst[i] = dst[i] .wrapping_add(deltas[i]) & 0x7F; }
+ for i in 0..4 { dst[i + stride] = dst[i + stride].wrapping_add(deltas[i]) & 0x7F; }
+}
+
+#[allow(unused_variables)]
+fn apply_delta8x8p(bufs: &mut Buffers, off: usize, stride: usize,
+ deltas: &[u8], topline: bool, first_line: bool) {
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + 8 + stride)] }
+ else { &mut bufs.buf2[off..(off + 8 + stride)] };
+ for i in 0..8 { dst[i] = dst[i] .wrapping_add(deltas[i >> 1]) & 0x7F; }
+ for i in 0..8 { dst[i + stride] = dst[i + stride].wrapping_add(deltas[i >> 1]) & 0x7F; }
+}
+
+fn apply_delta8x8i(bufs: &mut Buffers, off: usize, stride: usize,
+ deltas: &[u8], topline: bool, firstline: bool) {
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + 8 + stride)] }
+ else { &mut bufs.buf2[off..(off + 8 + stride)] };
+ if !firstline {
+ for i in 0..8 { dst[i + stride] = dst[i ].wrapping_add(deltas[i >> 1]) & 0x7F; }
+ } else {
+ for i in 0..8 { dst[i + stride] = dst[i & !1].wrapping_add(deltas[i >> 1]) & 0x7F; }
+ }
+ if !topline {
+ for i in 0..8 { dst[i] = (dst[i + stride] + dst[i]) >> 1; }
+ } else {
+ for i in 0..8 { dst[i] = dst[i + stride]; }
+ }
+}
+
+fn copy_line_top(bufs: &mut Buffers, off: usize, stride: usize, bw: usize, topline: bool) {
+ let mut buf: [u8; 8] = [0; 8];
+ if !topline {
+ let src = if bufs.fbuf { &bufs.buf1[(off - stride)..(off - stride + bw)] }
+ else { &bufs.buf2[(off - stride)..(off - stride + bw)] };
+ for i in 0..bw { buf[i] = src[i]; }
+ } else {
+ for i in 0..bw { buf[i] = DEFAULT_PIXEL; }
+ }
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + bw)] }
+ else { &mut bufs.buf2[off..(off + bw)] };
+ for i in 0..bw { dst[i] = buf[i]; }
+}
+
+fn copy_line_top4x4(bufs: &mut Buffers, off: usize, stride: usize, topline: bool) {
+ copy_line_top(bufs, off, stride, 4, topline);
+}
+
+fn copy_line_top4x8(bufs: &mut Buffers, off: usize, stride: usize, topline: bool) {
+ copy_line_top(bufs, off, stride, 4, topline);
+ copy_line_top(bufs, off + stride, stride, 4, false);
+}
+
+fn copy_line_top8x8(bufs: &mut Buffers, off: usize, stride: usize, topline: bool) {
+ let mut buf: [u8; 8] = [0; 8];
+ if !topline {
+ let src = if bufs.fbuf { &bufs.buf1[(off - stride)..(off - stride + 8)] }
+ else { &bufs.buf2[(off - stride)..(off - stride + 8)] };
+ for i in 0..8 { buf[i] = src[i & !1]; }
+ } else {
+ for i in 0..8 { buf[i] = DEFAULT_PIXEL; }
+ }
+ let dst = if bufs.fbuf { &mut bufs.buf1[off..(off + 8)] }
+ else { &mut bufs.buf2[off..(off + 8)] };
+ for i in 0..8 {dst[i] = buf[i]; }
+}
+
+fn fill_block8x8(bufs: &mut Buffers, doff: usize, stride: usize, h: usize, topline: bool, firstline: bool) {
+ let mut didx = doff;
+ let mut buf: [u8; 8] = [0; 8];
+ if firstline {
+ for i in 0..8 { buf[i] = DEFAULT_PIXEL; }
+ } else if bufs.fbuf {
+ for i in 0..8 { buf[i] = bufs.buf1[doff - stride + i]; }
+ } else {
+ for i in 0..8 { buf[i] = bufs.buf1[doff - stride + i]; }
+ }
+ if topline && !firstline {
+ for i in 0..4 { buf[i * 2 + 1] = buf[i * 2]; }
+ if bufs.fbuf {
+ for i in 0..8 { bufs.buf1[doff + i] = (bufs.buf1[doff - stride + i] + buf[i]) >> 1; }
+ } else {
+ for i in 0..8 { bufs.buf2[doff + i] = (bufs.buf2[doff - stride + i] + buf[i]) >> 1; }
+ }
+ }
+
+ let start = if !topline { 0 } else { 1 };
+ if bufs.fbuf {
+ for _ in start..h {
+ for i in 0..8 { bufs.buf1[didx + i] = buf[i]; }
+ didx += stride;
+ }
+ } else {
+ for _ in start..h {
+ for i in 0..8 { bufs.buf2[didx + i] = buf[i]; }
+ didx += stride;
+ }
+ }
+}
+
+struct Indeo3Decoder {
+ info: Rc<NACodecInfo>,
+ bpos: u8,
+ bbuf: u8,
+ width: u16,
+ height: u16,
+ mvs: Vec<MV>,
+ altquant: [u8; 16],
+ vq_offset: u8,
+ bufs: Buffers,
+}
+
+#[derive(Clone,Copy)]
+struct IV3Cell {
+ x: u16,
+ y: u16,
+ w: u16,
+ h: u16,
+ d: u8,
+ vqt: bool,
+ mv: Option<MV>,
+}
+
+impl IV3Cell {
+ fn new(w: u16, h: u16) -> Self {
+ IV3Cell { x: 0, y: 0, w: w, h: h, d: 20, vqt: false, mv: None }
+ }
+ fn split_h(&self) -> (Self, Self) {
+ let h1 = if self.h > 2 { ((self.h + 2) >> 2) << 1 } else { 1 };
+ let h2 = self.h - h1;
+ let mut cell1 = *self;
+ cell1.h = h1;
+ cell1.d -= 1;
+ let mut cell2 = *self;
+ cell2.y += h1;
+ cell2.h = h2;
+ cell2.d -= 1;
+ (cell1, cell2)
+ }
+ fn split_w(&self, stripw: u16) -> (Self, Self) {
+ let w1 = if self.w > stripw {
+ if self.w > stripw * 2 { stripw * 2 } else { stripw }
+ } else {
+ if self.w > 2 { ((self.w + 2) >> 2) << 1 } else { 1 }
+ };
+ let w2 = self.w - w1;
+ let mut cell1 = *self;
+ cell1.w = w1;
+ cell1.d -= 1;
+ let mut cell2 = *self;
+ cell2.x += w1;
+ cell2.w = w2;
+ cell2.d -= 1;
+ (cell1, cell2)
+ }
+ fn no_mv(&self) -> bool { match self.mv { None => true, Some(_) => false } }
+}
+
+struct CellDecParams {
+ tab: [usize; 2],
+ bw: u16,
+ bh: u16,
+ swap_q: [bool; 2],
+ hq: bool,
+ apply_delta: fn (&mut Buffers, usize, usize, &[u8], bool, bool),
+ copy_line_top: fn (&mut Buffers, usize, usize, bool),
+}
+
+const FRMH_TAG: u32 = ((b'F' as u32) << 24) | ((b'R' as u32) << 16)
+ | ((b'M' as u32) << 8) | (b'H' as u32);
+
+const H_SPLIT: u8 = 0;
+const V_SPLIT: u8 = 1;
+const SKIP_OR_TREE: u8 = 2;
+
+impl Indeo3Decoder {
+ fn new() -> Self {
+ let dummy_info = Rc::new(DUMMY_CODEC_INFO);
+ Indeo3Decoder { info: dummy_info, bpos: 0, bbuf: 0, width: 0, height: 0,
+ mvs: Vec::new(), altquant: [0; 16],
+ vq_offset: 0, bufs: Buffers::new() }
+ }
+
+ fn br_reset(&mut self) {
+ self.bpos = 0;
+ self.bbuf = 0;
+ }
+
+ fn get_2bits(&mut self, br: &mut ByteReader) -> DecoderResult<u8> {
+ if self.bpos == 0 {
+ self.bbuf = br.read_byte()?;
+ self.bpos = 8;
+ }
+ self.bpos -= 2;
+ Ok((self.bbuf >> self.bpos) & 0x3)
+ }
+
+ fn decode_cell_data(&mut self, br: &mut ByteReader, cell: IV3Cell,
+ off: usize, stride: usize, params: CellDecParams) -> DecoderResult<()> {
+ let blk_w = cell.w * 4 / params.bw;
+ let blk_h = cell.h * 4 / params.bh;
+ let scale: usize = if params.bh == 4 { 1 } else { 2 };
+
+ validate!((((cell.w * 4) % params.bw) == 0) && (((cell.h * 4) % params.bh) == 0));
+
+ let mut run_blocks = 0;
+ let mut run_skip = false;
+
+ let mut didx: usize = ((cell.x*4) as usize) + ((cell.y * 4) as usize) * stride + off;
+ let mut sidx: usize;
+ if cell.no_mv() {
+ sidx = 0;
+ } else {
+ let mv = cell.mv.unwrap();
+ let mx = mv.x as i16;
+ let my = mv.y as i16;
+ let l = (cell.x as i16) * 4 + mx;
+ let t = (cell.y as i16) * 4 + my;
+ let r = ((cell.x + cell.w) as i16) * 4 + mx;
+ let b = ((cell.y + cell.h) as i16) * 4 + my;
+ validate!(l >= 0);
+ validate!(t >= 0);
+ validate!(r <= (self.width as i16));
+ validate!(b <= (self.height as i16));
+ sidx = (l as usize) + (t as usize) * stride + off;
+ }
+ for y in 0..blk_h {
+ let mut xoff: usize = 0;
+ for _ in 0..blk_w {
+ if run_blocks > 0 {
+ if !run_skip || !cell.no_mv() {
+ if !(params.bw == 8 && cell.no_mv()) {
+ if !cell.no_mv() {
+ self.bufs.copy_block(didx + xoff, sidx + xoff, stride,
+ params.bw as usize, params.bh as usize);
+ } else {
+ self.bufs.fill_block(didx + xoff, stride,
+ params.bw as usize, params.bh as usize,
+ (cell.y == 0) && (y == 0));
+ }
+ } else {
+ fill_block8x8(&mut self.bufs,
+ didx + xoff, stride, 8,
+ y == 0, (cell.y == 0) && (y == 0));
+ }
+ }
+ run_blocks -= 1;
+ } else {
+ let mut line: usize = 0;
+ while line < 4 {
+ let c = br.read_byte()?;
+ if c < 0xF8 {
+ let delta_tab = if params.hq {
+ IVI3_DELTA_CBS[params.tab[line & 1]]
+ } else {
+ IVI3_DELTA_CBS[params.tab[1]]
+ };
+ let mut idx1;
+ let mut idx2;
+ if (c as usize) < delta_tab.data.len()/2 {
+ idx1 = br.read_byte()? as usize;
+ validate!(idx1 < delta_tab.data.len());
+ idx2 = c as usize;
+ } else {
+ let tmp = (c as usize) - delta_tab.data.len()/2;
+ idx1 = tmp / (delta_tab.quad_radix as usize);
+ idx2 = tmp % (delta_tab.quad_radix as usize);
+ if params.swap_q[line & 1] {
+ mem::swap(&mut idx1, &mut idx2);
+ }
+ }
+ let deltas: [u8; 4] = [delta_tab.data[idx1 * 2] as u8,
+ delta_tab.data[idx1 * 2 + 1] as u8,
+ delta_tab.data[idx2 * 2 + 0] as u8,
+ delta_tab.data[idx2 * 2 + 1] as u8];
+ let topline = (cell.y == 0) && (y == 0) && (line == 0);
+ let first_line = (y == 0) && (line == 0);
+ if cell.no_mv() {
+ (params.copy_line_top)(&mut self.bufs,
+ didx + xoff + line * scale * stride,
+ stride, topline);
+ } else {
+ self.bufs.copy_block(didx + xoff + line * scale * stride,
+ sidx + xoff + line * scale * stride,
+ stride, params.bw as usize, scale);
+ }
+ (params.apply_delta)(&mut self.bufs,
+ didx + xoff + line * scale * stride,
+ stride, &deltas, topline, first_line);
+ line += 1;
+ } else {
+ let mut tocopy: usize = 0;
+ let mut do_copy = true;
+ if c == 0xF8 { return Err(DecoderError::InvalidData); }
+ if c == 0xF9 {
+ run_blocks = 1;
+ run_skip = true;
+ validate!(line == 0);
+ tocopy = 4;
+ do_copy = !cell.no_mv();
+ }
+ if c == 0xFA {
+ validate!(line == 0);
+ tocopy = 4;
+ do_copy = !cell.no_mv();
+ }
+ if c == 0xFB {
+ let c = br.read_byte()?;
+ validate!((c < 64) && ((c & 0x1F) != 0));
+ run_blocks = (c & 0x1F) - 1;
+ run_skip = (c & 0x20) != 0;
+ tocopy = 4 - line;
+ if params.bw == 4 && cell.no_mv() && run_skip {
+ do_copy = false;
+ }
+ }
+ if c == 0xFC {
+ run_skip = false;
+ run_blocks = 1;
+ tocopy = 4 - line;
+ }
+ if c >= 0xFD {
+ let nl = 257 - (c as i16) - (line as i16);
+ validate!(nl > 0);
+ tocopy = nl as usize;
+ }
+ if do_copy {
+ if !(params.bw == 8 && cell.no_mv()) {
+ if !cell.no_mv() {
+ self.bufs.copy_block(didx + xoff + line * scale * stride,
+ sidx + xoff + line * scale * stride,
+ stride, params.bw as usize,
+ tocopy * scale);
+ } else {
+ self.bufs.fill_block(didx + xoff + line * scale * stride,
+ stride, params.bw as usize,
+ tocopy * scale,
+ (cell.y == 0) && (y == 0) && (line == 0));
+ }
+ } else {
+ fill_block8x8(&mut self.bufs,
+ didx + xoff + line * 2 * stride,
+ stride, tocopy * 2,
+ (y == 0) && (line == 0),
+ (cell.y == 0) && (y == 0) && (line == 0));
+ }
+ }
+ line += tocopy;
+ }
+ }
+ }
+ xoff += params.bw as usize;
+ }
+ didx += stride * (params.bh as usize);
+ sidx += stride * (params.bh as usize);
+ }
+ Ok(())
+ }
+
+ fn copy_cell(&mut self, cell: IV3Cell, off: usize, stride: usize) -> DecoderResult<()> {
+ if cell.no_mv() { return Err(DecoderError::InvalidData); }
+ let mv = cell.mv.unwrap();
+ let mx = mv.x as i16;
+ let my = mv.y as i16;
+ let l = (cell.x as i16) * 4 + mx;
+ let t = (cell.y as i16) * 4 + my;
+ let r = ((cell.x + cell.w) as i16) * 4 + mx;
+ let b = ((cell.y + cell.h) as i16) * 4 + my;
+ validate!(l >= 0);
+ validate!(t >= 0);
+ validate!(r <= (self.width as i16));
+ validate!(b <= (self.height as i16));
+ let sidx: usize = off + (l as usize) + (t as usize) * stride;
+ let didx: usize = off + ((cell.x * 4) as usize) + ((cell.y * 4) as usize) * stride;
+ self.bufs.copy_block(didx, sidx, stride, (cell.w * 4) as usize, (cell.h * 4) as usize);
+ Ok(())
+ }
+
+ fn decode_cell(&mut self, br: &mut ByteReader, cell: IV3Cell, off: usize,
+ stride: usize, intra: bool) -> DecoderResult<()> {
+ let code = br.read_byte()?;
+ let mode = code >> 4;
+ let vq_idx = code & 0xF;
+
+ let mut idx1: usize = vq_idx as usize;
+ let mut idx2: usize = vq_idx as usize;
+ if (mode == 1) || (mode == 4) {
+ let c = self.altquant[vq_idx as usize];
+ idx1 = (c >> 4) as usize;
+ idx2 = (c & 0xF) as usize;
+ }
+
+ idx1 += self.vq_offset as usize;
+ idx2 += self.vq_offset as usize;
+ validate!((idx1 < 24) && (idx2 < 24));
+
+ let mut cp = CellDecParams {
+ tab: [idx2, idx1],
+ bw: 0, bh: 0,
+ swap_q: [idx2 >= 16, idx1 >= 16],
+ hq: false,
+ apply_delta: apply_delta4x4,
+ copy_line_top: copy_line_top4x4,
+ };
+ if (mode == 0) || (mode == 1) {
+ cp.bw = 4;
+ cp.bh = 4;
+ cp.hq = true;
+ } else if (mode == 3) || (mode == 4) {
+ if !cell.no_mv() { return Err(DecoderError::InvalidData); }
+ cp.bw = 4;
+ cp.bh = 8;
+ cp.hq = true;
+ cp.apply_delta = apply_delta4x8;
+ cp.copy_line_top = copy_line_top4x8;
+ } else if mode == 10 {
+ if !cell.no_mv() {
+ validate!(!intra);
+ cp.apply_delta = apply_delta8x8p;
+ } else {
+ cp.apply_delta = apply_delta8x8i;
+ }
+ cp.bw = 8;
+ cp.bh = 8;
+ cp.copy_line_top = copy_line_top8x8;
+ } else if mode == 11 {
+ if cell.no_mv() { return Err(DecoderError::InvalidData); }
+ validate!(!intra);
+ cp.bw = 4;
+ cp.bh = 8;
+ cp.apply_delta = apply_delta4x8m11;
+ cp.copy_line_top = copy_line_top4x8;
+ } else {
+ return Err(DecoderError::InvalidData);
+ }
+ self.decode_cell_data(br, cell, off, stride, cp)
+ }
+
+ fn parse_tree(&mut self, br: &mut ByteReader, cell: IV3Cell, off: usize,
+ stride: usize, stripw: u16, intra: bool) -> DecoderResult<()> {
+ let op = self.get_2bits(br)?;
+ if op == H_SPLIT {
+ validate!(cell.h > 1);
+ validate!(cell.d > 0);
+ let (cell1, cell2) = cell.split_h();
+ self.parse_tree(br, cell1, off, stride, stripw, intra)?;
+ self.parse_tree(br, cell2, off, stride, stripw, intra)?;
+ Ok(())
+ } else if op == V_SPLIT {
+ validate!(cell.w > 1);
+ validate!(cell.d > 0);
+ let (cell1, cell2) = cell.split_w(stripw);
+ self.parse_tree(br, cell1, off, stride, stripw, intra)?;
+ self.parse_tree(br, cell2, off, stride, stripw, intra)?;
+ Ok(())
+ } else if op == SKIP_OR_TREE {
+ if !cell.vqt {
+ let mut newcell = cell;
+ newcell.vqt = true;
+ newcell.d -= 1;
+ self.parse_tree(br, newcell, off, stride, stripw, intra)
+ } else {
+ validate!(!intra);
+ let code = self.get_2bits(br)?;
+ validate!(code < 2);
+ if code == 1 { return Err(DecoderError::NotImplemented); }
+ self.copy_cell(cell, off, stride)
+ }
+ } else {
+ if !cell.vqt {
+ let mut newcell = cell;
+ newcell.vqt = true;
+ newcell.d -= 1;
+ let mv_idx = br.read_byte()? as usize;
+ validate!(mv_idx < self.mvs.len());
+ newcell.mv = Some(self.mvs[mv_idx]);
+ self.parse_tree(br, newcell, off, stride, stripw, intra)
+ } else {
+ self.decode_cell(br, cell, off, stride, intra)
+ }
+ }
+ }
+
+ fn decode_plane_intra(&mut self, br: &mut ByteReader, planeno: usize,
+ start: u64, end: u64) -> DecoderResult<()> {
+ let offs = self.bufs.get_offset(planeno);
+ let stride = self.bufs.get_stride(planeno);
+ br.seek(SeekFrom::Start(start))?;
+
+ let nvec = br.read_u32le()?;
+ validate!(nvec == 0); // for intra there should be no mc_vecs
+ self.mvs.truncate(0);
+ for _ in 0..nvec {
+ let x = br.read_byte()? as i8;
+ let y = br.read_byte()? as i8;
+ self.mvs.push(MV{ x: x, y: y });
+ }
+
+ let shift = if planeno == 0 { 2 } else { 4 };
+ let cell = IV3Cell::new((self.bufs.width >> shift) as u16,
+ (self.bufs.height >> shift) as u16);
+ self.br_reset();
+ self.parse_tree(br, cell, offs, stride, if planeno > 0 { 10 } else { 40 }, true)?;
+ validate!(br.tell() <= end);
+ Ok(())
+ }
+
+ fn decode_plane_inter(&mut self, br: &mut ByteReader, planeno: usize,
+ start: u64, end: u64) -> DecoderResult<()> {
+ let offs = self.bufs.get_offset(planeno);
+ let stride = self.bufs.get_stride(planeno);
+ br.seek(SeekFrom::Start(start))?;
+
+ let nvec = br.read_u32le()?;
+ validate!(nvec <= 256); // for intra there should be no mc_vecs
+ self.mvs.truncate(0);
+ for _ in 0..nvec {
+ let y = br.read_byte()? as i8;
+ let x = br.read_byte()? as i8;
+ self.mvs.push(MV{ x: x, y: y });
+ }
+
+ let shift = if planeno == 0 { 2 } else { 4 };
+ let cell = IV3Cell::new((self.bufs.width >> shift) as u16,
+ (self.bufs.height >> shift) as u16);
+ self.br_reset();
+ self.parse_tree(br, cell, offs, stride, if planeno > 0 { 10 } else { 40 }, false)?;
+ validate!(br.tell() <= end);
+ Ok(())
+ }
+}
+
+const FLAG_KEYFRAME: u16 = 1 << 2;
+const FLAG_NONREF: u16 = 1 << 8;
+
+impl NADecoder for Indeo3Decoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ let w = vinfo.get_width();
+ let h = vinfo.get_height();
+ let fmt = formats::YUV410_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()));
+ self.bufs.reset();
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let src = pkt.get_buffer();
+ let mut mr = MemoryReader::new_read(&src);
+ let mut br = ByteReader::new(&mut mr);
+ let frameno = br.read_u32le()?;
+ let hdr_2 = br.read_u32le()?;
+ let check = br.read_u32le()?;
+ let size = br.read_u32le()?;
+
+ let data_start = br.tell();
+
+ if (frameno ^ hdr_2 ^ size ^ FRMH_TAG) != check {
+ return Err(DecoderError::InvalidData);
+ }
+ if (size as i64) > br.left() { return Err(DecoderError::InvalidData); }
+ let ver = br.read_u16le()?;
+ if ver != 32 { return Err(DecoderError::NotImplemented); }
+ let flags = br.read_u16le()?;
+ let size2 = br.read_u32le()?;
+ validate!(((size2 + 7) >> 3) <= size);
+ let cb = br.read_byte()?;
+ self.vq_offset = cb;
+ br.read_skip(3)?;
+ let height = br.read_u16le()?;
+ let width = br.read_u16le()?;
+ validate!((width >= 16) && (width <= 640));
+ validate!((height >= 16) && (height <= 640));
+ validate!(((width & 3) == 0) && ((height & 3) == 0));
+ if (self.bufs.width != (width as usize)) || (self.bufs.height != (height as usize)) {
+ self.bufs.alloc(width as usize, height as usize);
+ }
+ self.width = width;
+ self.height = height;
+
+ let yoff = br.read_u32le()?;
+ let uoff = br.read_u32le()?;
+ let voff = br.read_u32le()?;
+ if yoff > size { return Err(DecoderError::InvalidData); }
+ if uoff > size { return Err(DecoderError::InvalidData); }
+ if voff > size { return Err(DecoderError::InvalidData); }
+
+ br.read_skip(4)?;
+ br.read_buf(&mut self.altquant)?;
+
+ let mut yend = src.len() as u32;//size;
+ if (uoff < yend) && (uoff > yoff) { yend = uoff; }
+ if (voff < yend) && (voff > yoff) { yend = voff; }
+ let mut uend = size;
+ if (yoff < uend) && (yoff > uoff) { uend = yoff; }
+ if (voff < uend) && (voff > uoff) { uend = voff; }
+ let mut vend = size;
+ if (yoff < vend) && (yoff > voff) { vend = yoff; }
+ if (uoff < vend) && (uoff > voff) { vend = uoff; }
+
+ let intraframe = (flags & FLAG_KEYFRAME) != 0;
+ let vinfo = self.info.get_properties().get_video_info().unwrap();
+ let bufret = alloc_video_buffer(vinfo, 2);
+ if let Err(_) = bufret { return Err(DecoderError::InvalidData); }
+ let mut bufinfo = bufret.unwrap();
+ let mut buf = bufinfo.get_vbuf().unwrap();
+ let ystart = data_start + (yoff as u64);
+ let ustart = data_start + (uoff as u64);
+ let vstart = data_start + (voff as u64);
+ let yendpos = data_start + (yend as u64);
+ let uendpos = data_start + (uend as u64);
+ let vendpos = data_start + (vend as u64);
+ if intraframe {
+ self.decode_plane_intra(&mut br, 0, ystart, yendpos)?;
+ self.decode_plane_intra(&mut br, 1, ustart, uendpos)?;
+ self.decode_plane_intra(&mut br, 2, vstart, vendpos)?;
+ } else {
+ self.decode_plane_inter(&mut br, 0, ystart, yendpos)?;
+ self.decode_plane_inter(&mut br, 1, ustart, uendpos)?;
+ self.decode_plane_inter(&mut br, 2, vstart, vendpos)?;
+ }
+ self.bufs.fill_framebuf(&mut buf);
+ if (flags & FLAG_NONREF) == 0 { self.bufs.flip(); }
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(intraframe);
+ frm.set_frame_type(if intraframe { FrameType::I } else { FrameType::P });
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+}
+
+pub fn get_decoder() -> Box<NADecoder> {
+ Box::new(Indeo3Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use crate::test::dec_video::test_file_decoding;
+ #[test]
+ fn test_indeo3() {
+ test_file_decoding("avi", "assets/iv32_example.avi", Some(10), true, false, None);
+ }
+}
+
+const DT_1_1: IviDeltaCB = IviDeltaCB{ quad_radix: 7, data: &[
+ 0, 0, 2, 2, -2, -2, -1, 3,
+ 1, -3, 3, -1, -3, 1, 4, 4,
+ -4, -4, 1, 5, -1, -5, 5, 1,
+ -5, -1, -4, 4, 4, -4, -2, 6,
+ 2, -6, 6, -2, -6, 2, 4, 9,
+ -4, -9, 9, 4, -9, -4, 9, 9,
+ -9, -9, 1, 10, -1, -10, 10, 1,
+ -10, -1, -5, 8, 5, -8, 8, -5,
+ -8, 5, 9, 15, -9, -15, 15, 9,
+ -15, -9, -3, 12, 3, -12, 12, -3,
+ -12, 3, 4, 16, -4, -16, 16, 4,
+ -16, -4, 16, 16, -16, -16, 0, 18,
+ 0, -18, 18, 0, -18, 0, -12, 12,
+ 12, -12, -9, 16, 9, -16, 16, -9,
+ -16, 9, 11, 27, -11, -27, 27, 11,
+ -27, -11, 19, 28, -19, -28, 28, 19,
+ -28, -19, -6, 22, 6, -22, 22, -6,
+ -22, 6, 4, 29, -4, -29, 29, 4,
+ -29, -4, 30, 30, -30, -30, -2, 33,
+ 2, -33, 33, -2, -33, 2, -18, 23,
+ 18, -23, 23, -18, -23, 18, -15, 30,
+ 15, -30, 30, -15, -30, 15, 22, 46,
+ -22, -46, 46, 22, -46, -22, 13, 47,
+ -13, -47, 47, 13, -47, -13, 35, 49,
+ -35, -49, 49, 35, -49, -35, -11, 41,
+ 11, -41, 41, -11, -41, 11, 4, 51,
+ -4, -51, 51, 4, -51, -4, 54, 54,
+ -54, -54, -34, 34, 34, -34, -29, 42,
+ 29, -42, 42, -29, -42, 29, -6, 60,
+ 6, -60, 60, -6, -60, 6, 27, 76,
+ -27, -76, 76, 27, -76, -27, 43, 77,
+ -43, -77, 77, 43, -77, -43, -24, 55,
+ 24, -55, 55, -24, -55, 24, 14, 79,
+ -14, -79, 79, 14, -79, -14, 63, 83,
+ -63, -83, 83, 63, -83, -63, -20, 74,
+ 20, -74, 74, -20, -74, 20, 2, 88,
+ -2, -88, 88, 2, -88, -2, 93, 93,
+ -93, -93, -52, 61, 52, -61, 61, -52,
+ -61, 52, 52, 120, -52, -120, 120, 52,
+ -120, -52, -45, 75, 45, -75, 75, -45,
+ -75, 45, 75, 125, -75, -125, 125, 75,
+ -125, -75, 33, 122, -33, -122, 122, 33,
+ -122, -33, -13, 103, 13, -103, 103, -13,
+ -103, 13, -40, 96, 40, -96, 96, -40,
+ -96, 40, -34, 127, 34, -127, 127, -34,
+ -127, 34, -89, 89, 89, -89, -78, 105,
+ 78, -105, 105, -78, -105, 78, 12, 12,
+ -12, -12, 23, 23, -23, -23, 42, 42,
+ -42, -42, 73, 73, -73, -73,
+]};
+
+const DT_1_2: IviDeltaCB = IviDeltaCB{ quad_radix: 9, data: &[
+ 0, 0, 3, 3, -3, -3, -1, 4,
+ 1, -4, 4, -1, -4, 1, 7, 7,
+ -7, -7, 2, 8, -2, -8, 8, 2,
+ -8, -2, -2, 9, 2, -9, 9, -2,
+ -9, 2, -6, 6, 6, -6, 6, 13,
+ -6, -13, 13, 6, -13, -6, 13, 13,
+ -13, -13, 1, 14, -1, -14, 14, 1,
+ -14, -1, -8, 12, 8, -12, 12, -8,
+ -12, 8, 14, 23, -14, -23, 23, 14,
+ -23, -14, -5, 18, 5, -18, 18, -5,
+ -18, 5, 6, 24, -6, -24, 24, 6,
+ -24, -6, 24, 24, -24, -24, -1, 27,
+ 1, -27, 27, -1, -27, 1, -17, 17,
+ 17, -17, -13, 23, 13, -23, 23, -13,
+ -23, 13, 16, 40, -16, -40, 40, 16,
+ -40, -16, 28, 41, -28, -41, 41, 28,
+ -41, -28, -9, 33, 9, -33, 33, -9,
+ -33, 9, 6, 43, -6, -43, 43, 6,
+ -43, -6, 46, 46, -46, -46, -4, 50,
+ 4, -50, 50, -4, -50, 4, -27, 34,
+ 27, -34, 34, -27, -34, 27, -22, 45,
+ 22, -45, 45, -22, -45, 22, 34, 69,
+ -34, -69, 69, 34, -69, -34, 19, 70,
+ -19, -70, 70, 19, -70, -19, 53, 73,
+ -53, -73, 73, 53, -73, -53, -17, 62,
+ 17, -62, 62, -17, -62, 17, 5, 77,
+ -5, -77, 77, 5, -77, -5, 82, 82,
+ -82, -82, -51, 51, 51, -51, -43, 64,
+ 43, -64, 64, -43, -64, 43, -10, 90,
+ 10, -90, 90, -10, -90, 10, 41, 114,
+ -41, -114, 114, 41, -114, -41, 64, 116,
+ -64, -116, 116, 64, -116, -64, -37, 82,
+ 37, -82, 82, -37, -82, 37, 22, 119,
+ -22, -119, 119, 22, -119, -22, 95, 124,
+ -95, -124, 124, 95, -124, -95, -30, 111,
+ 30, -111, 111, -30, -111, 30, -78, 92,
+ 78, -92, 92, -78, -92, 78, -68, 113,
+ 68, -113, 113, -68, -113, 68, 18, 18,
+ -18, -18, 34, 34, -34, -34, 63, 63,
+ -63, -63, 109, 109, -109, -109,
+]};
+
+const DT_1_3: IviDeltaCB = IviDeltaCB{ quad_radix: 10, data: &[
+ 0, 0, 4, 4, -4, -4, -1, 5,
+ 1, -5, 5, -1, -5, 1, 3, 10,
+ -3, -10, 10, 3, -10, -3, 9, 9,
+ -9, -9, -7, 7, 7, -7, -3, 12,
+ 3, -12, 12, -3, -12, 3, 8, 17,
+ -8, -17, 17, 8, -17, -8, 17, 17,
+ -17, -17, 1, 19, -1, -19, 19, 1,
+ -19, -1, -11, 16, 11, -16, 16, -11,
+ -16, 11, -6, 23, 6, -23, 23, -6,
+ -23, 6, 18, 31, -18, -31, 31, 18,
+ -31, -18, 8, 32, -8, -32, 32, 8,
+ -32, -8, 33, 33, -33, -33, -1, 36,
+ 1, -36, 36, -1, -36, 1, -23, 23,
+ 23, -23, -17, 31, 17, -31, 31, -17,
+ -31, 17, 21, 54, -21, -54, 54, 21,
+ -54, -21, 37, 55, -37, -55, 55, 37,
+ -55, -37, -12, 44, 12, -44, 44, -12,
+ -44, 12, 8, 57, -8, -57, 57, 8,
+ -57, -8, 61, 61, -61, -61, -5, 66,
+ 5, -66, 66, -5, -66, 5, -36, 45,
+ 36, -45, 45, -36, -45, 36, -29, 60,
+ 29, -60, 60, -29, -60, 29, 45, 92,
+ -45, -92, 92, 45, -92, -45, 25, 93,
+ -25, -93, 93, 25, -93, -25, 71, 97,
+ -71, -97, 97, 71, -97, -71, -22, 83,
+ 22, -83, 83, -22, -83, 22, 7, 102,
+ -7, -102, 102, 7, -102, -7, 109, 109,
+ -109, -109, -68, 68, 68, -68, -57, 85,
+ 57, -85, 85, -57, -85, 57, -13, 120,
+ 13, -120, 120, -13, -120, 13, -49, 110,
+ 49, -110, 110, -49, -110, 49, -104, 123,
+ 104, -123, 123, -104, -123, 104, 24, 24,
+ -24, -24, 46, 46, -46, -46, 84, 84,
+ -84, -84,
+]};
+
+const DT_1_4: IviDeltaCB = IviDeltaCB{ quad_radix: 11, data: &[
+ 0, 0, 5, 5, -5, -5, -2, 7,
+ 2, -7, 7, -2, -7, 2, 11, 11,
+ -11, -11, 3, 13, -3, -13, 13, 3,
+ -13, -3, -9, 9, 9, -9, -4, 15,
+ 4, -15, 15, -4, -15, 4, 11, 22,
+ -11, -22, 22, 11, -22, -11, 21, 21,
+ -21, -21, 2, 24, -2, -24, 24, 2,
+ -24, -2, -14, 20, 14, -20, 20, -14,
+ -20, 14, 23, 38, -23, -38, 38, 23,
+ -38, -23, -8, 29, 8, -29, 29, -8,
+ -29, 8, 11, 39, -11, -39, 39, 11,
+ -39, -11, 41, 41, -41, -41, -1, 45,
+ 1, -45, 45, -1, -45, 1, -29, 29,
+ 29, -29, -22, 39, 22, -39, 39, -22,
+ -39, 22, 27, 67, -27, -67, 67, 27,
+ -67, -27, 47, 69, -47, -69, 69, 47,
+ -69, -47, -15, 56, 15, -56, 56, -15,
+ -56, 15, 11, 71, -11, -71, 71, 11,
+ -71, -11, 76, 76, -76, -76, -6, 83,
+ 6, -83, 83, -6, -83, 6, -45, 57,
+ 45, -57, 57, -45, -57, 45, -36, 75,
+ 36, -75, 75, -36, -75, 36, 56, 115,
+ -56, -115, 115, 56, -115, -56, 31, 117,
+ -31, -117, 117, 31, -117, -31, 88, 122,
+ -88, -122, 122, 88, -122, -88, -28, 104,
+ 28, -104, 104, -28, -104, 28, -85, 85,
+ 85, -85, -72, 106, 72, -106, 106, -72,
+ -106, 72, 30, 30, -30, -30, 58, 58,
+ -58, -58, 105, 105, -105, -105,
+]};
+
+const DT_1_5: IviDeltaCB = IviDeltaCB{ quad_radix: 12, data: &[
+ 0, 0, 6, 6, -6, -6, -2, 8,
+ 2, -8, 8, -2, -8, 2, 13, 13,
+ -13, -13, 4, 15, -4, -15, 15, 4,
+ -15, -4, -11, 11, 11, -11, -5, 18,
+ 5, -18, 18, -5, -18, 5, 13, 26,
+ -13, -26, 26, 13, -26, -13, 26, 26,
+ -26, -26, 2, 29, -2, -29, 29, 2,
+ -29, -2, -16, 24, 16, -24, 24, -16,
+ -24, 16, 28, 46, -28, -46, 46, 28,
+ -46, -28, -9, 35, 9, -35, 35, -9,
+ -35, 9, 13, 47, -13, -47, 47, 13,
+ -47, -13, 49, 49, -49, -49, -1, 54,
+ 1, -54, 54, -1, -54, 1, -35, 35,
+ 35, -35, -26, 47, 26, -47, 47, -26,
+ -47, 26, 32, 81, -32, -81, 81, 32,
+ -81, -32, 56, 83, -56, -83, 83, 56,
+ -83, -56, -18, 67, 18, -67, 67, -18,
+ -67, 18, 13, 86, -13, -86, 86, 13,
+ -86, -13, 91, 91, -91, -91, -7, 99,
+ 7, -99, 99, -7, -99, 7, -54, 68,
+ 54, -68, 68, -54, -68, 54, -44, 90,
+ 44, -90, 90, -44, -90, 44, -33, 124,
+ 33, -124, 124, -33, -124, 33, -103, 103,
+ 103, -103, -86, 127, 86, -127, 127, -86,
+ -127, 86, 37, 37, -37, -37, 69, 69,
+ -69, -69,
+]};
+
+const DT_1_6: IviDeltaCB = IviDeltaCB{ quad_radix: 12, data: &[
+ 0, 0, 7, 7, -7, -7, -3, 10,
+ 3, -10, 10, -3, -10, 3, 16, 16,
+ -16, -16, 5, 18, -5, -18, 18, 5,
+ -18, -5, -13, 13, 13, -13, -6, 21,
+ 6, -21, 21, -6, -21, 6, 15, 30,
+ -15, -30, 30, 15, -30, -15, 30, 30,
+ -30, -30, 2, 34, -2, -34, 34, 2,
+ -34, -2, -19, 28, 19, -28, 28, -19,
+ -28, 19, 32, 54, -32, -54, 54, 32,
+ -54, -32, -11, 41, 11, -41, 41, -11,
+ -41, 11, 15, 55, -15, -55, 55, 15,
+ -55, -15, 57, 57, -57, -57, -1, 63,
+ 1, -63, 63, -1, -63, 1, -40, 40,
+ 40, -40, -30, 55, 30, -55, 55, -30,
+ -55, 30, 37, 94, -37, -94, 94, 37,
+ -94, -37, 65, 96, -65, -96, 96, 65,
+ -96, -65, -21, 78, 21, -78, 78, -21,
+ -78, 21, 15, 100, -15, -100, 100, 15,
+ -100, -15, 106, 106, -106, -106, -8, 116,
+ 8, -116, 116, -8, -116, 8, -63, 79,
+ 63, -79, 79, -63, -79, 63, -51, 105,
+ 51, -105, 105, -51, -105, 51, -120, 120,
+ 120, -120, 43, 43, -43, -43, 80, 80,
+ -80, -80,
+]};
+
+const DT_1_7: IviDeltaCB = IviDeltaCB{ quad_radix: 12, data: &[
+ 0, 0, 8, 8, -8, -8, -3, 11,
+ 3, -11, 11, -3, -11, 3, 18, 18,
+ -18, -18, 5, 20, -5, -20, 20, 5,
+ -20, -5, -15, 15, 15, -15, -7, 24,
+ 7, -24, 24, -7, -24, 7, 17, 35,
+ -17, -35, 35, 17, -35, -17, 34, 34,
+ -34, -34, 3, 38, -3, -38, 38, 3,
+ -38, -3, -22, 32, 22, -32, 32, -22,
+ -32, 22, 37, 61, -37, -61, 61, 37,
+ -61, -37, -13, 47, 13, -47, 47, -13,
+ -47, 13, 17, 63, -17, -63, 63, 17,
+ -63, -17, 65, 65, -65, -65, -1, 72,
+ 1, -72, 72, -1, -72, 1, -46, 46,
+ 46, -46, -35, 63, 35, -63, 63, -35,
+ -63, 35, 43, 107, -43, -107, 107, 43,
+ -107, -43, 75, 110, -75, -110, 110, 75,
+ -110, -75, -24, 89, 24, -89, 89, -24,
+ -89, 24, 17, 114, -17, -114, 114, 17,
+ -114, -17, 121, 121, -121, -121, -72, 91,
+ 72, -91, 91, -72, -91, 72, -58, 120,
+ 58, -120, 120, -58, -120, 58, 49, 49,
+ -49, -49, 92, 92, -92, -92,
+]};
+
+const DT_1_8: IviDeltaCB = IviDeltaCB{ quad_radix: 13, data: &[
+ 0, 0, 9, 9, -9, -9, -3, 12,
+ 3, -12, 12, -3, -12, 3, 20, 20,
+ -20, -20, 6, 23, -6, -23, 23, 6,
+ -23, -6, -17, 17, 17, -17, -7, 27,
+ 7, -27, 27, -7, -27, 7, 19, 39,
+ -19, -39, 39, 19, -39, -19, 39, 39,
+ -39, -39, 3, 43, -3, -43, 43, 3,
+ -43, -3, -24, 36, 24, -36, 36, -24,
+ -36, 24, 42, 69, -42, -69, 69, 42,
+ -69, -42, -14, 53, 14, -53, 53, -14,
+ -53, 14, 19, 71, -19, -71, 71, 19,
+ -71, -19, 73, 73, -73, -73, -2, 80,
+ 2, -80, 80, -2, -80, 2, -52, 52,
+ 52, -52, -39, 70, 39, -70, 70, -39,
+ -70, 39, 48, 121, -48, -121, 121, 48,
+ -121, -48, 84, 124, -84, -124, 124, 84,
+ -124, -84, -27, 100, 27, -100, 100, -27,
+ -100, 27, -81, 102, 81, -102, 102, -81,
+ -102, 81, 55, 55, -55, -55, 104, 104,
+ -104, -104,
+]};
+
+const DT_2_1: IviDeltaCB = IviDeltaCB{ quad_radix: 7, data: &[
+ 0, 0, 2, 2, -2, -2, 0, 2,
+ 0, -2, 2, 0, -2, 0, 4, 4,
+ -4, -4, 0, 4, 0, -4, 4, 0,
+ -4, 0, -4, 4, 4, -4, -2, 6,
+ 2, -6, 6, -2, -6, 2, 4, 8,
+ -4, -8, 8, 4, -8, -4, 8, 8,
+ -8, -8, 0, 10, 0, -10, 10, 0,
+ -10, 0, -4, 8, 4, -8, 8, -4,
+ -8, 4, 8, 14, -8, -14, 14, 8,
+ -14, -8, -2, 12, 2, -12, 12, -2,
+ -12, 2, 4, 16, -4, -16, 16, 4,
+ -16, -4, 16, 16, -16, -16, 0, 18,
+ 0, -18, 18, 0, -18, 0, -12, 12,
+ 12, -12, -8, 16, 8, -16, 16, -8,
+ -16, 8, 10, 26, -10, -26, 26, 10,
+ -26, -10, 18, 28, -18, -28, 28, 18,
+ -28, -18, -6, 22, 6, -22, 22, -6,
+ -22, 6, 4, 28, -4, -28, 28, 4,
+ -28, -4, 30, 30, -30, -30, -2, 32,
+ 2, -32, 32, -2, -32, 2, -18, 22,
+ 18, -22, 22, -18, -22, 18, -14, 30,
+ 14, -30, 30, -14, -30, 14, 22, 46,
+ -22, -46, 46, 22, -46, -22, 12, 46,
+ -12, -46, 46, 12, -46, -12, 34, 48,
+ -34, -48, 48, 34, -48, -34, -10, 40,
+ 10, -40, 40, -10, -40, 10, 4, 50,
+ -4, -50, 50, 4, -50, -4, 54, 54,
+ -54, -54, -34, 34, 34, -34, -28, 42,
+ 28, -42, 42, -28, -42, 28, -6, 60,
+ 6, -60, 60, -6, -60, 6, 26, 76,
+ -26, -76, 76, 26, -76, -26, 42, 76,
+ -42, -76, 76, 42, -76, -42, -24, 54,
+ 24, -54, 54, -24, -54, 24, 14, 78,
+ -14, -78, 78, 14, -78, -14, 62, 82,
+ -62, -82, 82, 62, -82, -62, -20, 74,
+ 20, -74, 74, -20, -74, 20, 2, 88,
+ -2, -88, 88, 2, -88, -2, 92, 92,
+ -92, -92, -52, 60, 52, -60, 60, -52,
+ -60, 52, 52, 118, -52, -118, 118, 52,
+ -118, -52, -44, 74, 44, -74, 74, -44,
+ -74, 44, 74, 118, -74, -118, 118, 74,
+ -118, -74, 32, 118, -32, -118, 118, 32,
+ -118, -32, -12, 102, 12, -102, 102, -12,
+ -102, 12, -40, 96, 40, -96, 96, -40,
+ -96, 40, -34, 118, 34, -118, 118, -34,
+ -118, 34, -88, 88, 88, -88, -78, 104,
+ 78, -104, 104, -78, -104, 78, 12, 12,
+ -12, -12, 22, 22, -22, -22, 42, 42,
+ -42, -42, 72, 72, -72, -72,
+]};
+
+const DT_2_2: IviDeltaCB = IviDeltaCB{ quad_radix: 9, data: &[
+ 0, 0, 3, 3, -3, -3, 0, 3,
+ 0, -3, 3, 0, -3, 0, 6, 6,
+ -6, -6, 3, 9, -3, -9, 9, 3,
+ -9, -3, -3, 9, 3, -9, 9, -3,
+ -9, 3, -6, 6, 6, -6, 6, 12,
+ -6, -12, 12, 6, -12, -6, 12, 12,
+ -12, -12, 0, 15, 0, -15, 15, 0,
+ -15, 0, -9, 12, 9, -12, 12, -9,
+ -12, 9, 15, 24, -15, -24, 24, 15,
+ -24, -15, -6, 18, 6, -18, 18, -6,
+ -18, 6, 6, 24, -6, -24, 24, 6,
+ -24, -6, 24, 24, -24, -24, 0, 27,
+ 0, -27, 27, 0, -27, 0, -18, 18,
+ 18, -18, -12, 24, 12, -24, 24, -12,
+ -24, 12, 15, 39, -15, -39, 39, 15,
+ -39, -15, 27, 42, -27, -42, 42, 27,
+ -42, -27, -9, 33, 9, -33, 33, -9,
+ -33, 9, 6, 42, -6, -42, 42, 6,
+ -42, -6, 45, 45, -45, -45, -3, 51,
+ 3, -51, 51, -3, -51, 3, -27, 33,
+ 27, -33, 33, -27, -33, 27, -21, 45,
+ 21, -45, 45, -21, -45, 21, 33, 69,
+ -33, -69, 69, 33, -69, -33, 18, 69,
+ -18, -69, 69, 18, -69, -18, 54, 72,
+ -54, -72, 72, 54, -72, -54, -18, 63,
+ 18, -63, 63, -18, -63, 18, 6, 78,
+ -6, -78, 78, 6, -78, -6, 81, 81,
+ -81, -81, -51, 51, 51, -51, -42, 63,
+ 42, -63, 63, -42, -63, 42, -9, 90,
+ 9, -90, 90, -9, -90, 9, 42, 114,
+ -42, -114, 114, 42, -114, -42, 63, 117,
+ -63, -117, 117, 63, -117, -63, -36, 81,
+ 36, -81, 81, -36, -81, 36, 21, 120,
+ -21, -120, 120, 21, -120, -21, 96, 123,
+ -96, -123, 123, 96, -123, -96, -30, 111,
+ 30, -111, 111, -30, -111, 30, -78, 93,
+ 78, -93, 93, -78, -93, 78, -69, 114,
+ 69, -114, 114, -69, -114, 69, 18, 18,
+ -18, -18, 33, 33, -33, -33, 63, 63,
+ -63, -63, 108, 108, -108, -108,
+]};
+
+const DT_2_3: IviDeltaCB = IviDeltaCB{ quad_radix: 10, data: &[
+ 0, 0, 4, 4, -4, -4, 0, 4,
+ 0, -4, 4, 0, -4, 0, 4, 8,
+ -4, -8, 8, 4, -8, -4, 8, 8,
+ -8, -8, -8, 8, 8, -8, -4, 12,
+ 4, -12, 12, -4, -12, 4, 8, 16,
+ -8, -16, 16, 8, -16, -8, 16, 16,
+ -16, -16, 0, 20, 0, -20, 20, 0,
+ -20, 0, -12, 16, 12, -16, 16, -12,
+ -16, 12, -4, 24, 4, -24, 24, -4,
+ -24, 4, 16, 32, -16, -32, 32, 16,
+ -32, -16, 8, 32, -8, -32, 32, 8,
+ -32, -8, 32, 32, -32, -32, 0, 36,
+ 0, -36, 36, 0, -36, 0, -24, 24,
+ 24, -24, -16, 32, 16, -32, 32, -16,
+ -32, 16, 20, 52, -20, -52, 52, 20,
+ -52, -20, 36, 56, -36, -56, 56, 36,
+ -56, -36, -12, 44, 12, -44, 44, -12,
+ -44, 12, 8, 56, -8, -56, 56, 8,
+ -56, -8, 60, 60, -60, -60, -4, 64,
+ 4, -64, 64, -4, -64, 4, -36, 44,
+ 36, -44, 44, -36, -44, 36, -28, 60,
+ 28, -60, 60, -28, -60, 28, 44, 92,
+ -44, -92, 92, 44, -92, -44, 24, 92,
+ -24, -92, 92, 24, -92, -24, 72, 96,
+ -72, -96, 96, 72, -96, -72, -20, 84,
+ 20, -84, 84, -20, -84, 20, 8, 100,
+ -8, -100, 100, 8, -100, -8, 108, 108,
+ -108, -108, -68, 68, 68, -68, -56, 84,
+ 56, -84, 84, -56, -84, 56, -12, 120,
+ 12, -120, 120, -12, -120, 12, -48, 108,
+ 48, -108, 108, -48, -108, 48, -104, 124,
+ 104, -124, 124, -104, -124, 104, 24, 24,
+ -24, -24, 44, 44, -44, -44, 84, 84,
+ -84, -84,
+]};
+
+const DT_2_4: IviDeltaCB = IviDeltaCB{ quad_radix: 11, data: &[
+ 0, 0, 5, 5, -5, -5, 0, 5,
+ 0, -5, 5, 0, -5, 0, 10, 10,
+ -10, -10, 5, 15, -5, -15, 15, 5,
+ -15, -5, -10, 10, 10, -10, -5, 15,
+ 5, -15, 15, -5, -15, 5, 10, 20,
+ -10, -20, 20, 10, -20, -10, 20, 20,
+ -20, -20, 0, 25, 0, -25, 25, 0,
+ -25, 0, -15, 20, 15, -20, 20, -15,
+ -20, 15, 25, 40, -25, -40, 40, 25,
+ -40, -25, -10, 30, 10, -30, 30, -10,
+ -30, 10, 10, 40, -10, -40, 40, 10,
+ -40, -10, 40, 40, -40, -40, 0, 45,
+ 0, -45, 45, 0, -45, 0, -30, 30,
+ 30, -30, -20, 40, 20, -40, 40, -20,
+ -40, 20, 25, 65, -25, -65, 65, 25,
+ -65, -25, 45, 70, -45, -70, 70, 45,
+ -70, -45, -15, 55, 15, -55, 55, -15,
+ -55, 15, 10, 70, -10, -70, 70, 10,
+ -70, -10, 75, 75, -75, -75, -5, 85,
+ 5, -85, 85, -5, -85, 5, -45, 55,
+ 45, -55, 55, -45, -55, 45, -35, 75,
+ 35, -75, 75, -35, -75, 35, 55, 115,
+ -55, -115, 115, 55, -115, -55, 30, 115,
+ -30, -115, 115, 30, -115, -30, 90, 120,
+ -90, -120, 120, 90, -120, -90, -30, 105,
+ 30, -105, 105, -30, -105, 30, -85, 85,
+ 85, -85, -70, 105, 70, -105, 105, -70,
+ -105, 70, 30, 30, -30, -30, 60, 60,
+ -60, -60, 105, 105, -105, -105,
+]};
+
+const DT_2_5: IviDeltaCB = IviDeltaCB{ quad_radix: 12, data: &[
+ 0, 0, 6, 6, -6, -6, 0, 6,
+ 0, -6, 6, 0, -6, 0, 12, 12,
+ -12, -12, 6, 12, -6, -12, 12, 6,
+ -12, -6, -12, 12, 12, -12, -6, 18,
+ 6, -18, 18, -6, -18, 6, 12, 24,
+ -12, -24, 24, 12, -24, -12, 24, 24,
+ -24, -24, 0, 30, 0, -30, 30, 0,
+ -30, 0, -18, 24, 18, -24, 24, -18,
+ -24, 18, 30, 48, -30, -48, 48, 30,
+ -48, -30, -6, 36, 6, -36, 36, -6,
+ -36, 6, 12, 48, -12, -48, 48, 12,
+ -48, -12, 48, 48, -48, -48, 0, 54,
+ 0, -54, 54, 0, -54, 0, -36, 36,
+ 36, -36, -24, 48, 24, -48, 48, -24,
+ -48, 24, 30, 78, -30, -78, 78, 30,
+ -78, -30, 54, 84, -54, -84, 84, 54,
+ -84, -54, -18, 66, 18, -66, 66, -18,
+ -66, 18, 12, 84, -12, -84, 84, 12,
+ -84, -12, 90, 90, -90, -90, -6, 96,
+ 6, -96, 96, -6, -96, 6, -54, 66,
+ 54, -66, 66, -54, -66, 54, -42, 90,
+ 42, -90, 90, -42, -90, 42, -30, 126,
+ 30, -126, 126, -30, -126, 30, -102, 102,
+ 102, -102, -84, 126, 84, -126, 126, -84,
+ -126, 84, 36, 36, -36, -36, 66, 66,
+ -66, -66,
+]};
+
+const DT_2_6: IviDeltaCB = IviDeltaCB{ quad_radix: 12, data: &[
+ 0, 0, 7, 7, -7, -7, 0, 7,
+ 0, -7, 7, 0, -7, 0, 14, 14,
+ -14, -14, 7, 21, -7, -21, 21, 7,
+ -21, -7, -14, 14, 14, -14, -7, 21,
+ 7, -21, 21, -7, -21, 7, 14, 28,
+ -14, -28, 28, 14, -28, -14, 28, 28,
+ -28, -28, 0, 35, 0, -35, 35, 0,
+ -35, 0, -21, 28, 21, -28, 28, -21,
+ -28, 21, 35, 56, -35, -56, 56, 35,
+ -56, -35, -14, 42, 14, -42, 42, -14,
+ -42, 14, 14, 56, -14, -56, 56, 14,
+ -56, -14, 56, 56, -56, -56, 0, 63,
+ 0, -63, 63, 0, -63, 0, -42, 42,
+ 42, -42, -28, 56, 28, -56, 56, -28,
+ -56, 28, 35, 91, -35, -91, 91, 35,
+ -91, -35, 63, 98, -63, -98, 98, 63,
+ -98, -63, -21, 77, 21, -77, 77, -21,
+ -77, 21, 14, 98, -14, -98, 98, 14,
+ -98, -14, 105, 105, -105, -105, -7, 119,
+ 7, -119, 119, -7, -119, 7, -63, 77,
+ 63, -77, 77, -63, -77, 63, -49, 105,
+ 49, -105, 105, -49, -105, 49, -119, 119,
+ 119, -119, 42, 42, -42, -42, 77, 77,
+ -77, -77,
+]};
+
+const DT_2_7: IviDeltaCB = IviDeltaCB{ quad_radix: 12, data: &[
+ 0, 0, 8, 8, -8, -8, 0, 8,
+ 0, -8, 8, 0, -8, 0, 16, 16,
+ -16, -16, 8, 16, -8, -16, 16, 8,
+ -16, -8, -16, 16, 16, -16, -8, 24,
+ 8, -24, 24, -8, -24, 8, 16, 32,
+ -16, -32, 32, 16, -32, -16, 32, 32,
+ -32, -32, 0, 40, 0, -40, 40, 0,
+ -40, 0, -24, 32, 24, -32, 32, -24,
+ -32, 24, 40, 64, -40, -64, 64, 40,
+ -64, -40, -16, 48, 16, -48, 48, -16,
+ -48, 16, 16, 64, -16, -64, 64, 16,
+ -64, -16, 64, 64, -64, -64, 0, 72,
+ 0, -72, 72, 0, -72, 0, -48, 48,
+ 48, -48, -32, 64, 32, -64, 64, -32,
+ -64, 32, 40, 104, -40, -104, 104, 40,
+ -104, -40, 72, 112, -72, -112, 112, 72,
+ -112, -72, -24, 88, 24, -88, 88, -24,
+ -88, 24, 16, 112, -16, -112, 112, 16,
+ -112, -16, 120, 120, -120, -120, -72, 88,
+ 72, -88, 88, -72, -88, 72, -56, 120,
+ 56, -120, 120, -56, -120, 56, 48, 48,
+ -48, -48, 88, 88, -88, -88,
+]};
+
+const DT_2_8: IviDeltaCB = IviDeltaCB{ quad_radix: 13, data: &[
+ 0, 0, 9, 9, -9, -9, 0, 9,
+ 0, -9, 9, 0, -9, 0, 18, 18,
+ -18, -18, 9, 27, -9, -27, 27, 9,
+ -27, -9, -18, 18, 18, -18, -9, 27,
+ 9, -27, 27, -9, -27, 9, 18, 36,
+ -18, -36, 36, 18, -36, -18, 36, 36,
+ -36, -36, 0, 45, 0, -45, 45, 0,
+ -45, 0, -27, 36, 27, -36, 36, -27,
+ -36, 27, 45, 72, -45, -72, 72, 45,
+ -72, -45, -18, 54, 18, -54, 54, -18,
+ -54, 18, 18, 72, -18, -72, 72, 18,
+ -72, -18, 72, 72, -72, -72, 0, 81,
+ 0, -81, 81, 0, -81, 0, -54, 54,
+ 54, -54, -36, 72, 36, -72, 72, -36,
+ -72, 36, 45, 117, -45, -117, 117, 45,
+ -117, -45, 81, 126, -81, -126, 126, 81,
+ -126, -81, -27, 99, 27, -99, 99, -27,
+ -99, 27, -81, 99, 81, -99, 99, -81,
+ -99, 81, 54, 54, -54, -54, 108, 108,
+ -108, -108,
+]};
+
+const DT_3_1: IviDeltaCB = IviDeltaCB{ quad_radix: 11, data: &[
+ 0, 0, 2, 2, -2, -2, 0, 3,
+ 0, -3, 3, 0, -3, 0, 6, 6,
+ -6, -6, 0, 7, 0, -7, 7, 0,
+ -7, 0, -5, 5, 5, -5, 5, -5,
+ -5, 5, 6, 11, -6, -11, 11, 6,
+ -11, -6, 0, 8, 0, -8, 8, 0,
+ -8, 0, 11, 11, -11, -11, 0, 12,
+ 0, -12, 12, 0, -12, 0, 12, 17,
+ -12, -17, 17, 12, -17, -12, 17, 17,
+ -17, -17, 6, 18, -6, -18, 18, 6,
+ -18, -6, -8, 11, 8, -11, 11, -8,
+ -11, 8, 0, 15, 0, -15, 15, 0,
+ -15, 0, 0, 20, 0, -20, 20, 0,
+ -20, 0, 18, 25, -18, -25, 25, 18,
+ -25, -18, 11, 25, -11, -25, 25, 11,
+ -25, -11, 25, 25, -25, -25, -14, 14,
+ 14, -14, 14, -14, -14, 14, 0, 26,
+ 0, -26, 26, 0, -26, 0, -11, 18,
+ 11, -18, 18, -11, -18, 11, -7, 22,
+ 7, -22, 22, -7, -22, 7, 26, 34,
+ -26, -34, 34, 26, -34, -26, 18, 34,
+ -18, -34, 34, 18, -34, -18, 34, 34,
+ -34, -34, 11, 35, -11, -35, 35, 11,
+ -35, -11, 0, 29, 0, -29, 29, 0,
+ -29, 0, -19, 22, 19, -22, 22, -19,
+ -22, 19, -15, 26, 15, -26, 26, -15,
+ -26, 15, 0, 37, 0, -37, 37, 0,
+ -37, 0, 27, 44, -27, -44, 44, 27,
+ -44, -27, 36, 44, -36, -44, 44, 36,
+ -44, -36, 18, 44, -18, -44, 44, 18,
+ -44, -18, -10, 33, 10, -33, 33, -10,
+ -33, 10, 45, 45, -45, -45, 0, 0,
+]};
+
+const DT_3_2: IviDeltaCB = IviDeltaCB{ quad_radix: 13, data: &[
+ 0, 0, 0, 2, 0, -2, 2, 0,
+ -2, 0, 2, 2, -2, -2, 6, 6,
+ -6, -6, 0, 6, 0, -6, 6, 0,
+ -6, 0, -4, 4, 4, -4, 10, -6,
+ -10, 6, 0, -12, 0, 12, -6, -12,
+ 6, -12, -6, 12, 6, 12, -14, 0,
+ 14, 0, 12, 12, -12, -12, 0, -18,
+ 0, 18, 14, -12, -14, 12, -18, -6,
+ 18, -6, -18, 6, 18, 6, -10, -18,
+ 10, -18, -10, 18, 10, 18, -22, 0,
+ 22, 0, 0, -24, 0, 24, -22, -12,
+ 22, -12, -22, 12, 22, 12, -8, -24,
+ 8, -24, -8, 24, 8, 24, -26, -6,
+ 26, -6, -26, 6, 26, 6, -28, 0,
+ 28, 0, 20, 20, -20, -20, -14, -26,
+ 14, 26, -30, -12, 30, 12, -10, -32,
+ 10, 32, -18, -32, 18, 32, -26, -26,
+ 26, 26, -34, -20, 34, 20, -38, -12,
+ 38, 12, -32, -32, 32, 32, 32, 32,
+ -22, -40, -34, -34, 34, 34,
+]};
+
+const DT_3_3: IviDeltaCB = IviDeltaCB{ quad_radix: 13, data: &[
+ 0, 0, 0, 2, 0, -2, 2, 0,
+ -2, 0, 4, 4, -4, -4, 10, 10,
+ -10, -10, 0, 10, 0, -10, 10, 0,
+ -10, 0, -6, 6, 6, -6, 14, -8,
+ -14, 8, -18, 0, 18, 0, 10, -16,
+ -10, 16, 0, -24, 0, 24, -24, -8,
+ 24, -8, -24, 8, 24, 8, 18, 18,
+ -18, -18, 20, -16, -20, 16, -14, -26,
+ 14, -26, -14, 26, 14, 26, -30, 0,
+ 30, 0, 0, -34, 0, 34, -34, -8,
+ 34, -8, -34, 8, 34, 8, -30, -18,
+ 30, -18, -30, 18, 30, 18, -10, -34,
+ 10, -34, -10, 34, 10, 34, -20, -34,
+ 20, 34, -40, 0, 40, 0, 30, 30,
+ -30, -30, -40, -18, 40, 18, 0, -44,
+ 0, 44, -16, -44, 16, 44, -36, -36,
+ -36, -36, 36, 36, -26, -44, 26, 44,
+ -46, -26, 46, 26, -52, -18, 52, 18,
+ -20, -54, -44, -44, 44, 44, -32, -54,
+ -46, -46, -46, -46, 46, 46,
+]};
+
+const DT_3_4: IviDeltaCB = IviDeltaCB{ quad_radix: 13, data: &[
+ 0, 0, 0, 4, 0, -4, 4, 0,
+ -4, 0, 4, 4, -4, -4, 12, 12,
+ -12, -12, 0, 12, 0, -12, 12, 0,
+ -12, 0, -8, 8, 8, -8, 8, -16,
+ -8, 16, 0, -24, 0, 24, -24, -8,
+ 24, -8, -24, 8, 24, 8, 20, -16,
+ -20, 16, -28, 0, 28, 0, -16, -24,
+ 16, -24, -16, 24, 16, 24, 0, -32,
+ 0, 32, -28, -16, 28, -16, -28, 16,
+ 28, 16, -8, -32, 8, -32, -32, -8,
+ 32, -8, -32, 8, 32, 8, -8, 32,
+ 8, 32, 24, 24, -24, -24, 24, -24,
+ -24, 24, -20, -32, 20, 32, -40, 0,
+ 40, 0, -40, -16, 40, 16, 0, -44,
+ 0, -44, -44, 0, 44, 0, 0, 44,
+ 0, 44, -32, -32, 32, 32, -16, -44,
+ 16, 44, -24, -44, -44, -24, 44, 24,
+ 24, 44, -48, -16, 48, 16, -36, -36,
+ -36, -36, 36, 36, 36, 36, -20, -52,
+ 40, 40, -40, -40, -32, -52,
+]};
+
+const DT_3_5: IviDeltaCB = IviDeltaCB{ quad_radix: 13, data: &[
+ 0, 0, 2, 2, -2, -2, 6, 6,
+ -6, -6, 12, 12, -12, -12, 20, 20,
+ -20, -20, 32, 32, -32, -32, 46, 46,
+ -46, -46, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+]};
+
+const IVI3_DELTA_CBS: [&IviDeltaCB; 24] = [
+ &DT_1_1, &DT_1_2, &DT_1_3, &DT_1_4, &DT_1_5, &DT_1_6, &DT_1_7, &DT_1_8,
+ &DT_2_1, &DT_2_2, &DT_2_3, &DT_2_4, &DT_2_5, &DT_2_6, &DT_2_7, &DT_2_8,
+ &DT_3_1, &DT_3_2, &DT_3_3, &DT_3_4, &DT_3_5, &DT_3_5, &DT_3_5, &DT_3_5
+];
diff --git a/nihav-indeo/src/codecs/indeo4.rs b/nihav-indeo/src/codecs/indeo4.rs
new file mode 100644
index 0000000..58c246e
--- /dev/null
+++ b/nihav-indeo/src/codecs/indeo4.rs
@@ -0,0 +1,775 @@
+use std::rc::Rc;
+use std::cell::{Ref, RefCell};
+use nihav_core::io::bitreader::*;
+use nihav_core::formats;
+use nihav_core::frame::*;
+use nihav_core::codecs::*;
+use super::ivi::*;
+use super::ivibr::*;
+
+#[inline(always)]
+fn mclip8(a: i32) -> u8 {
+ if (a as u16) > 255 { !(a >> 16) as u8 }
+ else { a as u8 }
+}
+
+struct Indeo4Parser {
+ mb_cb: IVICodebook,
+ blk_cb: IVICodebook,
+}
+
+fn calc_quant(glob_q: u32, qd: i16) -> u8 {
+ let q = (glob_q as i16) + qd;
+ if q < 0 {
+ 0
+ } else if q > 31 {
+ 31
+ } else {
+ q as u8
+ }
+}
+
+impl Indeo4Parser {
+ fn new() -> Self {
+ Indeo4Parser {
+ mb_cb: IVI_CB_ZERO,
+ blk_cb: IVI_CB_ZERO,
+ }
+ }
+}
+
+impl IndeoXParser for Indeo4Parser {
+#[allow(unused_variables,unused_assignments)]
+ fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader> {
+ let sync = br.read(18)?;
+ validate!(sync == 0x3FFF8);
+ let ftype_idx = br.read(3)?;
+ validate!(ftype_idx < 7);
+ let ftype = INDEO4_FRAME_TYPE[ftype_idx as usize];
+ let transparent = br.read_bool()?;
+ br.skip(1)?;
+ let data_size;
+ if br.read_bool()? {
+ data_size = br.read(24)? as usize;
+ } else {
+ data_size = 0;
+ }
+ if ftype.is_null() {
+ return Ok(PictureHeader::new_null(ftype));
+ }
+ if br.read_bool()? {
+ br.skip(32)?; // key lock
+ }
+ let width;
+ let height;
+ let pic_size_idx = br.read(3)?;
+ if pic_size_idx < 7 {
+ width = INDEO4_PICTURE_SIZE_TAB[pic_size_idx as usize][0];
+ height = INDEO4_PICTURE_SIZE_TAB[pic_size_idx as usize][1];
+ } else {
+ height = br.read(16)? as usize;
+ width = br.read(16)? as usize;
+ validate!((width > 0) && ((width & 3) == 0));
+ validate!((height > 0) && ((height & 3) == 0));
+ }
+
+ let slice_w;
+ let slice_h;
+ if br.read_bool()? {
+ let idx = br.read(4)? as usize;
+ if idx < 15 {
+ slice_w = INDEO4_SLICE_SIZE_TAB[idx];
+ slice_h = INDEO4_SLICE_SIZE_TAB[idx];
+ } else {
+ slice_w = width;
+ slice_h = height;
+ }
+ } else {
+ slice_w = width;
+ slice_h = height;
+ }
+ let subsampling = br.read(2)?;
+ validate!(subsampling == 0);
+ let sc_idx = br.read(2)?;
+ match sc_idx {
+ 3 => { },
+ 2 => { validate!(br.read(2*4)? == 0xFF); }
+ _ => { return Err(DecoderError::InvalidData); }
+ };
+ let luma_bands = if sc_idx == 2 { 4 } else { 1 };
+ let sc_idx = br.read(2)?;
+ match sc_idx {
+ 3 => { },
+ 2 => { validate!(br.read(2*4)? == 0xFF); }
+ _ => { return Err(DecoderError::InvalidData); }
+ };
+ let chroma_bands = if sc_idx == 2 { 4 } else { 1 };
+ let frame_no;
+ if br.read_bool()? {
+ frame_no = br.read(20)?;
+ } else {
+ frame_no = 0;
+ }
+ if br.read_bool()? {
+ br.skip(8)?; // decTimeEst
+ }
+ let desc_coded = br.read_bool()?;
+ self.mb_cb = br.read_ivi_codebook_desc(true, desc_coded)?;
+ let desc_coded = br.read_bool()?;
+ self.blk_cb = br.read_ivi_codebook_desc(false, desc_coded)?;
+ let rvmap = if br.read_bool()? { br.read(3)? as usize } else { 8 };
+ let in_imf = br.read_bool()?;
+ let in_q = br.read_bool()?;
+ let glob_q = br.read(5)? as u8;
+ if br.read_bool()? {
+ br.skip(3)?;
+ }
+ let checksum = if br.read_bool()? { br.read(16)? } else { 0 };
+ if br.read_bool()? {
+ br.skip(8)?; // pic hdr extension
+ }
+ if br.read_bool()? {
+ println!("bad blocks bits!");
+ }
+ br.align();
+
+ Ok(PictureHeader::new(ftype, width, height, slice_w, slice_h, transparent, luma_bands, chroma_bands, in_q))
+ }
+
+#[allow(unused_variables,unused_assignments)]
+ fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane: usize, band: usize) -> DecoderResult<BandHeader> {
+ let plane_no = br.read(2)? as usize;
+ let band_no = br.read(4)? as usize;
+ validate!(plane_no == plane);
+ validate!(band_no == band);
+ if br.read_bool()? {
+ br.align();
+ return Ok(BandHeader::new_empty(plane_no, band_no));
+ }
+ let hdr_size;
+ if br.read_bool()? {
+ hdr_size = br.read(16)? as usize;
+ } else {
+ hdr_size = 32;
+ }
+ let mv_mode = br.read(2)?;
+ validate!(mv_mode < 2);
+ if br.read_bool()? {
+ br.skip(16)?; //checksum
+ }
+
+ let scale = br.read(2)?;
+ validate!(scale != 3);
+ let mb_size = 16 >> scale;
+ let blk_size = 8 >> (scale >> 1);
+ let inherit_mv = br.read_bool()?;
+ let inherit_qd = br.read_bool()?;
+ let quant = br.read(5)?;
+
+ let tr: IVITransformType;
+ let txtype: TxType;
+ if !br.read_bool()? || pic_hdr.ftype == IVIFrameType::Intra {
+ let tr_id = br.read(5)?;
+ validate!(tr_id < 18);
+ let scan_idx = br.read(4)? as usize;
+ validate!(scan_idx != 15);
+ let qmat_idx = br.read(5)? as usize;
+
+ tr = INDEO4_TRANSFORMS[tr_id as usize];
+ if (scan_idx < 5) || (scan_idx >= 10) {
+ validate!(tr.is_8x8());
+ validate!(qmat_idx < 15);
+ let scan = if scan_idx < 5 { INDEO4_SCANS_8X8[scan_idx] }
+ else { INDEO4_SCANS_8X8[4] };
+ let qidx = INDEO4_Q8X8_IDX[qmat_idx];
+ let qintra = INDEO4_Q8_INTRA[qidx];
+ let qinter = INDEO4_Q8_INTER[qidx];
+ txtype = TxType::Transform8(TxParams8x8::new(qintra, qinter, scan));
+ } else if scan_idx < 10 {
+ validate!(!tr.is_8x8());
+ validate!((qmat_idx >= 15) && (qmat_idx < 22));
+ let scan = INDEO4_SCANS_4X4[scan_idx - 5];
+ let qidx = INDEO4_Q4X4_IDX[qmat_idx - 15];
+ let qintra = INDEO4_Q4_INTRA[qidx];
+ let qinter = INDEO4_Q4_INTER[qidx];
+ txtype = TxType::Transform4(TxParams4x4::new(qintra, qinter, scan));
+ } else {
+ unreachable!();
+ }
+ } else {
+ tr = IVITransformType::None(TSize::T8x8);
+ txtype = TxType::None;
+ }
+
+ let blk_cb;
+ if br.read_bool()? {
+ blk_cb = br.read_ivi_codebook_desc(false, true)?;
+ } else {
+ blk_cb = self.blk_cb;
+ }
+ let rvmap_idx;
+ if br.read_bool()? {
+ rvmap_idx = br.read(3)? as usize;
+ } else {
+ rvmap_idx = 8;
+ }
+ let num_corr;
+ let mut corr_map: [u8; CORR_MAP_SIZE] = [0; CORR_MAP_SIZE];
+ if br.read_bool()? {
+ num_corr = br.read(8)? as usize;
+ validate!(num_corr*2 <= CORR_MAP_SIZE);
+ for i in 0..num_corr*2 {
+ corr_map[i] = br.read(8)? as u8;
+ }
+ } else {
+ num_corr = 0;
+ }
+
+ br.align();
+ Ok(BandHeader::new(plane_no, band_no, mb_size, blk_size, mv_mode == 1, inherit_mv, false, inherit_qd, quant, rvmap_idx, num_corr, corr_map, blk_cb, tr, txtype))
+ }
+
+ fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band: &BandHeader, tile: &mut IVITile, ref_tile: Option<Ref<IVITile>>, mv_scale: u8) -> DecoderResult<()> {
+ let mut mv_x = 0;
+ let mut mv_y = 0;
+ let mut mb_idx = 0;
+
+ for mb_y in 0..tile.mb_h {
+ for mb_x in 0..tile.mb_w {
+ let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
+ if !br.read_bool()? {
+ if pic_hdr.ftype.is_intra() {
+ mb.mtype = MBType::Intra;
+ } else if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ mb.mtype = tileref.mb[mb_idx].mtype;
+ } else {
+ return Err(DecoderError::MissingReference);
+ }
+ } else {
+ if !pic_hdr.ftype.is_bidir() {
+ mb.mtype = if br.read_bool()? { MBType::Inter } else { MBType::Intra };
+ } else {
+ mb.mtype = match br.read(2)? {
+ 0 => { MBType::Intra },
+ 1 => { MBType::Inter },
+ 2 => { MBType::Backward },
+ _ => { MBType::Bidir },
+ };
+ }
+ }
+ if band.mb_size == band.blk_size {
+ mb.cbp = br.read(1)? as u8;
+ } else {
+ mb.cbp = br.read(4)? as u8;
+ }
+ if band.inherit_qd {
+ if let Some(ref tileref) = ref_tile {
+ mb.qd = tileref.mb[mb_idx].qd;
+ mb.q = calc_quant(band.quant, mb.qd);
+ } else {
+ mb.q = band.quant as u8;
+ }
+ } else if (mb.cbp != 0) || ((band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q) {
+ mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+ mb.q = calc_quant(band.quant, mb.qd);
+ } else {
+ mb.q = band.quant as u8;
+ }
+
+ if mb.mtype != MBType::Intra {
+ if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ let mx = tileref.mb[mb_idx].mv_x;
+ let my = tileref.mb[mb_idx].mv_y;
+ if mv_scale == 0 {
+ mb.mv_x = mx;
+ mb.mv_y = my;
+ } else {
+ mb.mv_x = scale_mv(mx, mv_scale);
+ mb.mv_y = scale_mv(my, mv_scale);
+ }
+ }
+ } else {
+ mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
+ mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
+ mb.mv_x = mv_x;
+ mb.mv_y = mv_y;
+ if mb.mtype == MBType::Backward {
+ mb.mv_x = -mb.mv_x;
+ mb.mv_y = -mb.mv_y;
+ } else if mb.mtype == MBType::Bidir {
+ mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
+ mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
+ mb.mv2_x = -mv_x;
+ mb.mv2_y = -mv_y;
+ }
+ }
+ }
+ } else {
+ validate!(!pic_hdr.ftype.is_intra());
+ mb.mtype = MBType::Inter;
+ mb.cbp = 0;
+ mb.qd = 0;
+ if (band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q {
+ mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+ mb.q = calc_quant(band.quant, mb.qd);
+ }
+ if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ let mx = tileref.mb[mb_idx].mv_x;
+ let my = tileref.mb[mb_idx].mv_y;
+ if mv_scale == 0 {
+ mb.mv_x = mx;
+ mb.mv_y = my;
+ } else {
+ mb.mv_x = scale_mv(mx, mv_scale);
+ mb.mv_y = scale_mv(my, mv_scale);
+ }
+ }
+ }
+ }
+ tile.mb[mb_idx] = mb;
+ mb_idx += 1;
+ }
+ }
+ br.align();
+ Ok(())
+ }
+
+ fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize) {
+/* let mut idx0 = 0;
+ let mut idx1 = w / 2;
+ let mut idx2 = (h / 2) * sstride;
+ let mut idx3 = idx2 + idx1;
+ let mut oidx0 = 0;
+ let mut oidx1 = dstride;
+
+ for _ in 0..(h/2) {
+ for x in 0..(w/2) {
+ let p0 = src[idx0 + x];
+ let p1 = src[idx1 + x];
+ let p2 = src[idx2 + x];
+ let p3 = src[idx3 + x];
+ let s0 = p0 + p2;
+ let d0 = p0 - p2;
+ let s1 = p1 + p3;
+ let d1 = p1 - p3;
+ dst[oidx0 + x * 2 + 0] = clip8(((s0 + s1 + 2) >> 2) + 128);
+ dst[oidx0 + x * 2 + 1] = clip8(((d0 + d1 + 2) >> 2) + 128);
+ dst[oidx1 + x * 2 + 0] = clip8(((s0 - s1 + 2) >> 2) + 128);
+ dst[oidx1 + x * 2 + 1] = clip8(((d0 - d1 + 2) >> 2) + 128);
+ }
+ idx0 += sstride;
+ idx1 += sstride;
+ idx2 += sstride;
+ idx3 += sstride;
+ oidx0 += dstride * 2;
+ oidx1 += dstride * 2;
+ }*/
+ unsafe {
+ let hw = (w / 2) as isize;
+ let hh = (h / 2) as isize;
+ let mut band0 = src.as_ptr();
+ let mut band1 = band0.offset(hw);
+ let mut band2 = band0.offset(((h / 2) * sstride) as isize);
+ let mut band3 = band2.offset(hw);
+ let mut dst0 = dst.as_mut_ptr();
+ let mut dst1 = dst0.offset(dstride as isize);
+ for _ in 0..hh {
+ let mut b0_ptr = band0;
+ let mut b1_ptr = band1;
+ let mut b2_ptr = band2;
+ let mut b3_ptr = band3;
+ let mut d0_ptr = dst0;
+ let mut d1_ptr = dst1;
+ for _ in 0..hw {
+ let p0 = *b0_ptr as i32;
+ let p1 = *b1_ptr as i32;
+ let p2 = *b2_ptr as i32;
+ let p3 = *b3_ptr as i32;
+ let s0 = p0.wrapping_add(p2);
+ let s1 = p1.wrapping_add(p3);
+ let d0 = p0.wrapping_sub(p2);
+ let d1 = p1.wrapping_sub(p3);
+ let o0 = s0.wrapping_add(s1).wrapping_add(2);
+ let o1 = d0.wrapping_add(d1).wrapping_add(2);
+ let o2 = s0.wrapping_sub(s1).wrapping_add(2);
+ let o3 = d0.wrapping_sub(d1).wrapping_add(2);
+ *d0_ptr.offset(0) = mclip8((o0 >> 2).wrapping_add(128));
+ *d0_ptr.offset(1) = mclip8((o1 >> 2).wrapping_add(128));
+ *d1_ptr.offset(0) = mclip8((o2 >> 2).wrapping_add(128));
+ *d1_ptr.offset(1) = mclip8((o3 >> 2).wrapping_add(128));
+ b0_ptr = b0_ptr.offset(1);
+ b1_ptr = b1_ptr.offset(1);
+ b2_ptr = b2_ptr.offset(1);
+ b3_ptr = b3_ptr.offset(1);
+ d0_ptr = d0_ptr.offset(2);
+ d1_ptr = d1_ptr.offset(2);
+ }
+ band0 = band0.offset(sstride as isize);
+ band1 = band1.offset(sstride as isize);
+ band2 = band2.offset(sstride as isize);
+ band3 = band3.offset(sstride as isize);
+ dst0 = dst0.offset((dstride * 2) as isize);
+ dst1 = dst1.offset((dstride * 2) as isize);
+ }
+ }
+ }
+}
+
+struct Indeo4Decoder {
+ info: Rc<NACodecInfo>,
+ dec: IVIDecoder,
+}
+
+impl Indeo4Decoder {
+ fn new() -> Self {
+ Indeo4Decoder {
+ info: NACodecInfo::new_dummy(),
+ dec: IVIDecoder::new(),
+ }
+ }
+}
+
+impl NADecoder for Indeo4Decoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ let w = vinfo.get_width();
+ let h = vinfo.get_height();
+ let f = vinfo.is_flipped();
+ let fmt = formats::YUV410_FORMAT;
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, 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<NAFrameRef> {
+ let src = pkt.get_buffer();
+ let mut br = BitReader::new(src.as_slice(), src.len(), BitReaderMode::LE);
+
+ let mut ip = Indeo4Parser::new();
+ let bufinfo = self.dec.decode_frame(&mut ip, &mut br)?;
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(self.dec.is_intra());
+ frm.set_frame_type(self.dec.get_frame_type());
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+}
+
+const INDEO4_PICTURE_SIZE_TAB: [[usize; 2]; 7] = [
+ [640, 480], [320, 240], [160, 120], [704, 480], [352, 240], [352, 288], [176, 144]
+];
+
+const INDEO4_SLICE_SIZE_TAB: [usize; 15] = [
+ 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480
+];
+
+const INDEO4_FRAME_TYPE: [IVIFrameType; 7] = [
+ IVIFrameType::Intra, IVIFrameType::Intra1, IVIFrameType::Inter, IVIFrameType::Bidir,
+ IVIFrameType::InterDroppable, IVIFrameType::NULL, IVIFrameType::NULL2
+];
+
+const INDEO4_TRANSFORMS: [IVITransformType; 18] = [
+ IVITransformType::Haar(TSize::T8x8, TDir::TwoD),
+ IVITransformType::Haar(TSize::T8x8, TDir::Row),
+ IVITransformType::Haar(TSize::T8x8, TDir::Col),
+ IVITransformType::None(TSize::T8x8),
+ IVITransformType::Slant(TSize::T8x8, TDir::TwoD),
+ IVITransformType::Slant(TSize::T8x8, TDir::Row),
+ IVITransformType::Slant(TSize::T8x8, TDir::Col),
+ IVITransformType::DCT(TSize::T8x8, TDir::TwoD),
+ IVITransformType::DCT(TSize::T8x8, TDir::Row),
+ IVITransformType::DCT(TSize::T8x8, TDir::Col),
+ IVITransformType::Haar(TSize::T4x4, TDir::TwoD),
+ IVITransformType::Slant(TSize::T4x4, TDir::TwoD),
+ IVITransformType::None(TSize::T4x4),
+ IVITransformType::Haar(TSize::T4x4, TDir::Row),
+ IVITransformType::Haar(TSize::T4x4, TDir::Col),
+ IVITransformType::Slant(TSize::T4x4, TDir::Row),
+ IVITransformType::Slant(TSize::T4x4, TDir::Col),
+ IVITransformType::DCT(TSize::T4x4, TDir::TwoD),
+];
+
+const INDEO4_SCAN_8X8_ALT: [usize; 64] = [
+ 0, 8, 1, 9, 16, 24, 2, 3,
+ 17, 25, 10, 11, 32, 40, 48, 56,
+ 4, 5, 6, 7, 33, 41, 49, 57,
+ 18, 19, 26, 27, 12, 13, 14, 15,
+ 34, 35, 43, 42, 50, 51, 59, 58,
+ 20, 21, 22, 23, 31, 30, 29, 28,
+ 36, 37, 38, 39, 47, 46, 45, 44,
+ 52, 53, 54, 55, 63, 62, 61, 60
+];
+const INDEO4_SCAN_4X4_ALT: [usize; 16] = [ 0, 1, 4, 5, 8, 12, 2, 3, 9, 13, 6, 7, 10, 11, 14, 15 ];
+const INDEO4_SCAN_4X4_VER: [usize; 16] = [ 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 ];
+const INDEO4_SCAN_4X4_HOR: [usize; 16] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ];
+
+const INDEO4_SCANS_8X8: [&[usize; 64]; 5] = [
+ &IVI_ZIGZAG, &INDEO4_SCAN_8X8_ALT, &IVI_SCAN_8X8_HOR, &IVI_SCAN_8X8_VER, &IVI_ZIGZAG
+];
+const INDEO4_SCANS_4X4: [&[usize; 16]; 5] = [
+ &IVI_SCAN_4X4, &INDEO4_SCAN_4X4_ALT, &INDEO4_SCAN_4X4_VER, &INDEO4_SCAN_4X4_HOR, &IVI_SCAN_4X4
+];
+
+const INDEO4_Q8X8_IDX: [usize; 15] = [ 0, 1, 0, 2, 1, 3, 0, 4, 1, 5, 0, 1, 6, 7, 8 ];
+const INDEO4_Q4X4_IDX: [usize; 7] = [ 0, 1, 2, 2, 3, 3, 4 ];
+
+const INDEO4_QUANT8X8_INTRA: [[u16; 64]; 9] = [
+ [
+ 43, 342, 385, 470, 555, 555, 598, 726,
+ 342, 342, 470, 513, 555, 598, 726, 769,
+ 385, 470, 555, 555, 598, 726, 726, 811,
+ 470, 470, 555, 555, 598, 726, 769, 854,
+ 470, 555, 555, 598, 683, 726, 854, 1025,
+ 555, 555, 598, 683, 726, 854, 1025, 1153,
+ 555, 555, 598, 726, 811, 982, 1195, 1451,
+ 555, 598, 726, 811, 982, 1195, 1451, 1793
+ ], [
+ 86, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+ 1195, 1195, 2390, 2390, 4865, 4865, 4865, 4865,
+ 2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+ 2390, 2390, 4865, 4865, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827,
+ 4865, 4865, 6827, 6827, 6827, 6827, 6827, 6827
+ ], [
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835,
+ 235, 1067, 1195, 1323, 1451, 1579, 1707, 1835
+ ], [
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414,
+ 1707, 1707, 3414, 3414, 3414, 3414, 3414, 3414
+ ], [
+ 897, 897, 897, 897, 897, 897, 897, 897,
+ 1067, 1067, 1067, 1067, 1067, 1067, 1067, 1067,
+ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ 1409, 1409, 1409, 1409, 1409, 1409, 1409, 1409,
+ 1579, 1579, 1579, 1579, 1579, 1579, 1579, 1579,
+ 1750, 1750, 1750, 1750, 1750, 1750, 1750, 1750,
+ 1921, 1921, 1921, 1921, 1921, 1921, 1921, 1921,
+ 2091, 2091, 2091, 2091, 2091, 2091, 2091, 2091
+ ], [
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414
+ ], [
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390,
+ 2390, 2390, 2390, 2390, 2390, 2390, 2390, 2390
+ ], [
+ 22, 171, 214, 257, 257, 299, 299, 342,
+ 171, 171, 257, 257, 299, 299, 342, 385,
+ 214, 257, 257, 299, 299, 342, 342, 385,
+ 257, 257, 257, 299, 299, 342, 385, 427,
+ 257, 257, 299, 299, 342, 385, 427, 513,
+ 257, 299, 299, 342, 385, 427, 513, 598,
+ 299, 299, 299, 385, 385, 470, 598, 726,
+ 299, 299, 385, 385, 470, 598, 726, 897
+ ], [
+ 86, 598, 1195, 1195, 2390, 2390, 2390, 2390,
+ 598, 598, 1195, 1195, 2390, 2390, 2390, 2390,
+ 1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+ 1195, 1195, 2390, 2390, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2390, 2390, 3414, 3414, 3414, 3414, 3414, 3414
+ ]
+];
+const INDEO4_QUANT8X8_INTER: [[u16; 64]; 9] = [
+ [
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470,
+ 427, 427, 470, 470, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 427, 427, 470, 427, 427, 427, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470,
+ 470, 470, 470, 470, 470, 470, 470, 470
+ ], [
+ 1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+ 1707, 1707, 2433, 2433, 3414, 3414, 3414, 3414,
+ 2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+ 2433, 2433, 3414, 3414, 4822, 4822, 4822, 4822,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414,
+ 3414, 3414, 4822, 4822, 3414, 3414, 3414, 3414
+ ], [
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281,
+ 1195, 1195, 1281, 1238, 1195, 1195, 1281, 1281
+ ], [
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433,
+ 2433, 2433, 3414, 3414, 2433, 2433, 2433, 2433
+ ], [
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1195, 1195, 1195, 1195, 1195, 1195, 1195, 1195,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
+ 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281
+ ], [
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 3414, 3414, 3414, 3414, 3414, 3414, 3414, 3414,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433,
+ 2433, 2433, 2433, 2433, 2433, 2433, 2433, 2433
+ ], [
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707,
+ 1707, 1707, 1707, 1707, 1707, 1707, 1707, 1707
+ ], [
+ 86, 171, 171, 214, 214, 214, 214, 257,
+ 171, 171, 214, 214, 214, 214, 257, 257,
+ 171, 214, 214, 214, 214, 257, 257, 257,
+ 214, 214, 214, 214, 257, 257, 257, 299,
+ 214, 214, 214, 257, 257, 257, 299, 299,
+ 214, 214, 257, 257, 257, 299, 299, 299,
+ 214, 257, 257, 257, 299, 299, 299, 342,
+ 257, 257, 257, 299, 299, 299, 342, 342
+ ], [
+ 854, 854, 1195, 1195, 1707, 1707, 1707, 1707,
+ 854, 854, 1195, 1195, 1707, 1707, 1707, 1707,
+ 1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+ 1195, 1195, 1707, 1707, 2390, 2390, 2390, 2390,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707,
+ 1707, 1707, 2390, 2390, 1707, 1707, 1707, 1707
+ ]
+];
+const INDEO4_QUANT4X4_INTRA: [[u16; 16]; 5] = [
+ [
+ 22, 214, 257, 299,
+ 214, 257, 299, 342,
+ 257, 299, 342, 427,
+ 299, 342, 427, 513
+ ], [
+ 129, 1025, 1451, 1451,
+ 1025, 1025, 1451, 1451,
+ 1451, 1451, 2049, 2049,
+ 1451, 1451, 2049, 2049
+ ], [
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171
+ ], [
+ 43, 43, 43, 43,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171
+ ], [
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43
+ ]
+];
+const INDEO4_QUANT4X4_INTER: [[u16; 16]; 5] = [
+ [
+ 107, 214, 257, 299,
+ 214, 257, 299, 299,
+ 257, 299, 299, 342,
+ 299, 299, 342, 342
+ ], [
+ 513, 1025, 1238, 1238,
+ 1025, 1025, 1238, 1238,
+ 1238, 1238, 1451, 1451,
+ 1238, 1238, 1451, 1451
+ ], [
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171,
+ 43, 171, 171, 171
+ ], [
+ 43, 43, 43, 43,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171,
+ 171, 171, 171, 171
+ ], [
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43,
+ 43, 43, 43, 43
+ ]
+];
+const INDEO4_Q8_INTRA: [&[u16; 64]; 9] = [
+ &INDEO4_QUANT8X8_INTRA[0], &INDEO4_QUANT8X8_INTRA[1], &INDEO4_QUANT8X8_INTRA[2],
+ &INDEO4_QUANT8X8_INTRA[3], &INDEO4_QUANT8X8_INTRA[4], &INDEO4_QUANT8X8_INTRA[5],
+ &INDEO4_QUANT8X8_INTRA[6], &INDEO4_QUANT8X8_INTRA[7], &INDEO4_QUANT8X8_INTRA[8],
+];
+const INDEO4_Q8_INTER: [&[u16; 64]; 9] = [
+ &INDEO4_QUANT8X8_INTER[0], &INDEO4_QUANT8X8_INTER[1], &INDEO4_QUANT8X8_INTER[2],
+ &INDEO4_QUANT8X8_INTER[3], &INDEO4_QUANT8X8_INTER[4], &INDEO4_QUANT8X8_INTER[5],
+ &INDEO4_QUANT8X8_INTER[6], &INDEO4_QUANT8X8_INTER[7], &INDEO4_QUANT8X8_INTER[8],
+];
+const INDEO4_Q4_INTRA: [&[u16; 16]; 5] = [
+ &INDEO4_QUANT4X4_INTRA[0], &INDEO4_QUANT4X4_INTRA[1], &INDEO4_QUANT4X4_INTRA[2],
+ &INDEO4_QUANT4X4_INTRA[3], &INDEO4_QUANT4X4_INTRA[4]
+];
+const INDEO4_Q4_INTER: [&[u16; 16]; 5] = [
+ &INDEO4_QUANT4X4_INTER[0], &INDEO4_QUANT4X4_INTER[1], &INDEO4_QUANT4X4_INTER[2],
+ &INDEO4_QUANT4X4_INTER[3], &INDEO4_QUANT4X4_INTER[4]
+];
+
+pub fn get_decoder() -> Box<NADecoder> {
+ Box::new(Indeo4Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use crate::test::dec_video::test_file_decoding;
+ #[test]
+ fn test_indeo4() {
+ test_file_decoding("avi", "assets/IV4/volcano.avi", /*None*/Some(16), true, false, None/*Some("iv4")*/);
+//panic!("the end");
+ }
+}
diff --git a/nihav-indeo/src/codecs/indeo5.rs b/nihav-indeo/src/codecs/indeo5.rs
new file mode 100644
index 0000000..5256fa4
--- /dev/null
+++ b/nihav-indeo/src/codecs/indeo5.rs
@@ -0,0 +1,729 @@
+use std::rc::Rc;
+use std::cell::{Ref, RefCell};
+use nihav_core::io::bitreader::*;
+use nihav_core::formats;
+use nihav_core::frame::*;
+use nihav_core::codecs::*;
+use super::ivi::*;
+use super::ivibr::*;
+
+fn calc_quant(glob_q: u32, qd: i16) -> usize {
+ let qq = (glob_q as i16) + (qd as i16);
+ if qq < 0 {
+ 0
+ } else if qq > 23 {
+ 23
+ } else {
+ qq as usize
+ }
+}
+
+struct Indeo5Parser {
+ mb_cb: IVICodebook,
+
+ width: usize,
+ height: usize,
+ tile_w: usize,
+ tile_h: usize,
+ luma_bands: usize,
+ chroma_bands: usize,
+
+ is_hpel: [bool; 5],
+ mb_size: [usize; 5],
+ blk_size: [usize; 5],
+}
+
+impl Indeo5Parser {
+ fn new() -> Self {
+ Indeo5Parser {
+ mb_cb: IVI_CB_ZERO,
+
+ width: 0,
+ height: 0,
+ tile_w: 0,
+ tile_h: 0,
+ luma_bands: 0,
+ chroma_bands: 0,
+
+ is_hpel: [false; 5],
+ mb_size: [0; 5],
+ blk_size: [0; 5],
+ }
+ }
+}
+
+fn skip_extension(br: &mut BitReader) -> DecoderResult<()> {
+ loop {
+ let len = br.read(8)?;
+ if len == 0 { break; }
+ br.skip(len * 8)?;
+ }
+ Ok(())
+}
+
+impl IndeoXParser for Indeo5Parser {
+#[allow(unused_variables)]
+#[allow(unused_assignments)]
+ fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader> {
+ let sync = br.read(5)?;
+ validate!(sync == 0x1F);
+ let ftype_idx = br.read(3)?;
+ validate!(ftype_idx < 5);
+ let ftype = INDEO5_FRAME_TYPE[ftype_idx as usize];
+ let fnum = br.read(8)?;
+ if ftype == IVIFrameType::Intra {
+ let gop_flags = br.read(8)?;
+ let hdr_size;
+ if (gop_flags & 0x01) != 0 {
+ hdr_size = br.read(16)?;
+ } else {
+ hdr_size = 0;
+ }
+ if (gop_flags & 0x20) != 0 {
+ br.skip(32)?; // lock word
+ }
+ self.tile_w = 0;
+ self.tile_h = 0;
+ if (gop_flags & 0x40) != 0 {
+ self.tile_w = 64 << br.read(2)?;
+ self.tile_h = self.tile_w;
+ }
+ validate!(self.tile_w < 256);
+ self.luma_bands = (br.read(2)? * 3 + 1) as usize;
+ self.chroma_bands = (br.read(1)? * 3 + 1) as usize;
+ validate!((self.luma_bands == 4) || (self.luma_bands == 1));
+ validate!(self.chroma_bands == 1);
+ let pic_size_idx = br.read(4)? as usize;
+ let w;
+ let h;
+ if pic_size_idx < 15 {
+ w = INDEO5_PICTURE_SIZE_TAB[pic_size_idx][0];
+ h = INDEO5_PICTURE_SIZE_TAB[pic_size_idx][1];
+ } else {
+ h = br.read(13)? as usize;
+ w = br.read(13)? as usize;
+ }
+ validate!((w != 0) && (h != 0));
+ self.width = w;
+ self.height = h;
+
+ validate!((gop_flags & 0x02) == 0);
+ if self.tile_w == 0 {
+ self.tile_w = w;
+ self.tile_h = h;
+ }
+ for b in 0..self.luma_bands+self.chroma_bands {
+ self.is_hpel[b] = br.read_bool()?;
+ let mb_scale = br.read(1)?;
+ self.blk_size[b] = 8 >> br.read(1)?;
+ self.mb_size[b] = self.blk_size[b] << (1 - mb_scale);
+ let ext_tr = br.read_bool()?;
+ validate!(!ext_tr);
+ let end_marker = br.read(2)?;
+ validate!(end_marker == 0);
+ }
+ if (gop_flags & 0x08) != 0 {
+ let align = br.read(3)?;
+ validate!(align == 0);
+ if br.read_bool()? {
+ br.skip(24)?; // transparency color
+ }
+ }
+ br.align();
+ br.skip(23)?;
+ if br.read_bool()? { // gop extension
+ loop {
+ let v = br.read(16)?;
+ if (v & 0x8000) == 0 { break; }
+ }
+ }
+ br.align();
+ }
+ if ftype.is_null() {
+ br.align();
+ return Ok(PictureHeader::new_null(ftype));
+ }
+ let flags = br.read(8)?;
+ let size;
+ if (flags & 0x01) != 0 {
+ size = br.read(24)?;
+ } else {
+ size = 0;
+ }
+ let checksum;
+ if (flags & 0x10) != 0 {
+ checksum = br.read(16)?;
+ } else {
+ checksum = 0;
+ }
+ if (flags & 0x20) != 0 {
+ skip_extension(br)?;
+ }
+ let in_q = (flags & 0x08) != 0;
+ self.mb_cb = br.read_ivi_codebook_desc(true, (flags & 0x40) != 0)?;
+ br.skip(3)?;
+ br.align();
+
+ Ok(PictureHeader::new(ftype, self.width, self.height, self.tile_w, self.tile_h, false, self.luma_bands, self.chroma_bands, in_q))
+ }
+
+#[allow(unused_variables)]
+ fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane_no: usize, band_no: usize) -> DecoderResult<BandHeader> {
+ let band_flags = br.read(8)?;
+
+ if (band_flags & 0x01) != 0 {
+ br.align();
+ return Ok(BandHeader::new_empty(plane_no, band_no));
+ }
+ let inherit_mv = (band_flags & 0x02) != 0;
+ let has_qdelta = (band_flags & 0x04) != 0;
+ let inherit_qd = ((band_flags & 0x08) != 0) || !has_qdelta;
+ let data_size: usize;
+ if (band_flags & 0x80) != 0 {
+ data_size = br.read(24)? as usize;
+ } else {
+ data_size = 0;
+ }
+ validate!(data_size <= ((br.left() / 8) as usize));
+
+ let num_corr: usize;
+ let mut corr_map: [u8; CORR_MAP_SIZE] = [0; CORR_MAP_SIZE];
+ if (band_flags & 0x10) != 0 {
+ num_corr = br.read(8)? as usize;
+ validate!(num_corr*2 <= CORR_MAP_SIZE);
+ for i in 0..num_corr*2 {
+ corr_map[i] = br.read(8)? as u8;
+ }
+ } else {
+ num_corr = 0;
+ }
+ let rvmap_idx;
+ if (band_flags & 0x40) != 0 {
+ rvmap_idx = br.read(3)? as usize;
+ } else {
+ rvmap_idx = 8;
+ }
+ let blk_cb = br.read_ivi_codebook_desc(false, (band_flags & 0x80) != 0)?;
+ if br.read_bool()? {
+ br.skip(16)?; // checksum
+ }
+ let band_q = br.read(5)?;
+ if (band_flags & 0x20) != 0 {
+ skip_extension(br)?;
+ }
+ br.align();
+
+ let tr;
+ let txtype;
+ let band_id = if plane_no == 0 { band_no } else { self.luma_bands };
+ match plane_no {
+ 0 => {
+ let scan = INDEO5_SCAN8X8[band_no];
+ let qintra;
+ let qinter;
+ validate!(self.blk_size[band_id] == 8);
+ match band_no {
+ 0 => {
+ tr = IVITransformType::Slant(TSize::T8x8, TDir::TwoD);
+ if self.luma_bands == 1 {
+ qintra = INDEO5_Q8_INTRA[0];
+ qinter = INDEO5_Q8_INTER[0];
+ } else {
+ qintra = INDEO5_Q8_INTRA[1];
+ qinter = INDEO5_Q8_INTER[1];
+ }
+ },
+ 1 => {
+ tr = IVITransformType::Slant(TSize::T8x8, TDir::Row);
+ qintra = INDEO5_Q8_INTRA[2];
+ qinter = INDEO5_Q8_INTER[2];
+ },
+ 2 => {
+ tr = IVITransformType::Slant(TSize::T8x8, TDir::Col);
+ qintra = INDEO5_Q8_INTRA[3];
+ qinter = INDEO5_Q8_INTER[3];
+ },
+ 3 => {
+ tr = IVITransformType::None(TSize::T8x8);
+ qintra = INDEO5_Q8_INTRA[4];
+ qinter = INDEO5_Q8_INTER[4];
+ },
+ _ => { unreachable!(); }
+ };
+ txtype = TxType::Transform8(TxParams8x8::new(qintra, qinter, scan));
+ },
+ 1 | 2 => {
+ validate!(self.blk_size[band_id] == 4);
+ tr = IVITransformType::Slant(TSize::T4x4, TDir::TwoD);
+ let scan = INDEO5_SCAN4X4;
+ let qintra = INDEO5_Q4_INTRA;
+ let qinter = INDEO5_Q4_INTER;
+ txtype = TxType::Transform4(TxParams4x4::new(qintra, qinter, scan));
+ },
+ _ => { unreachable!(); }
+ };
+
+ Ok(BandHeader::new(plane_no, band_no, self.mb_size[band_id], self.blk_size[band_id], self.is_hpel[band_id], inherit_mv, has_qdelta, inherit_qd, band_q, rvmap_idx, num_corr, corr_map, blk_cb, tr, txtype))
+ }
+
+ fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band: &BandHeader, tile: &mut IVITile, ref_tile: Option<Ref<IVITile>>, mv_scale: u8) -> DecoderResult<()> {
+ let mut mv_x = 0;
+ let mut mv_y = 0;
+ let band_id = if pic_hdr.luma_bands == 4 { band.band_no + 1 } else { 0 };
+ let mut mb_idx = 0;
+ for mb_y in 0..tile.mb_h {
+ for mb_x in 0..tile.mb_w {
+ let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
+ if !br.read_bool()? {
+ if pic_hdr.ftype.is_intra() {
+ mb.mtype = MBType::Intra;
+ } else if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ mb.mtype = tileref.mb[mb_idx].mtype;
+ } else {
+ return Err(DecoderError::MissingReference);
+ }
+ } else {
+ mb.mtype = if br.read_bool()? { MBType::Inter } else { MBType::Intra };
+ }
+ if band.mb_size == band.blk_size {
+ mb.cbp = br.read(1)? as u8;
+ } else {
+ mb.cbp = br.read(4)? as u8;
+ }
+ let q;
+ if band.has_qdelta {
+ if band.inherit_qd {
+ if let Some(ref tileref) = ref_tile {
+ mb.qd = tileref.mb[mb_idx].qd;
+ q = calc_quant(band.quant, mb.qd);
+ } else {
+ return Err(DecoderError::MissingReference);
+ }
+ } else if (mb.cbp != 0) || ((band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q) {
+ mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+ q = calc_quant(band.quant, mb.qd);
+ } else {
+ q = band.quant as usize;
+ }
+ } else {
+ q = band.quant as usize;
+ }
+
+ if mb.mtype == MBType::Intra {
+ if band.blk_size == 8 {
+ mb.q = INDEO5_QSCALE8_INTRA[band_id][q];
+ } else {
+ mb.q = INDEO5_QSCALE4_INTRA[q];
+ }
+ } else {
+ if band.blk_size == 8 {
+ mb.q = INDEO5_QSCALE8_INTER[band_id][q];
+ } else {
+ mb.q = INDEO5_QSCALE4_INTER[q];
+ }
+ }
+
+ if mb.mtype != MBType::Intra {
+ if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ let mx = tileref.mb[mb_idx].mv_x;
+ let my = tileref.mb[mb_idx].mv_y;
+ if mv_scale == 0 {
+ mb.mv_x = mx;
+ mb.mv_y = my;
+ } else {
+ mb.mv_x = scale_mv(mx, mv_scale);
+ mb.mv_y = scale_mv(my, mv_scale);
+ }
+ }
+ } else {
+ mv_y += br.read_ivi_cb_s(&self.mb_cb)?;
+ mv_x += br.read_ivi_cb_s(&self.mb_cb)?;
+ mb.mv_x = mv_x;
+ mb.mv_y = mv_y;
+ }
+ }
+ } else {
+ validate!(!pic_hdr.ftype.is_intra());
+ mb.mtype = MBType::Inter;
+ mb.cbp = 0;
+ mb.qd = 0;
+ if (band.plane_no == 0) && (band.band_no == 0) && pic_hdr.in_q {
+ mb.qd = br.read_ivi_cb_s(&self.mb_cb)? as i16;
+ let q = calc_quant(band.quant, mb.qd);
+ if mb.mtype == MBType::Intra {
+ if band.blk_size == 8 {
+ mb.q = INDEO5_QSCALE8_INTRA[band_id][q];
+ } else {
+ mb.q = INDEO5_QSCALE4_INTRA[q];
+ }
+ } else {
+ if band.blk_size == 8 {
+ mb.q = INDEO5_QSCALE8_INTER[band_id][q];
+ } else {
+ mb.q = INDEO5_QSCALE4_INTER[q];
+ }
+ }
+ }
+ if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ let mx = tileref.mb[mb_idx].mv_x;
+ let my = tileref.mb[mb_idx].mv_y;
+ if mv_scale == 0 {
+ mb.mv_x = mx;
+ mb.mv_y = my;
+ } else {
+ mb.mv_x = scale_mv(mx, mv_scale);
+ mb.mv_y = scale_mv(my, mv_scale);
+ }
+ }
+ }
+ }
+ tile.mb[mb_idx] = mb;
+ mb_idx += 1;
+ }
+ }
+ br.align();
+ Ok(())
+ }
+
+ fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize) {
+ let mut idx0 = 0;
+ let mut idx1 = w / 2;
+ let mut idx2 = (h / 2) * sstride;
+ let mut idx3 = idx2 + idx1;
+ let mut bidx1 = idx1;
+ let mut bidx3 = idx3;
+ let mut oidx0 = 0;
+ let mut oidx1 = dstride;
+ let filt_lo = |a: i16, b: i16| a + b;
+ let filt_hi = |a: i16, b: i16, c: i16| a - b * 6 + c;
+
+ for _ in 0..(h/2) {
+ let mut b0_1 = src[idx0];
+ let mut b0_2 = src[idx0 + sstride];
+ let mut b1_1 = src[bidx1];
+ let mut b1_2 = src[idx1];
+ let mut b1_3 = filt_hi(b1_1, b1_2, src[idx1 + sstride]);
+ let mut b2_1;
+ let mut b2_2 = src[idx2];
+ let mut b2_3 = b2_2;
+ let mut b2_4;
+ let mut b2_5 = src[idx2 + sstride];
+ let mut b2_6 = b2_5;
+ let mut b3_1;
+ let mut b3_2 = src[bidx3];
+ let mut b3_3 = b3_2;
+ let mut b3_4;
+ let mut b3_5 = src[idx3];
+ let mut b3_6 = b3_5;
+ let mut b3_8 = filt_hi(b3_2, b3_5, src[idx3 + sstride]);
+ let mut b3_9 = b3_8;
+ let mut b3_7;
+
+ for x in 0..(w/2) {
+ b2_1 = b2_2;
+ b2_2 = b2_3;
+ b2_4 = b2_5;
+ b2_5 = b2_6;
+ b3_1 = b3_2;
+ b3_2 = b3_3;
+ b3_4 = b3_5;
+ b3_5 = b3_6;
+ b3_7 = b3_8;
+ b3_8 = b3_9;
+
+ let tmp0 = b0_1;
+ let tmp1 = b0_2;
+ b0_1 = src[idx0 + x + 1];
+ b0_2 = src[idx0 + x + 1 + sstride];
+ let mut p0 = tmp0 << 4;
+ let mut p1 = (tmp0 + b0_1) << 3;
+ let mut p2 = (tmp0 + tmp1) << 3;
+ let mut p3 = (tmp0 + tmp1 + b0_1 + b0_2) << 2;
+
+ let tmp0 = b1_1;
+ let tmp1 = b1_2;
+ let tmp2 = filt_lo(tmp0, tmp1);
+ let tmp3 = filt_hi(tmp0, tmp1, b1_3);
+ b1_2 = src[ idx1 + x + 1];
+ b1_1 = src[bidx1 + x + 1];
+ b1_3 = filt_hi(b1_1, b1_2, src[idx1 + x + 1 + sstride]);
+ p0 += tmp2 << 3;
+ p1 += (tmp2 + b1_1 + b1_2) << 2;
+ p2 += tmp3 << 2;
+ p3 += (tmp3 + b1_3) << 1;
+
+ b2_3 = src[idx2 + x + 1];
+ b2_6 = src[idx2 + x + 1 + sstride];
+ let tmp0 = filt_lo(b2_1, b2_2);
+ let tmp1 = filt_hi(b2_1, b2_2, b2_3);
+ p0 += tmp0 << 3;
+ p1 += tmp1 << 2;
+ p2 += (tmp0 + filt_lo(b2_4, b2_5)) << 2;
+ p3 += (tmp1 + filt_hi(b2_4, b2_5, b2_6)) << 1;
+
+ b3_6 = src[idx3 + x + 1];
+ b3_3 = src[bidx3 + x + 1];
+ b3_9 = filt_hi(b3_3, b3_6, src[idx3 + x + 1 + sstride]);
+ let tmp0 = b3_1 + b3_4;
+ let tmp1 = b3_2 + b3_5;
+ let tmp2 = b3_3 + b3_6;
+ p0 += filt_lo(tmp0, tmp1) << 2;
+ p1 += filt_hi(tmp0, tmp1, tmp2) << 1;
+ p2 += filt_lo(b3_7, b3_8) << 1;
+ p3 += filt_hi(b3_7, b3_8, b3_9) << 0;
+
+ dst[oidx0 + x * 2 + 0] = clip8((p0 >> 6) + 128);
+ dst[oidx0 + x * 2 + 1] = clip8((p1 >> 6) + 128);
+ dst[oidx1 + x * 2 + 0] = clip8((p2 >> 6) + 128);
+ dst[oidx1 + x * 2 + 1] = clip8((p3 >> 6) + 128);
+ }
+ bidx1 = idx1;
+ bidx3 = idx3;
+ idx0 += sstride;
+ idx1 += sstride;
+ idx2 += sstride;
+ idx3 += sstride;
+ oidx0 += dstride * 2;
+ oidx1 += dstride * 2;
+ }
+ }
+}
+
+struct Indeo5Decoder {
+ info: Rc<NACodecInfo>,
+ dec: IVIDecoder,
+ ip: Indeo5Parser,
+}
+
+impl Indeo5Decoder {
+ fn new() -> Self {
+ Indeo5Decoder {
+ info: NACodecInfo::new_dummy(),
+ dec: IVIDecoder::new(),
+ ip: Indeo5Parser::new(),
+ }
+ }
+}
+
+impl NADecoder for Indeo5Decoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Video(vinfo) = info.get_properties() {
+ let w = vinfo.get_width();
+ let h = vinfo.get_height();
+ let f = vinfo.is_flipped();
+ let fmt = formats::YUV410_FORMAT;
+ let myinfo = NACodecTypeInfo::Video(NAVideoInfo::new(w, h, f, 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<NAFrameRef> {
+ let src = pkt.get_buffer();
+ let mut br = BitReader::new(src.as_slice(), src.len(), BitReaderMode::LE);
+
+ let bufinfo = self.dec.decode_frame(&mut self.ip, &mut br)?;
+ let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), bufinfo);
+ frm.set_keyframe(self.dec.is_intra());
+ frm.set_frame_type(self.dec.get_frame_type());
+ Ok(Rc::new(RefCell::new(frm)))
+ }
+}
+
+const INDEO5_PICTURE_SIZE_TAB: [[usize; 2]; 15] = [
+ [640, 480], [320, 240], [160, 120], [704, 480], [352, 240], [352, 288], [176, 144],
+ [240, 180], [640, 240], [704, 240], [80, 60], [88, 72], [0, 0], [0, 0], [0, 0]
+];
+
+const INDEO5_FRAME_TYPE: [IVIFrameType; 5] = [
+ IVIFrameType::Intra, IVIFrameType::Inter, IVIFrameType::InterScal,
+ IVIFrameType::InterDroppable, IVIFrameType::NULL,
+];
+
+const INDEO5_QUANT8X8_INTRA: [[u16; 64]; 5] = [
+ [
+ 0x1a, 0x2e, 0x36, 0x42, 0x46, 0x4a, 0x4e, 0x5a,
+ 0x2e, 0x32, 0x3e, 0x42, 0x46, 0x4e, 0x56, 0x6a,
+ 0x36, 0x3e, 0x3e, 0x44, 0x4a, 0x54, 0x66, 0x72,
+ 0x42, 0x42, 0x44, 0x4a, 0x52, 0x62, 0x6c, 0x7a,
+ 0x46, 0x46, 0x4a, 0x52, 0x5e, 0x66, 0x72, 0x8e,
+ 0x4a, 0x4e, 0x54, 0x62, 0x66, 0x6e, 0x86, 0xa6,
+ 0x4e, 0x56, 0x66, 0x6c, 0x72, 0x86, 0x9a, 0xca,
+ 0x5a, 0x6a, 0x72, 0x7a, 0x8e, 0xa6, 0xca, 0xfe,
+ ], [
+ 0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
+ 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+ 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
+ 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+ 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
+ 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+ 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
+ 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+ ], [
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ ], [
+ 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+ 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
+ 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+ 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ ], [
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ ]
+];
+const INDEO5_QUANT8X8_INTER: [[u16; 64]; 5] = [
+ [
+ 0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
+ 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+ 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
+ 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+ 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
+ 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+ 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
+ 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+ ], [
+ 0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a,
+ 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e,
+ 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62,
+ 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66,
+ 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a,
+ 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e,
+ 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72,
+ 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76,
+ ], [
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2,
+ ], [
+ 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+ 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4,
+ 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde,
+ 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6,
+ 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2,
+ ], [
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e,
+ ]
+];
+const INDEO5_QUANT4X4_INTRA: [u16; 16] = [
+ 0x1e, 0x3e, 0x4a, 0x52,
+ 0x3e, 0x4a, 0x52, 0x5e,
+ 0x4a, 0x52, 0x5e, 0x7a,
+ 0x52, 0x5e, 0x7a, 0x92
+];
+const INDEO5_QUANT4X4_INTER: [u16; 16] = [
+ 0x1e, 0x3e, 0x4a, 0x52,
+ 0x3e, 0x4a, 0x52, 0x56,
+ 0x4a, 0x52, 0x56, 0x5e,
+ 0x52, 0x56, 0x5e, 0x66
+];
+const INDEO5_Q8_INTRA: [&[u16; 64]; 5] = [
+ &INDEO5_QUANT8X8_INTRA[0], &INDEO5_QUANT8X8_INTRA[1], &INDEO5_QUANT8X8_INTRA[2],
+ &INDEO5_QUANT8X8_INTRA[3], &INDEO5_QUANT8X8_INTRA[4],
+];
+const INDEO5_Q8_INTER: [&[u16; 64]; 5] = [
+ &INDEO5_QUANT8X8_INTER[0], &INDEO5_QUANT8X8_INTER[1], &INDEO5_QUANT8X8_INTER[2],
+ &INDEO5_QUANT8X8_INTER[3], &INDEO5_QUANT8X8_INTER[4],
+];
+const INDEO5_Q4_INTRA: &[u16; 16] = &INDEO5_QUANT4X4_INTRA;
+const INDEO5_Q4_INTER: &[u16; 16] = &INDEO5_QUANT4X4_INTER;
+
+const INDEO5_SCAN8X8: [&[usize; 64]; 4] = [
+ &IVI_ZIGZAG, &IVI_SCAN_8X8_VER, &IVI_SCAN_8X8_HOR, &IVI_SCAN_8X8_HOR
+];
+const INDEO5_SCAN4X4: &[usize; 16] = &IVI_SCAN_4X4;
+
+const INDEO5_QSCALE8_INTRA: [[u8; 24]; 5] = [
+ [
+ 0x0b, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20,
+ 0x22, 0x24, 0x27, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x37, 0x39, 0x3c,
+ ], [
+ 0x01, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x28, 0x2c,
+ 0x30, 0x34, 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x52, 0x58, 0x5e, 0x65, 0x6c,
+ ], [
+ 0x13, 0x22, 0x27, 0x2a, 0x2d, 0x33, 0x36, 0x3c, 0x41, 0x45, 0x49, 0x4e,
+ 0x53, 0x58, 0x5d, 0x63, 0x69, 0x6f, 0x75, 0x7c, 0x82, 0x88, 0x8e, 0x95,
+ ], [
+ 0x13, 0x1f, 0x21, 0x24, 0x27, 0x29, 0x2d, 0x2f, 0x34, 0x37, 0x3a, 0x3d,
+ 0x40, 0x44, 0x48, 0x4c, 0x4f, 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6b,
+ ], [
+ 0x31, 0x42, 0x47, 0x47, 0x4d, 0x52, 0x58, 0x58, 0x5d, 0x63, 0x67, 0x6b,
+ 0x6f, 0x73, 0x78, 0x7c, 0x80, 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa4,
+ ]
+];
+const INDEO5_QSCALE8_INTER: [[u8; 24]; 5] = [
+ [
+ 0x0b, 0x11, 0x13, 0x14, 0x15, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x20, 0x22,
+ 0x23, 0x25, 0x28, 0x2a, 0x2e, 0x32, 0x35, 0x39, 0x3d, 0x41, 0x44, 0x4a,
+ ], [
+ 0x07, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35,
+ 0x3a, 0x3f, 0x44, 0x4a, 0x50, 0x56, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x7e,
+ ], [
+ 0x15, 0x25, 0x28, 0x2d, 0x30, 0x34, 0x3a, 0x3d, 0x42, 0x48, 0x4c, 0x51,
+ 0x56, 0x5b, 0x60, 0x65, 0x6b, 0x70, 0x76, 0x7c, 0x82, 0x88, 0x8f, 0x97,
+ ], [
+ 0x13, 0x1f, 0x20, 0x22, 0x25, 0x28, 0x2b, 0x2d, 0x30, 0x33, 0x36, 0x39,
+ 0x3c, 0x3f, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x62,
+ ], [
+ 0x3c, 0x52, 0x58, 0x5d, 0x63, 0x68, 0x68, 0x6d, 0x73, 0x78, 0x7c, 0x80,
+ 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa3, 0xa9, 0xad, 0xb1, 0xb5, 0xba
+ ]
+];
+const INDEO5_QSCALE4_INTRA: [u8; 24] = [
+ 0x01, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+];
+const INDEO5_QSCALE4_INTER: [u8; 24] = [
+ 0x0b, 0x0d, 0x0d, 0x0e, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23
+];
+
+pub fn get_decoder() -> Box<NADecoder> {
+ Box::new(Indeo5Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use crate::test::dec_video::test_file_decoding;
+ #[test]
+ fn test_indeo5() {
+ test_file_decoding("avi", "assets/IV5/sample.avi", /*None*/Some(2), true, false, None);
+// test_file_decoding("avi", "assets/IV5/W32mdl_1.avi", None/*Some(2)*/, true, false, Some("iv5"));
+//panic!("the end");
+ }
+}
diff --git a/nihav-indeo/src/codecs/intel263.rs b/nihav-indeo/src/codecs/intel263.rs
new file mode 100644
index 0000000..df9b852
--- /dev/null
+++ b/nihav-indeo/src/codecs/intel263.rs
@@ -0,0 +1,423 @@
+use std::rc::Rc;
+use std::cell::RefCell;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::codebook::*;
+use nihav_core::formats;
+use nihav_core::frame::*;
+use nihav_core::codecs::*;
+use nihav_core::codecs::h263::*;
+use nihav_core::codecs::h263::decoder::*;
+use nihav_core::codecs::h263::data::*;
+use nihav_core::codecs::h263::code::H263BlockDSP;
+
+#[allow(dead_code)]
+struct Tables {
+ intra_mcbpc_cb: Codebook<u8>,
+ inter_mcbpc_cb: Codebook<u8>,
+ cbpy_cb: Codebook<u8>,
+ rl_cb: Codebook<H263RLSym>,
+ aic_rl_cb: Codebook<H263RLSym>,
+ mv_cb: Codebook<u8>,
+}
+
+struct Intel263Decoder {
+ info: Rc<NACodecInfo>,
+ dec: H263BaseDecoder,
+ tables: Tables,
+ bdsp: H263BlockDSP,
+}
+
+struct Intel263BR<'a> {
+ br: BitReader<'a>,
+ tables: &'a Tables,
+ gob_no: usize,
+ mb_w: usize,
+ is_pb: bool,
+ is_ipb: 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,
+ is_ipb: false,
+ }
+ }
+
+ fn decode_block(&mut self, quant: u8, intra: bool, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
+ let 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<u8>) -> DecoderResult<i16> {
+ 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<u8>) -> DecoderResult<MV> {
+ let xval = decode_mv_component(br, mv_cb)?;
+ let yval = decode_mv_component(br, mv_cb)?;
+ Ok(MV::new(xval, yval))
+}
+
+fn decode_b_info(br: &mut BitReader, is_pb: bool, is_ipb: bool, is_intra: bool) -> DecoderResult<BBlockInfo> {
+ if is_pb { // as improved pb
+ if is_ipb {
+ let pb_mv_add = if is_intra { 1 } else { 0 };
+ if br.read_bool()?{
+ if br.read_bool()? {
+ let pb_mv_count = 1 - (br.read(1)? as usize);
+ let cbpb = br.read(6)? as u8;
+ Ok(BBlockInfo::new(true, cbpb, pb_mv_count + pb_mv_add, pb_mv_count == 1))
+ } else {
+ Ok(BBlockInfo::new(true, 0, 1 + pb_mv_add, true))
+ }
+ } else {
+ Ok(BBlockInfo::new(true, 0, pb_mv_add, false))
+ }
+ } else {
+ let mvdb = br.read_bool()?;
+ let cbpb = if mvdb && br.read_bool()? { br.read(6)? as u8 } else { 0 };
+ Ok(BBlockInfo::new(true, cbpb, if mvdb { 1 } else { 0 }, false))
+ }
+ } else {
+ Ok(BBlockInfo::new(false, 0, 0, false))
+ }
+}
+
+impl<'a> BlockDecoder for Intel263BR<'a> {
+
+#[allow(unused_variables)]
+ fn decode_pichdr(&mut self) -> DecoderResult<PicInfo> {
+ let br = &mut self.br;
+ let syncw = br.read(22)?;
+ validate!(syncw == 0x000020);
+ let tr = (br.read(8)? << 8) as u16;
+ 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()?;
+ let deblock;
+ let pbplus;
+ if sfmt == 0b111 {
+ sfmt = br.read(3)?;
+ validate!((sfmt != 0b000) && (sfmt != 0b111));
+ br.read(2)?; // unknown flags
+ deblock = br.read_bool()?;
+ br.read(1)?; // unknown flag
+ pbplus = br.read_bool()?;
+ br.read(5)?; // unknown flags
+ let marker = br.read(5)?;
+ validate!(marker == 1);
+ } else {
+ deblock = false;
+ pbplus = false;
+ }
+ self.is_ipb = pbplus;
+ 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);
+
+ let pbinfo;
+ if self.is_pb {
+ let trb = br.read(3)?;
+ let dbquant = br.read(2)?;
+ pbinfo = Some(PBInfo::new(trb as u8, dbquant as u8, pbplus));
+ } else {
+ pbinfo = None;
+ }
+ 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 plusinfo = if deblock { Some(PlusInfo::new(false, deblock, false, false)) } else { None };
+ let mvmode = if umv { MVMode::UMV } else { MVMode::Old };
+ let picinfo = PicInfo::new(w, h, ftype, mvmode, umv, apm, quant as u8, tr, pbinfo, plusinfo);
+ Ok(picinfo)
+ }
+
+ #[allow(unused_variables)]
+ fn decode_slice_header(&mut self, info: &PicInfo) -> DecoderResult<SliceInfo> {
+ let br = &mut self.br;
+ let gbsc = br.read(17)?;
+ 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 = SliceInfo::new_gob(0, self.gob_no, gquant as u8);
+ self.gob_no += 1;
+ Ok(ret)
+ }
+
+ #[allow(unused_variables)]
+ fn decode_block_header(&mut self, info: &PicInfo, slice: &SliceInfo, sstate: &SliceState) -> DecoderResult<BlockInfo> {
+ let 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;
+ }
+ Ok(BlockInfo::new(Type::I, cbp, q))
+ },
+ Type::P => {
+ 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<MV> = Vec::new();
+ let bbinfo = decode_b_info(br, self.is_pb, self.is_ipb, true)?;
+ 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);
+ binfo.set_bpart(bbinfo);
+ if self.is_pb {
+ for _ in 0..bbinfo.get_num_mv() {
+ mvec.push(decode_mv(br, &self.tables.mv_cb)?);
+ }
+ binfo.set_b_mv(mvec.as_slice());
+ }
+ return Ok(binfo);
+ }
+
+ let bbinfo = decode_b_info(br, self.is_pb, self.is_ipb, false)?;
+ 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);
+ binfo.set_bpart(bbinfo);
+ if !is_4x4 {
+ let mvec: [MV; 1] = [decode_mv(br, &self.tables.mv_cb)?];
+ 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<MV> = Vec::with_capacity(bbinfo.get_num_mv());
+ for _ in 0..bbinfo.get_num_mv() {
+ let mv = decode_mv(br, &self.tables.mv_cb)?;
+ mvec.push(mv);
+ }
+ binfo.set_b_mv(mvec.as_slice());
+ }
+ Ok(binfo)
+ },
+ _ => { Err(DecoderError::InvalidData) },
+ }
+ }
+
+ #[allow(unused_variables)]
+ fn decode_block_intra(&mut self, info: &BlockInfo, sstate: &SliceState, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
+ self.decode_block(quant, true, coded, blk)
+ }
+
+ #[allow(unused_variables)]
+ fn decode_block_inter(&mut self, info: &BlockInfo, sstate: &SliceState, quant: u8, no: usize, coded: bool, blk: &mut [i16; 64]) -> DecoderResult<()> {
+ self.decode_block(quant, false, coded, blk)
+ }
+
+ 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: H263BaseDecoder::new(true),
+ tables: tables,
+ bdsp: H263BlockDSP::new(),
+ }
+ }
+}
+
+impl NADecoder for Intel263Decoder {
+ fn init(&mut self, info: Rc<NACodecInfo>) -> 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<NAFrameRef> {
+ let src = pkt.get_buffer();
+
+ if src.len() == 8 {
+ let bret = self.dec.get_bframe(&self.bdsp);
+ 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::B });
+ return Ok(Rc::new(RefCell::new(frm)));
+ }
+ let mut ibr = Intel263BR::new(&src, &self.tables);
+
+ let bufinfo = self.dec.parse_frame(&mut ibr, &self.bdsp)?;
+
+ 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<NADecoder> {
+ Box::new(Intel263Decoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use crate::test::dec_video::test_file_decoding;
+ #[test]
+ fn test_intel263() {
+ test_file_decoding("avi", "assets/neal73_saber.avi", Some(16), true, false, None/*Some("i263")*/);
+ }
+}
diff --git a/nihav-indeo/src/codecs/ivi.rs b/nihav-indeo/src/codecs/ivi.rs
new file mode 100644
index 0000000..064da0b
--- /dev/null
+++ b/nihav-indeo/src/codecs/ivi.rs
@@ -0,0 +1,287 @@
+use super::ivibr::{IVICodebook,IVI_CB_ZERO,RVMap,IVI_ZERO_RVMAP,IVI_RVMAPS};
+
+pub fn clip8(a: i16) -> u8 {
+ if a < 0 { 0 }
+ else if a > 255 { 255 }
+ else { a as u8 }
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum IVIFrameType {
+ Intra,
+ Inter,
+ Bidir,
+ Intra1,
+ InterDroppable,
+ InterScal,
+ NULL,
+ NULL2,
+}
+
+impl IVIFrameType {
+ pub fn is_intra(self) -> bool {
+ (self == IVIFrameType::Intra) || (self == IVIFrameType::Intra1)
+ }
+ pub fn is_null(self) -> bool {
+ (self == IVIFrameType::NULL) || (self == IVIFrameType::NULL2)
+ }
+ pub fn is_bidir(self) -> bool {
+ self == IVIFrameType::Bidir
+ }
+}
+
+#[derive(Clone,Copy)]
+pub struct PictureHeader {
+ pub ftype: IVIFrameType,
+ pub width: usize,
+ pub height: usize,
+ pub slice_w: usize,
+ pub slice_h: usize,
+ pub transparent: bool,
+ pub luma_bands: usize,
+ pub chroma_bands: usize,
+ pub in_q: bool,
+}
+
+impl PictureHeader {
+ pub fn new(ftype: IVIFrameType, width: usize, height: usize, slice_w: usize, slice_h: usize, transparent: bool, luma_bands: usize, chroma_bands: usize, in_q: bool) -> Self {
+ PictureHeader {
+ ftype: ftype,
+ width: width, height: height, slice_w: slice_w, slice_h: slice_h,
+ transparent: transparent,
+ luma_bands: luma_bands, chroma_bands: chroma_bands,
+ in_q: in_q,
+ }
+ }
+ pub fn new_null(ftype: IVIFrameType) -> Self {
+ PictureHeader {
+ ftype: ftype,
+ width: 0, height: 0, slice_w: 0, slice_h: 0,
+ transparent: false,
+ luma_bands: 0, chroma_bands: 0,
+ in_q: false,
+ }
+ }
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum TSize {
+ T8x8,
+ T4x4,
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum TDir {
+ TwoD,
+ Row,
+ Col,
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum IVITransformType {
+ Haar (TSize, TDir),
+ Slant(TSize, TDir),
+ DCT (TSize, TDir),
+ None (TSize),
+}
+
+pub type TrFunc = fn (&mut [i32; 64]);
+pub type TrFuncDC = fn (&mut [i32; 64], i32);
+
+impl IVITransformType {
+ pub fn is_8x8(&self) -> bool {
+ match *self {
+ IVITransformType::Haar (ref sz, _) => { *sz == TSize::T8x8 },
+ IVITransformType::Slant(ref sz, _) => { *sz == TSize::T8x8 },
+ IVITransformType::DCT (ref sz, _) => { *sz == TSize::T8x8 },
+ IVITransformType::None (ref sz) => { *sz == TSize::T8x8 },
+ }
+ }
+ pub fn is_2d(&self) -> bool {
+ match *self {
+ IVITransformType::Haar (_, ref dir) => { *dir == TDir::TwoD },
+ IVITransformType::Slant(_, ref dir) => { *dir == TDir::TwoD },
+ IVITransformType::DCT (_, ref dir) => { *dir == TDir::TwoD },
+ _ => { false },
+ }
+ }
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct TxParams4x4 {
+ pub quant_intra: &'static [u16; 16],
+ pub quant_inter: &'static [u16; 16],
+ pub scan: &'static [usize; 16],
+}
+
+impl TxParams4x4 {
+ pub fn new(quant_intra: &'static [u16; 16], quant_inter: &'static [u16; 16], scan: &'static [usize; 16]) -> Self {
+ TxParams4x4 {
+ quant_intra: quant_intra, quant_inter: quant_inter, scan: scan,
+ }
+ }
+}
+
+#[allow(dead_code)]
+#[derive(Clone)]
+pub struct TxParams8x8 {
+ pub quant_intra: &'static [u16; 64],
+ pub quant_inter: &'static [u16; 64],
+ pub scan: &'static [usize; 64],
+}
+
+impl TxParams8x8 {
+ pub fn new(quant_intra: &'static [u16; 64], quant_inter: &'static [u16; 64], scan: &'static [usize; 64]) -> Self {
+ TxParams8x8 {
+ quant_intra: quant_intra, quant_inter: quant_inter, scan: scan,
+ }
+ }
+}
+
+#[derive(Clone)]
+pub enum TxType {
+ Transform4(TxParams4x4),
+ Transform8(TxParams8x8),
+ None,
+}
+
+pub const CORR_MAP_SIZE: usize = 122;
+
+#[derive(Clone)]
+pub struct BandHeader {
+ pub plane_no: usize,
+ pub band_no: usize,
+ pub empty: bool,
+ pub mb_size: usize,
+ pub blk_size: usize,
+ pub halfpel: bool,
+ pub inherit_mv: bool,
+ pub has_qdelta: bool,
+ pub inherit_qd: bool,
+ pub quant: u32,
+ pub blk_cb: IVICodebook,
+ pub rvmap: RVMap,
+ pub tr: IVITransformType,
+ pub ttype: TxType,
+}
+
+impl BandHeader {
+ pub fn new(plane_no: usize, band_no: usize, mb_size: usize, blk_size: usize, halfpel: bool, inherit_mv: bool, has_qdelta: bool, inherit_qd: bool, quant: u32, rvmap_idx: usize, num_corr: usize, corr_map: [u8; CORR_MAP_SIZE], blk_cb: IVICodebook, tr: IVITransformType, ttype: TxType) -> Self {
+ let mut rvmap = IVI_RVMAPS[rvmap_idx].clone();
+ for i in 0..num_corr {
+ let pos1 = corr_map[i * 2 + 0] as usize;
+ let pos2 = corr_map[i * 2 + 1] as usize;
+ let t = rvmap.runtab[pos1];
+ rvmap.runtab[pos1] = rvmap.runtab[pos2];
+ rvmap.runtab[pos2] = t;
+ let t = rvmap.valtab[pos1];
+ rvmap.valtab[pos1] = rvmap.valtab[pos2];
+ rvmap.valtab[pos2] = t;
+ }
+ BandHeader {
+ plane_no: plane_no, band_no: band_no,
+ empty: false, halfpel: halfpel,
+ inherit_mv: inherit_mv,
+ has_qdelta: has_qdelta, inherit_qd: inherit_qd, quant: quant,
+ mb_size: mb_size, blk_size: blk_size,
+ rvmap: rvmap, blk_cb: blk_cb,
+ tr: tr, ttype: ttype,
+ }
+ }
+ pub fn new_empty(plane_no: usize, band_no: usize) -> Self {
+ BandHeader {
+ plane_no: plane_no, band_no: band_no,
+ empty: true, halfpel: true,
+ inherit_mv: false, has_qdelta: false, inherit_qd: false, quant: 0,
+ mb_size: 0, blk_size: 0,
+ rvmap: IVI_ZERO_RVMAP, blk_cb: IVI_CB_ZERO,
+ tr: IVITransformType::None(TSize::T8x8), ttype: TxType::None,
+ }
+ }
+}
+
+#[derive(Debug,Clone,Copy,PartialEq)]
+pub enum MBType {
+ Intra,
+ Inter,
+ Backward,
+ Bidir,
+}
+
+#[derive(Clone,Copy)]
+pub struct MB {
+ pub mtype: MBType,
+ pub pos_x: usize,
+ pub pos_y: usize,
+ pub mv_x: i32,
+ pub mv_y: i32,
+ pub mv2_x: i32,
+ pub mv2_y: i32,
+ pub qd: i16,
+ pub q: u8,
+ pub cbp: u8,
+}
+
+impl MB {
+ pub fn new(x: usize, y: usize) -> Self {
+ MB {
+ mtype: MBType::Intra,
+ pos_x: x, pos_y: y,
+ mv_x: 0, mv_y: 0,
+ mv2_x: 0, mv2_y: 0,
+ cbp: 0, q: 0, qd: 0,
+ }
+ }
+}
+
+pub struct IVITile {
+ pub pos_x: usize,
+ pub pos_y: usize,
+ pub mb_w: usize,
+ pub mb_h: usize,
+ pub w: usize,
+ pub h: usize,
+ pub mb: Vec<MB>,
+}
+
+impl IVITile {
+ pub fn new(pos_x: usize, pos_y: usize, w: usize, h: usize) -> Self {
+ IVITile {
+ pos_x: pos_x, pos_y: pos_y, w: w, h: h,
+ mb_w: 0, mb_h: 0, mb: Vec::new(),
+ }
+ }
+}
+
+pub const IVI_ZIGZAG: [usize; 64] = [
+ 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 IVI_SCAN_8X8_VER: [usize; 64] = [
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 1, 9, 17, 25, 33, 41, 49, 57,
+ 2, 10, 18, 26, 34, 42, 50, 58,
+ 3, 11, 19, 27, 35, 43, 51, 59,
+ 4, 12, 20, 28, 36, 44, 52, 60,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 7, 15, 23, 31, 39, 47, 55, 63
+];
+pub const IVI_SCAN_8X8_HOR: [usize; 64] = [
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ 56, 57, 58, 59, 60, 61, 62, 63
+];
+pub const IVI_SCAN_4X4: [usize; 16] = [ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 ];
diff --git a/nihav-indeo/src/codecs/ivibr.rs b/nihav-indeo/src/codecs/ivibr.rs
new file mode 100644
index 0000000..10581c8
--- /dev/null
+++ b/nihav-indeo/src/codecs/ivibr.rs
@@ -0,0 +1,1293 @@
+use std::mem;
+use std::rc::Rc;
+use std::cell::{Ref,RefCell};
+use nihav_core::io::bitreader::*;
+//use io::intcode::*;
+use nihav_core::codecs::*;
+use nihav_core::formats::*;
+use nihav_core::frame::*;
+use super::ivi::*;
+use super::ividsp::*;
+
+pub fn scale_mv(val: i32, scale: u8) -> i32 {
+ (val + (if val > 0 { 1 } else { 0 }) + (scale as i32) - 1) >> scale
+}
+
+#[derive(Clone,Copy)]
+pub struct IVICodebook {
+ len: usize,
+ bits: [u8; 16],
+ offs: [u32; 16],
+}
+
+impl IVICodebook {
+ pub fn init(&self) -> Self {
+ let mut cb = *self;
+ let mut base: u32 = 0;
+ for i in 0..cb.len {
+ cb.offs[i] = base;
+ base += 1 << cb.bits[i];
+ }
+ cb
+ }
+}
+
+pub const IVI_CB_ZERO: IVICodebook = IVICodebook { len: 0, bits: [0; 16], offs: [0; 16] };
+
+const IVI_REV0: [u32; 1] = [0];
+const IVI_REV1: [u32; 2] = [0, 1];
+const IVI_REV2: [u32; 4] = [0, 2, 1, 3];
+const IVI_REV3: [u32; 8] = [0, 4, 2, 6, 1, 5, 3, 7];
+const IVI_REV4: [u32; 16] = [ 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15];
+const IVI_REV5: [u32; 32] = [ 0, 16, 8, 24, 4, 20, 12, 28, 2, 18, 10, 26, 6, 22, 14, 30, 1, 17, 9, 25, 5, 21, 13, 29, 3, 19, 11, 27, 7, 23, 15, 31];
+const IVI_REV6: [u32; 64] = [ 0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60, 2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62, 1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61, 3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63];
+const IVI_REV7: [u32; 128] = [ 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124, 2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122, 6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126, 1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121, 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125, 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123, 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127];
+const IVI_REV8: [u32; 256] = [ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255];
+
+const IVI_REVS: [&[u32]; 9] = [ &IVI_REV0, &IVI_REV1, &IVI_REV2, &IVI_REV3, &IVI_REV4, &IVI_REV5, &IVI_REV6, &IVI_REV7, &IVI_REV8];
+
+pub trait IVICodebookReader {
+ fn read_ivi_codebook_desc(&mut self, mb_cb: bool, try_default: bool) -> DecoderResult<IVICodebook>;
+ fn read_ivi_cb(&mut self, cb: &IVICodebook) -> BitReaderResult<u32>;
+ fn read_ivi_cb_s(&mut self, cb: &IVICodebook) -> BitReaderResult<i32>;
+}
+
+impl<'a> IVICodebookReader for BitReader<'a> {
+ fn read_ivi_codebook_desc(&mut self, mb_cb: bool, desc_coded: bool) -> DecoderResult<IVICodebook> {
+ if !desc_coded {
+ if mb_cb {
+ Ok(IVI_MB_CB[7].init())
+ } else {
+ Ok(IVI_BLK_CB[7].init())
+ }
+ } else {
+ let idx = self.read(3)? as usize;
+ if idx != 7 {
+ if mb_cb {
+ Ok(IVI_MB_CB[idx].init())
+ } else {
+ Ok(IVI_BLK_CB[idx].init())
+ }
+ } else {
+ let mut cb = IVI_CB_ZERO;
+ cb.len = self.read(4)? as usize;
+ if cb.len == 0 { return Err(DecoderError::InvalidData); }
+ for i in 0..cb.len {
+ cb.bits[i] = self.read(4)? as u8;
+ }
+ Ok(cb.init())
+ }
+ }
+ }
+ #[inline(always)]
+ fn read_ivi_cb(&mut self, cb: &IVICodebook) -> BitReaderResult<u32> {
+/* let pfx = if cb.len == 1 { 0 } else { self.read_code(UintCodeType::LimitedUnary((cb.len - 1) as u32, 0))? as usize };
+ let nbits = cb.bits[pfx];
+ let mut base: u32 = 0;
+ for i in 0..pfx { base += 1 << cb.bits[i]; }
+ let rval = self.read(nbits)?;
+ let add = reverse_bits(rval, nbits);
+ Ok(base + add)*/
+ if cb.len > 1 {
+ let len = (!self.peek(16)).trailing_zeros() as usize;
+ let pfx;
+ if len >= cb.len - 1 {
+ pfx = cb.len - 1;
+ self.skip((cb.len - 1) as u32)?;
+ } else {
+ pfx = len;
+ self.skip((len + 1) as u32)?;
+ }
+ let nbits = cb.bits[pfx];
+ let base = cb.offs[pfx];
+ let rval = self.read(nbits)?;
+ let add = IVI_REVS[nbits as usize][rval as usize];
+ Ok(base + add)
+ } else {
+ let nbits = cb.bits[0];
+ return Ok(IVI_REVS[nbits as usize][self.read(nbits)? as usize]);
+ }
+ }
+ #[inline(always)]
+ fn read_ivi_cb_s(&mut self, cb: &IVICodebook) -> BitReaderResult<i32> {
+ let v = self.read_ivi_cb(cb)?;
+ if v == 0 {
+ Ok(0)
+ } else {
+ let sign = (v & 1) == 1;
+ let val = (v >> 1) as i32;
+ if sign {
+ Ok(val + 1)
+ } else {
+ Ok(-val)
+ }
+ }
+ }
+}
+
+pub const IVI_MB_CB: &[IVICodebook; 8] = &[
+ IVICodebook { len: 8, bits: [ 0, 4, 5, 4, 4, 4, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 12, bits: [ 0, 2, 2, 3, 3, 3, 3, 5, 3, 2, 2, 2, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 12, bits: [ 0, 2, 3, 4, 3, 3, 3, 3, 4, 3, 2, 2, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 12, bits: [ 0, 3, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 13, bits: [ 0, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 9, bits: [ 0, 4, 4, 4, 4, 3, 3, 3, 2, 0, 0, 0, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 10, bits: [ 0, 4, 4, 4, 4, 3, 3, 2, 2, 2, 0, 0, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 12, bits: [ 0, 4, 4, 4, 3, 3, 2, 3, 2, 2, 2, 2, 0, 0, 0, 0 ], offs: [0; 16] }
+];
+
+pub const IVI_BLK_CB: &[IVICodebook; 8] = &[
+ IVICodebook { len: 10, bits: [ 1, 2, 3, 4, 4, 7, 5, 5, 4, 1, 0, 0, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 11, bits: [ 2, 3, 4, 4, 4, 7, 5, 4, 3, 3, 2, 0, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 12, bits: [ 2, 4, 5, 5, 5, 5, 6, 4, 4, 3, 1, 1, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 13, bits: [ 3, 3, 4, 4, 5, 6, 6, 4, 4, 3, 2, 1, 1, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 11, bits: [ 3, 4, 4, 5, 5, 5, 6, 5, 4, 2, 2, 0, 0, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 13, bits: [ 3, 4, 5, 5, 5, 5, 6, 4, 3, 3, 2, 1, 1, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 13, bits: [ 3, 4, 5, 5, 5, 6, 5, 4, 3, 3, 2, 1, 1, 0, 0, 0 ], offs: [0; 16] },
+ IVICodebook { len: 9, bits: [ 3, 4, 4, 5, 5, 5, 6, 5, 5, 0, 0, 0, 0, 0, 0, 0 ], offs: [0; 16] }
+];
+
+#[allow(unused_variables)]
+fn read_trans_band_header(br: &mut BitReader, w: usize, h: usize, dst: &mut [i16], dstride: usize) -> DecoderResult<()> {
+ let color_plane = br.read(2)?;
+ let bit_depth = br.read(3)?;
+ let dirty_rects = br.read(8)? as usize;
+ for i in 0..dirty_rects {
+ let x = br.read(16)?;
+ let y = br.read(16)?;
+ let l = br.read(16)?;
+ let r = br.read(16)?;
+ }
+ let has_trans_color = br.read_bool()?;
+ if has_trans_color {
+ let r = br.read(8)?;
+ let g = br.read(8)?;
+ let b = br.read(8)?;
+ }
+
+ br.skip(1)?;
+
+ let mut cb = IVI_CB_ZERO;
+ cb.len = br.read(4)? as usize;
+ if cb.len == 0 { return Err(DecoderError::InvalidData); }
+ for i in 0..cb.len {
+ cb.bits[i] = br.read(4)? as u8;
+ }
+ br.align();
+
+let tile_start = br.tell();
+ let empty = br.read_bool()?;
+ if !empty {
+ br.read_bool()?;
+ let mut len = br.read(8)? as usize;
+ if len == 255 {
+ len = br.read(24)? as usize;
+ }
+ br.align();
+let tile_end = tile_start + len * 8;
+
+ let first_val = br.read_bool()?;
+
+ let mut dec_size = 0;
+ let mut x = 0;
+ let mut y = 0;
+ let mut fill = if !first_val { 255-128 } else { 0-128 };
+ let tr_w = (w + 31) & !31;
+ while br.tell() < tile_end {
+ let code = br.read_ivi_cb(&cb)? as usize;
+ if code == 0 {
+ dec_size += 255;
+ for _ in 0..255 {
+ if (x < w) && (y < h) {
+ dst[x + y * dstride] = fill;
+ }
+ x += 1;
+ if x == tr_w {
+ x = 0;
+ y += 1;
+ }
+ }
+ } else {
+ dec_size += code;
+ for _ in 0..code {
+ if (x < w) && (y < h) {
+ dst[x + y * dstride] = fill;
+ }
+ x += 1;
+ if x == tr_w {
+ x = 0;
+ y += 1;
+ }
+ }
+ fill = !fill;
+ }
+ }
+ br.align();
+ } else {
+ }
+
+ Ok(())
+}
+
+fn decode_block8x8(br: &mut BitReader, blk_cb: &IVICodebook, rvmap: &RVMap, tables: &TxParams8x8, is_intra: bool, is_2d: bool, prev_dc: &mut i32, quant: u8, coeffs: &mut [i32; 64], transform: &TrFunc) -> DecoderResult<()> {
+ let mut idx: isize = -1;
+ let quant_mat = if is_intra { tables.quant_intra } else { tables.quant_inter };
+ while idx <= 64 {
+ let c = br.read_ivi_cb(blk_cb)?;
+ if c == rvmap.eob_sym { break; }
+ let run;
+ let val: i32;
+ if c != rvmap.esc_sym {
+ validate!(c < 256);
+ run = rvmap.runtab[c as usize] as isize;
+ val = rvmap.valtab[c as usize] as i32;
+ } else {
+ run = (br.read_ivi_cb(blk_cb)? as isize) + 1;
+ let lo = br.read_ivi_cb(blk_cb)?;
+ let hi = br.read_ivi_cb(blk_cb)?;
+ let v = (hi << 6) + lo;
+ if v == 0 {
+ val = 0; // should not happen but still...
+ } else {
+ let vv = (v >> 1) as i32;
+ if (v & 1) != 0 {
+ val = vv + 1;
+ } else {
+ val = -vv;
+ }
+ }
+ }
+ idx += run;
+ validate!((idx >= 0) && (idx < 64));
+
+ let spos = tables.scan[idx as usize];
+ let q = ((quant_mat[spos] as u32) * (quant as u32)) >> 9;
+ if q > 1 {
+ let qq = q as i32;
+ let bias = (((q ^ 1) - 1) >> 1) as i32;
+ coeffs[spos] = val * qq;
+ if val > 0 { coeffs[spos] += bias; }
+ else { coeffs[spos] -= bias; }
+ } else {
+ coeffs[spos] = val;
+ }
+ }
+ if is_intra && is_2d {
+ *prev_dc += coeffs[0];
+ coeffs[0] = *prev_dc;
+ }
+ (transform)(coeffs);
+ Ok(())
+}
+fn decode_block4x4(br: &mut BitReader, blk_cb: &IVICodebook, rvmap: &RVMap, tables: &TxParams4x4, is_intra: bool, is_2d: bool, prev_dc: &mut i32, quant: u8, coeffs: &mut [i32; 64], transform: &TrFunc) -> DecoderResult<()> {
+ let mut idx: isize = -1;
+ let quant_mat = if is_intra { tables.quant_intra } else { tables.quant_inter };
+ while idx <= 64 {
+ let c = br.read_ivi_cb(blk_cb)?;
+ if c == rvmap.eob_sym { break; }
+ let run;
+ let val: i32;
+ if c != rvmap.esc_sym {
+ validate!(c < 256);
+ run = rvmap.runtab[c as usize] as isize;
+ val = rvmap.valtab[c as usize] as i32;
+ } else {
+ run = (br.read_ivi_cb(blk_cb)? as isize) + 1;
+ let lo = br.read_ivi_cb(blk_cb)?;
+ let hi = br.read_ivi_cb(blk_cb)?;
+ let v = (hi << 6) + lo;
+ if v == 0 {
+ val = 0; // should not happen but still...
+ } else {
+ if (v & 1) != 0 {
+ val = ((v >> 1) as i32) + 1;
+ } else {
+ val = -((v >> 1) as i32);
+ }
+ }
+ }
+ idx += run;
+ validate!((idx >= 0) && (idx < 16));
+
+ let spos = tables.scan[idx as usize];
+ let q = ((quant_mat[spos] as u32) * (quant as u32)) >> 9;
+ if q > 1 {
+ let qq = q as i32;
+ let bias = (((q ^ 1) - 1) >> 1) as i32;
+ coeffs[spos] = val * qq;
+ if val > 0 { coeffs[spos] += bias; }
+ else { coeffs[spos] -= bias; }
+ } else {
+ coeffs[spos] = val;
+ }
+ }
+ if is_intra && is_2d {
+ *prev_dc += coeffs[0];
+ coeffs[0] = *prev_dc;
+ }
+ (transform)(coeffs);
+ Ok(())
+}
+
+fn put_block(frame: &mut [i16], offs: usize, stride: usize, blk: &[i32], blk_size: usize) {
+ unsafe {
+ let mut dptr = frame.as_mut_ptr().offset(offs as isize);
+ for y in 0..blk_size {
+ for x in 0..blk_size {
+ *dptr.offset(x as isize) = blk[x + y * blk_size] as i16;
+ }
+ dptr = dptr.offset(stride as isize);
+ }
+ }
+}
+
+fn add_block(frame: &mut [i16], offs: usize, stride: usize, blk: &[i32], blk_size: usize) {
+ unsafe {
+ let mut dptr = frame.as_mut_ptr().offset(offs as isize);
+ for y in 0..blk_size {
+ for x in 0..blk_size {
+ *dptr.offset(x as isize) = (*dptr.offset(x as isize)).wrapping_add(blk[x + y * blk_size] as i16);
+ }
+ dptr = dptr.offset(stride as isize);
+ }
+ }
+}
+
+struct FrameData {
+ plane_buf: [Vec<i16>; 4],
+ plane_stride: [usize; 4],
+ pic_hdr: PictureHeader,
+}
+
+fn align(val: usize, bits: u8) -> usize {
+ let mask = (1 << bits) - 1;
+ (val + mask) & !mask
+}
+
+impl FrameData {
+ fn new() -> Rc<RefCell<Self>> {
+ Rc::new(RefCell::new(FrameData {
+ plane_buf: [Vec::new(), Vec::new(), Vec::new(), Vec::new()],
+ plane_stride: [0, 0, 0, 0],
+ pic_hdr: PictureHeader::new_null(IVIFrameType::Intra),
+ }))
+ }
+ fn realloc(&mut self, pic_hdr: &PictureHeader) -> DecoderResult<()> {
+ let width = align(pic_hdr.width, 6);
+ let height = align(pic_hdr.height, 6);
+
+ let stride = width;
+ self.plane_buf[0].resize(stride * height, 0);
+ self.plane_stride[0] = stride;
+ for plane in 1..3 {
+ self.plane_buf[plane].resize((stride >> 1) * (height >> 1), 0);
+ self.plane_stride[plane] = stride >> 1;
+ }
+ if pic_hdr.transparent {
+ self.plane_buf[3].resize(stride * height, 0);
+ self.plane_stride[3] = stride;
+ }
+ self.pic_hdr = *pic_hdr;
+ Ok(())
+ }
+ fn fill_plane(&mut self, vb: &mut NAVideoBuffer<u8>, plane: usize) {
+ let (w, h) = vb.get_dimensions(plane);
+ let mut didx = vb.get_offset(plane);
+ let dstride = vb.get_stride(plane);
+ let mut dst = vb.get_data_mut();
+ let src = &self.plane_buf[plane];
+ let mut sidx = 0;
+ let sstride = self.plane_stride[plane];
+ for _ in 0..h {
+ for x in 0..w {
+ dst[didx + x] = clip8(src[sidx + x] + 128);
+ }
+ didx += dstride;
+ sidx += sstride;
+ }
+ }
+}
+
+fn do_mc(dst: &mut [i16], dstride: usize, src: &[i16], sstride: usize, x: usize, y: usize, l: usize, r: usize, t: usize, b: usize, mv_x: i32, mv_y: i32, is_hpel: bool, blk_size: usize) {
+ let (xoff, yoff, mv_mode) = if is_hpel {
+ (mv_x >> 1, mv_y >> 1, ((mv_x & 1) + (mv_y & 1) * 2) as u8)
+ } else{
+ (mv_x, mv_y, 0)
+ };
+ let xpos = (x as isize) + (xoff as isize);
+ let ypos = (y as isize) + (yoff as isize);
+ if (xpos < (l as isize)) || ((xpos as usize) + blk_size + ((mv_mode & 1) as usize) > r) ||
+ (ypos < (t as isize)) || ((ypos as usize) + blk_size + ((mv_mode >> 1) as usize) > b) {
+//println!(" copy from {},{} of {}-{},{}-{} {}x{}!", xpos, ypos, l,r,t,b,blk_size,blk_size);
+ return;
+ }
+ let sidx = (xpos as usize) + (ypos as usize) * sstride;
+ if blk_size == 8 {
+ ivi_mc_put(dst, dstride, &src[sidx..], sstride, mv_mode, 8, 8);
+ } else {
+ ivi_mc_put(dst, dstride, &src[sidx..], sstride, mv_mode, 4, 4);
+ }
+}
+
+fn do_mc_b(dst: &mut [i16], dstride: usize, src1: &[i16], sstride1: usize, src2: &[i16], sstride2: usize, x: usize, y: usize, l: usize, r: usize, t: usize, b: usize, mv_x: i32, mv_y: i32, mv2_x: i32, mv2_y: i32, is_hpel: bool, blk_size: usize) {
+ let (xoff1, yoff1, mv_mode1) = if is_hpel {
+ (mv_x >> 1, mv_y >> 1, ((mv_x & 1) + (mv_y & 1) * 2) as u8)
+ } else{
+ (mv_x, mv_y, 0)
+ };
+ let xpos1 = (x as isize) + (xoff1 as isize);
+ let ypos1 = (y as isize) + (yoff1 as isize);
+ if (xpos1 < (l as isize)) || ((xpos1 as usize) + blk_size + ((mv_mode1 & 1) as usize) > r) ||
+ (ypos1 < (t as isize)) || ((ypos1 as usize) + blk_size + ((mv_mode1 >> 1) as usize) > b) {
+ return;
+ }
+ let sidx1 = (xpos1 as usize) + (ypos1 as usize) * sstride1;
+ let (xoff2, yoff2, mv_mode2) = if is_hpel {
+ (mv2_x >> 1, mv2_y >> 1, ((mv2_x & 1) + (mv2_y & 1) * 2) as u8)
+ } else{
+ (mv2_x, mv2_y, 0)
+ };
+ let xpos2 = (x as isize) + (xoff2 as isize);
+ let ypos2 = (y as isize) + (yoff2 as isize);
+ if (xpos2 < (l as isize)) || ((xpos2 as usize) + blk_size + ((mv_mode2 & 1) as usize) > r) ||
+ (ypos2 < (t as isize)) || ((ypos2 as usize) + blk_size + ((mv_mode2 >> 1) as usize) > b) {
+ return;
+ }
+ let sidx2 = (xpos2 as usize) + (ypos2 as usize) * sstride2;
+ ivi_mc_avg(dst, dstride, &src1[sidx1..], sstride1, mv_mode1, &src2[sidx2..], sstride2, mv_mode2, blk_size, blk_size);
+}
+
+pub trait IndeoXParser {
+ fn decode_picture_header(&mut self, br: &mut BitReader) -> DecoderResult<PictureHeader>;
+ fn decode_band_header(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, plane: usize, band: usize) -> DecoderResult<BandHeader>;
+ fn decode_mb_info(&mut self, br: &mut BitReader, pic_hdr: &PictureHeader, band_hdr: &BandHeader, tile: &mut IVITile, ref_tile: Option<Ref<IVITile>>, mv_scale: u8) -> DecoderResult<()>;
+ fn recombine_plane(&mut self, src: &[i16], sstride: usize, dst: &mut [u8], dstride: usize, w: usize, h: usize);
+}
+
+const MISSING_REF: usize = 42;
+
+pub struct IVIDecoder {
+ ftype: IVIFrameType,
+ frames: [Rc<RefCell<FrameData>>; 4],
+ cur_frame: usize,
+ prev_frame: usize,
+ next_frame: usize,
+ iref_0: usize,
+ iref_1: usize,
+ scal_ref: usize,
+ vinfo: NAVideoInfo,
+ vinfoa: NAVideoInfo,
+ bref: Option<NABufferType>,
+
+ bands: Vec<BandHeader>,
+ tiles: Vec<Rc<RefCell<IVITile>>>,
+ num_tiles: [[usize; 4]; 4],
+ tile_start: [[usize; 4]; 4],
+}
+
+impl IVIDecoder {
+ pub fn new() -> Self {
+ let mut bands: Vec<BandHeader> = Vec::with_capacity(12);
+ bands.resize(12, BandHeader::new_empty(42, 42));
+ IVIDecoder {
+ ftype: IVIFrameType::NULL,
+ frames: [FrameData::new(), FrameData::new(), FrameData::new(), FrameData::new()],
+ cur_frame: 0, prev_frame: MISSING_REF, next_frame: MISSING_REF,
+ iref_0: MISSING_REF, iref_1: MISSING_REF, scal_ref: MISSING_REF,
+ vinfo: NAVideoInfo::new(0, 0, false, YUV410_FORMAT),
+ vinfoa: NAVideoInfo::new(0, 0, false, YUVA410_FORMAT),
+ bref: None,
+
+ bands: bands,
+ tiles: Vec::new(), tile_start: [[0; 4]; 4], num_tiles: [[0; 4]; 4],
+ }
+ }
+
+ fn realloc(&mut self, pic_hdr: &PictureHeader) -> DecoderResult<()> {
+ let planes = if pic_hdr.transparent { 4 } else { 3 };
+
+ //self.bands.truncate(0);
+ self.tiles.truncate(0);
+ self.num_tiles = [[0; 4]; 4];
+ self.tile_start = [[0; 4]; 4];
+ let mut tstart: usize = 0;
+ for plane in 0..planes {
+ let is_luma = (plane != 1) && (plane != 2);
+ let bands = if is_luma { pic_hdr.luma_bands } else { pic_hdr.chroma_bands };
+ let mut band_w = if is_luma { pic_hdr.width } else { (pic_hdr.width + 3) >> 2 };
+ let mut band_h = if is_luma { pic_hdr.height } else { (pic_hdr.height + 3) >> 2 };
+ let mut tile_w = if is_luma { pic_hdr.slice_w } else { (pic_hdr.slice_w + 3) >> 2 };
+ let mut tile_h = if is_luma { pic_hdr.slice_h } else { (pic_hdr.slice_h + 3) >> 2 };
+ if bands > 1 {
+ band_w = (band_w + 1) >> 1;
+ band_h = (band_h + 1) >> 1;
+ if plane == 0 {
+ tile_w = (tile_w + 1) >> 1;
+ tile_h = (tile_h + 1) >> 1;
+ }
+ }
+ for band in 0..bands {
+ self.tile_start[plane][band] = tstart;
+ let band_xoff = if (band & 1) == 1 { band_w } else { 0 };
+ let band_yoff = if (band & 2) == 2 { band_h } else { 0 };
+ let mut y = 0;
+ while y < band_h {
+ let cur_h = if y + tile_h <= band_h { tile_h } else { band_h - y };
+ let mut x = 0;
+ while x < band_w {
+ let cur_w = if x + tile_w <= band_w { tile_w } else { band_w - x };
+ let tile = IVITile::new(band_xoff + x, band_yoff + y, cur_w, cur_h);
+ self.tiles.push(Rc::new(RefCell::new(tile)));
+ self.num_tiles[plane][band] += 1;
+ tstart += 1;
+ x += tile_w;
+ }
+ y += tile_h;
+ }
+ }
+ }
+ Ok(())
+ }
+ fn decode_band(&mut self, pic_hdr: &PictureHeader, dec: &mut IndeoXParser, br: &mut BitReader, plane_no: usize, band_no: usize) -> DecoderResult<()> {
+ let bidx = match plane_no {
+ 0 => { band_no },
+ _ => { pic_hdr.luma_bands + plane_no - 1 },
+ };
+ let prev_band = if bidx >= self.bands.len() { BandHeader::new_empty(plane_no, band_no) } else { self.bands[bidx].clone() };
+ let mut band = dec.decode_band_header(br, pic_hdr, plane_no, band_no)?;
+ if let TxType::None = band.ttype {
+ validate!(band.plane_no == prev_band.plane_no);
+ validate!(band.band_no == prev_band.band_no);
+ validate!(band.blk_size == prev_band.blk_size);
+ band.tr = prev_band.tr;
+ band.ttype = prev_band.ttype;
+ };
+
+ let tstart = self.tile_start[band.plane_no][band.band_no];
+ let tend = tstart + self.num_tiles[band.plane_no][band.band_no];
+ let mb_size = band.mb_size;
+ let (tr, tr_dc) = match band.ttype {
+ TxType::Transform4(_) => { ivi_get_transform4x4_funcs(band.tr) },
+ TxType::Transform8(_) => { ivi_get_transform8x8_funcs(band.tr) },
+ _ => { ivi_get_transform4x4_funcs(band.tr) },
+ };
+ for tile_no in tstart..tend {
+ {
+ let mut tile = self.tiles[tile_no].borrow_mut();
+ let mb_w = (tile.w + mb_size - 1) / mb_size;
+ let mb_h = (tile.h + mb_size - 1) / mb_size;
+ tile.mb_w = mb_w;
+ tile.mb_h = mb_h;
+ tile.mb.truncate(0);
+ tile.mb.resize(mb_w * mb_h, MB::new(0, 0));
+ }
+
+ let tile_start = br.tell();
+ if !br.read_bool()? {
+ let res = br.read_bool()?;
+ validate!(res);
+ let mut len = br.read(8)? as usize;
+ if len == 255 {
+ len = br.read(24)? as usize;
+ }
+ br.align();
+ validate!(len > 0);
+ let tile_end = tile_start + len * 8;
+ validate!(tile_end > br.tell());
+ validate!(tile_end <= br.tell() + (br.left() as usize));
+ {
+ let mut tile = self.tiles[tile_no].borrow_mut();
+ let ref_tile: Option<Ref<IVITile>>;
+ let mv_scale;
+ if (plane_no == 0) && (band_no == 0) {
+ mv_scale = 0;
+ } else {
+ mv_scale = (((self.bands[0].mb_size >> 3) as i8) - ((band.mb_size >> 3) as i8)) as u8;
+ }
+ if plane_no != 0 || band_no != 0 {
+ let rtile = self.tiles[0].borrow();
+ if (tile.mb_w != rtile.mb_w) || (tile.mb_h != rtile.mb_h) {
+ ref_tile = None;
+ } else {
+ ref_tile = Some(rtile);
+ }
+ } else {
+ ref_tile = None;
+ }
+ dec.decode_mb_info(br, pic_hdr, &band, &mut tile, ref_tile, mv_scale)?;
+ }
+
+ self.decode_tile(br, &band, tile_no, &tr, &tr_dc)?;
+let skip_part = tile_end - br.tell();
+br.skip(skip_part as u32)?;
+ } else {
+ {
+ let mut tile = self.tiles[tile_no].borrow_mut();
+ let ref_tile: Option<Ref<IVITile>>;
+ let mv_scale;
+ if (plane_no == 0) && (band_no == 0) {
+ mv_scale = 0;
+ } else {
+ mv_scale = (((self.bands[0].mb_size >> 3) as i8) - ((band.mb_size >> 3) as i8)) as u8;
+ }
+ if plane_no != 0 || band_no != 0 {
+ let rtile = self.tiles[0].borrow();
+ if (tile.mb_w != rtile.mb_w) || (tile.mb_h != rtile.mb_h) {
+ ref_tile = None;
+ } else {
+ ref_tile = Some(rtile);
+ }
+ } else {
+ ref_tile = None;
+ }
+ let mut mb_idx = 0;
+ for mb_y in 0..tile.mb_h {
+ for mb_x in 0..tile.mb_w {
+ let mut mb = MB::new(tile.pos_x + mb_x * band.mb_size, tile.pos_y + mb_y * band.mb_size);
+ mb.mtype = MBType::Inter;
+ mb.cbp = 0;
+ if band.inherit_mv {
+ if let Some(ref tileref) = ref_tile {
+ let mx = tileref.mb[mb_idx].mv_x;
+ let my = tileref.mb[mb_idx].mv_y;
+ mb.mv_x = scale_mv(mx, mv_scale);
+ mb.mv_y = scale_mv(my, mv_scale);
+ }
+ }
+ tile.mb[mb_idx] = mb;
+ mb_idx += 1;
+ }
+ }
+ }
+ self.decode_tile(br, &band, tile_no, &tr, &tr_dc)?;
+ }
+ }
+ self.bands[bidx] = band;
+ br.align();
+ Ok(())
+ }
+ fn decode_tile(&mut self, br: &mut BitReader, band: &BandHeader, tile_no: usize, tr: &TrFunc, transform_dc: &TrFuncDC) -> DecoderResult<()> {
+ let mut mb_idx = 0;
+ let mut prev_dc: i32 = 0;
+ let mut tile = self.tiles[tile_no].borrow_mut();
+ let mut frame = self.frames[self.cur_frame].borrow_mut();
+
+ let stride = frame.plane_stride[band.plane_no];
+ let mut dstidx = tile.pos_x + tile.pos_y * stride;
+ let mut dst = &mut frame.plane_buf[band.plane_no];
+ let pos_x = tile.pos_x;
+ let pos_y = tile.pos_y;
+ let tile_w = (tile.w + 15) & !15;
+ let tile_h = (tile.h + 15) & !15;
+ for mb_y in 0..tile.mb_h {
+ for mb_x in 0..tile.mb_w {
+ let mb = &mut tile.mb[mb_idx];
+
+ let is_intra = mb.mtype == MBType::Intra;
+
+ if band.mb_size != band.blk_size {
+ let mut cbp = mb.cbp;
+ for blk_no in 0..4 {
+ let mut blk: [i32; 64] = [0; 64];
+ let boff = (blk_no & 1) * 8 + (blk_no & 2) * 4 * stride + mb_x * 16;
+ if !is_intra {
+ if mb.mtype != MBType::Bidir {
+ let idx;
+ if mb.mtype != MBType::Backward {
+ idx = self.prev_frame;
+ } else {
+ idx = self.next_frame;
+ }
+ let pf = self.frames[idx].borrow();
+ do_mc(&mut dst[dstidx + boff..], stride,
+ &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+ pos_x + mb_x * 16 + (blk_no & 1) * 8,
+ pos_y + mb_y * 16 + (blk_no & 2) * 4,
+ pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+ mb.mv_x, mb.mv_y, band.halfpel, 8);
+ } else {
+ let pf = self.frames[self.prev_frame].borrow();
+ let nf = self.frames[self.next_frame].borrow();
+ do_mc_b(&mut dst[dstidx + boff..], stride,
+ &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+ &nf.plane_buf[band.plane_no], nf.plane_stride[band.plane_no],
+ pos_x + mb_x * 16 + (blk_no & 1) * 8,
+ pos_y + mb_y * 16 + (blk_no & 2) * 4,
+ pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+ mb.mv_x, mb.mv_y, mb.mv2_x, mb.mv2_y, band.halfpel,
+ band.blk_size);
+ }
+ }
+ if (cbp & 1) != 0 {
+ if let TxType::Transform8(ref params) = band.ttype {
+ decode_block8x8(br, &band.blk_cb, &band.rvmap, params, is_intra, band.tr.is_2d(), &mut prev_dc, mb.q, &mut blk, tr)?;
+ if is_intra {
+ put_block(&mut dst, dstidx + boff, stride, &blk, 8);
+ } else {
+ add_block(&mut dst, dstidx + boff, stride, &blk, 8);
+ }
+ }
+ } else {
+ if is_intra {
+ (transform_dc)(&mut blk, prev_dc);
+ put_block(&mut dst, dstidx + boff, stride, &blk, 8);
+ }
+ }
+ cbp >>= 1;
+ }
+ } else {
+ let mut blk: [i32; 64] = [0; 64];
+ if !is_intra {
+ if mb.mtype != MBType::Bidir {
+ let idx;
+ if mb.mtype != MBType::Backward {
+ idx = self.prev_frame;
+ } else {
+ idx = self.next_frame;
+ }
+ let pf = self.frames[idx].borrow();
+ do_mc(&mut dst[dstidx + mb_x * band.blk_size..], stride,
+ &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+ pos_x + mb_x * band.mb_size,
+ pos_y + mb_y * band.mb_size,
+ pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+ mb.mv_x, mb.mv_y, band.halfpel, band.blk_size);
+ } else {
+ let pf = self.frames[self.prev_frame].borrow();
+ let nf = self.frames[self.next_frame].borrow();
+ do_mc_b(&mut dst[dstidx + mb_x * band.blk_size..], stride,
+ &pf.plane_buf[band.plane_no], pf.plane_stride[band.plane_no],
+ &nf.plane_buf[band.plane_no], nf.plane_stride[band.plane_no],
+ pos_x + mb_x * band.mb_size,
+ pos_y + mb_y * band.mb_size,
+ pos_x, pos_x + tile_w, pos_y, pos_y + tile_h,
+ mb.mv_x, mb.mv_y, mb.mv2_x, mb.mv2_y, band.halfpel,
+ band.blk_size);
+ }
+ }
+ if mb.cbp != 0 {
+ if let TxType::Transform8(ref params) = band.ttype {
+ decode_block8x8(br, &band.blk_cb, &band.rvmap, params, is_intra, band.tr.is_2d(), &mut prev_dc, mb.q, &mut blk, tr)?;
+ }
+ if let TxType::Transform4(ref params) = band.ttype {
+ decode_block4x4(br, &band.blk_cb, &band.rvmap, params, is_intra, band.tr.is_2d(), &mut prev_dc, mb.q, &mut blk, tr)?;
+ }
+ if is_intra {
+ if band.blk_size == 8 {
+ put_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, 8);
+ } else {
+ put_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, 4);
+ }
+ } else {
+ if band.blk_size == 8 {
+ add_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, 8);
+ } else {
+ add_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, 4);
+ }
+ }
+ } else {
+ if is_intra {
+ (transform_dc)(&mut blk, prev_dc);
+ if band.blk_size == 8 {
+ put_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, 8);
+ } else {
+ put_block(&mut dst, dstidx + mb_x * band.blk_size, stride, &blk, 4);
+ }
+ }
+ }
+ }
+ mb_idx += 1;
+ }
+ dstidx += stride * band.mb_size;
+ }
+ br.align();
+ Ok(())
+ }
+
+ fn find_unused_frame(&self) -> usize {
+ for fno in 0..4 {
+ if (fno != self.iref_0) && (fno != self.iref_1) && (fno != self.scal_ref) {
+ return fno;
+ }
+ }
+ unreachable!();
+ }
+
+ fn decode_single_frame<'a>(&mut self, dec: &mut IndeoXParser, br: &mut BitReader<'a>) -> DecoderResult<NABufferType> {
+ let pic_hdr = dec.decode_picture_header(br)?;
+ self.ftype = pic_hdr.ftype;
+ if pic_hdr.ftype.is_null() {
+ return Ok(NABufferType::None);
+ }
+
+ self.cur_frame = self.find_unused_frame();
+ match self.ftype {
+ IVIFrameType::Inter => {
+ self.prev_frame = self.iref_0;
+ if self.prev_frame == MISSING_REF {
+ return Err(DecoderError::MissingReference);
+ }
+ },
+ IVIFrameType::InterDroppable => {
+ self.prev_frame = self.scal_ref;
+ if self.prev_frame == MISSING_REF {
+ return Err(DecoderError::MissingReference);
+ }
+ },
+ IVIFrameType::InterScal => {
+ self.prev_frame = self.scal_ref;
+ if self.prev_frame == MISSING_REF {
+ return Err(DecoderError::MissingReference);
+ }
+ },
+ IVIFrameType::Bidir => {
+ self.prev_frame = self.iref_1;
+ self.next_frame = self.iref_0;
+ if (self.prev_frame == MISSING_REF) || (self.next_frame == MISSING_REF) {
+ return Err(DecoderError::MissingReference);
+ }
+ },
+ _ => {},
+ };
+
+ let mut vinfo;
+ if pic_hdr.transparent {
+ vinfo = self.vinfoa.clone();
+ } else {
+ vinfo = self.vinfo.clone();
+ }
+ vinfo.set_width(pic_hdr.width);
+ vinfo.set_height(pic_hdr.height);
+ let mut buftype = alloc_video_buffer(vinfo, 0)?;
+ self.realloc(&pic_hdr)?;
+ self.frames[self.cur_frame].borrow_mut().realloc(&pic_hdr)?;
+
+ for plane in 0..3 {
+ let num_bands = if plane == 0 { pic_hdr.luma_bands } else { pic_hdr.chroma_bands };
+ for band in 0..num_bands {
+ self.decode_band(&pic_hdr, dec, br, plane, band)?;
+ }
+ if let NABufferType::Video(ref mut vb) = buftype {
+ let mut frame = self.frames[self.cur_frame].borrow_mut();
+ if num_bands == 1 {
+ frame.fill_plane(vb, plane);
+ } else {
+ let (w, h) = vb.get_dimensions(plane);
+ let dstride = vb.get_stride(plane);
+ let off = vb.get_offset(plane);
+ let mut dst = vb.get_data_mut();
+ dec.recombine_plane(&frame.plane_buf[plane], frame.plane_stride[plane], &mut dst[off..], dstride, w, h);
+ }
+ }
+ }
+ if pic_hdr.transparent {
+ let mut frame = self.frames[self.cur_frame].borrow_mut();
+ let stride = frame.plane_stride[3];
+ read_trans_band_header(br, pic_hdr.width, pic_hdr.height, &mut frame.plane_buf[3], stride)?;
+ if let NABufferType::Video(ref mut vb) = buftype {
+ frame.fill_plane(vb, 3);
+ }
+ }
+
+ match self.ftype {
+ IVIFrameType::Intra | IVIFrameType::Inter => {
+ self.iref_1 = self.iref_0;
+ self.iref_0 = self.cur_frame;
+ self.scal_ref = self.cur_frame;
+ },
+ IVIFrameType::InterScal => {
+ self.scal_ref = self.cur_frame;
+ },
+ _ => {},
+ };
+
+ Ok(buftype)
+ }
+
+ pub fn decode_frame<'a>(&mut self, dec: &mut IndeoXParser, br: &mut BitReader<'a>) -> DecoderResult<NABufferType> {
+ let res = self.decode_single_frame(dec, br);
+ if res.is_err() { return res; }
+ if (self.ftype == IVIFrameType::Intra) && (br.left() > 16) {
+ loop {
+ if br.left() < 8 { break; }
+ if br.read(8)? == 0 { break; }
+ }
+ loop {
+ if br.left() < 8 { break; }
+ if br.peek(8) != 0 { break; }
+ br.skip(8)?;
+ }
+ if br.left() > 24 {
+ let seq = br.peek(21);
+ if seq == 0xBFFF8 {
+ let res2 = self.decode_single_frame(dec, br);
+ if res2.is_ok() {
+ self.bref = Some(res2.unwrap());
+ }
+ }
+ self.ftype = IVIFrameType::Intra;
+ }
+ }
+ if let Ok(NABufferType::None) = res {
+ if self.bref.is_some() {
+ let mut bref: Option<NABufferType> = None;
+ mem::swap(&mut bref, &mut self.bref);
+ self.ftype = IVIFrameType::Inter;
+ return Ok(bref.unwrap());
+ }
+ }
+ res
+ }
+
+ pub fn is_intra(&mut self) -> bool {
+ self.ftype.is_intra()
+ }
+ pub fn get_frame_type(&mut self) -> FrameType {
+ match self.ftype {
+ IVIFrameType::Intra => { FrameType::I },
+ IVIFrameType::Intra1 => { FrameType::I },
+ IVIFrameType::Inter => { FrameType::P },
+ IVIFrameType::InterDroppable => { FrameType::P },
+ IVIFrameType::InterScal => { FrameType::P },
+ IVIFrameType::Bidir => { FrameType::B },
+ _ => { FrameType::Skip },
+ }
+ }
+}
+
+pub struct RVMap {
+ pub eob_sym: u32,
+ pub esc_sym: u32,
+ pub runtab: [u8; 256],
+ pub valtab: [i8; 256],
+}
+
+impl Clone for RVMap {
+ fn clone(&self) -> RVMap {
+ let mut runtab: [u8; 256] = [0; 256];
+ let mut valtab: [i8; 256] = [0; 256];
+ runtab.copy_from_slice(&self.runtab);
+ valtab.copy_from_slice(&self.valtab);
+ RVMap { eob_sym: self.eob_sym, esc_sym: self.esc_sym, runtab: runtab, valtab: valtab }
+ }
+}
+
+pub const IVI_ZERO_RVMAP: RVMap = RVMap { eob_sym: 0, esc_sym: 0, runtab: [0; 256], valtab: [0; 256] };
+
+pub static IVI_RVMAPS: [RVMap; 9] = [
+ RVMap { eob_sym: 5, esc_sym: 2, runtab: [
+ 1, 1, 0, 1, 1, 0, 1, 1, 2, 2, 1, 1, 1, 1, 3, 3,
+ 1, 1, 2, 2, 1, 1, 4, 4, 1, 1, 1, 1, 2, 2, 5, 5,
+ 1, 1, 3, 3, 1, 1, 6, 6, 1, 2, 1, 2, 7, 7, 1, 1,
+ 8, 8, 1, 1, 4, 2, 1, 4, 2, 1, 3, 3, 1, 1, 1, 9,
+ 9, 1, 2, 1, 2, 1, 5, 5, 1, 1, 10, 10, 1, 1, 3, 3,
+ 2, 2, 1, 1, 11, 11, 6, 4, 4, 1, 6, 1, 2, 1, 2, 12,
+ 8, 1, 12, 7, 8, 7, 1, 16, 1, 16, 1, 3, 3, 13, 1, 13,
+ 2, 2, 1, 15, 1, 5, 14, 15, 1, 5, 14, 1, 17, 8, 17, 8,
+ 1, 4, 4, 2, 2, 1, 25, 25, 24, 24, 1, 3, 1, 3, 1, 8,
+ 6, 7, 6, 1, 18, 8, 18, 1, 7, 23, 2, 2, 23, 1, 1, 21,
+ 22, 9, 9, 22, 19, 1, 21, 5, 19, 5, 1, 33, 20, 33, 20, 8,
+ 4, 4, 1, 32, 2, 2, 8, 3, 32, 26, 3, 1, 7, 7, 26, 6,
+ 1, 6, 1, 1, 16, 1, 10, 1, 10, 2, 16, 29, 28, 2, 29, 28,
+ 1, 27, 5, 8, 5, 27, 1, 8, 3, 7, 3, 31, 41, 31, 1, 41,
+ 6, 1, 6, 7, 4, 4, 1, 1, 2, 1, 2, 11, 34, 30, 11, 1,
+ 30, 15, 15, 34, 36, 40, 36, 40, 35, 35, 37, 37, 39, 39, 38, 38 ],
+ valtab: [
+ 1, -1, 0, 2, -2, 0, 3, -3, 1, -1, 4, -4, 5, -5, 1, -1,
+ 6, -6, 2, -2, 7, -7, 1, -1, 8, -8, 9, -9, 3, -3, 1, -1,
+ 10, -10, 2, -2, 11, -11, 1, -1, 12, 4, -12, -4, 1, -1, 13, -13,
+ 1, -1, 14, -14, 2, 5, 15, -2, -5, -15, -3, 3, 16, -16, 17, 1,
+ -1, -17, 6, 18, -6, -18, 2, -2, 19, -19, 1, -1, 20, -20, 4, -4,
+ 7, -7, 21, -21, 1, -1, 2, 3, -3, 22, -2, -22, 8, 23, -8, 1,
+ 2, -23, -1, 2, -2, -2, 24, 1, -24, -1, 25, 5, -5, 1, -25, -1,
+ 9, -9, 26, 1, -26, 3, 1, -1, 27, -3, -1, -27, 1, 3, -1, -3,
+ 28, -4, 4, 10, -10, -28, 1, -1, 1, -1, 29, 6, -29, -6, 30, -4,
+ 3, 3, -3, -30, 1, 4, -1, 31, -3, 1, 11, -11, -1, -31, 32, -1,
+ -1, 2, -2, 1, 1, -32, 1, 4, -1, -4, 33, -1, 1, 1, -1, 5,
+ 5, -5, -33, -1, -12, 12, -5, -7, 1, 1, 7, 34, 4, -4, -1, 4,
+ -34, -4, 35, 36, -2, -35, -2, -36, 2, 13, 2, -1, 1, -13, 1, -1,
+ 37, 1, -5, 6, 5, -1, 38, -6, -8, 5, 8, -1, 1, 1, -37, -1,
+ 5, 39, -5, -5, 6, -6, -38, -39, -14, 40, 14, 2, 1, 1, -2, -40,
+ -1, -2, 2, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1 ],
+ },
+ RVMap { eob_sym: 0, esc_sym: 38, runtab: [
+ 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8, 6, 8, 7,
+ 7, 9, 9, 10, 10, 11, 11, 1, 12, 1, 12, 13, 13, 16, 14, 16,
+ 14, 15, 15, 17, 17, 18, 0, 18, 19, 20, 21, 19, 22, 21, 20, 22,
+ 25, 24, 2, 25, 24, 23, 23, 2, 26, 28, 26, 28, 29, 27, 29, 27,
+ 33, 33, 1, 32, 1, 3, 32, 30, 36, 3, 36, 30, 31, 31, 35, 34,
+ 37, 41, 34, 35, 37, 4, 41, 4, 49, 8, 8, 49, 40, 38, 5, 38,
+ 40, 39, 5, 39, 42, 43, 42, 7, 57, 6, 43, 44, 6, 50, 7, 44,
+ 57, 48, 50, 48, 45, 45, 46, 47, 51, 46, 47, 58, 1, 51, 58, 1,
+ 52, 59, 53, 9, 52, 55, 55, 59, 53, 56, 54, 56, 54, 9, 64, 64,
+ 60, 63, 60, 63, 61, 62, 61, 62, 2, 10, 2, 10, 11, 1, 11, 13,
+ 12, 1, 12, 13, 16, 16, 8, 8, 14, 3, 3, 15, 14, 15, 4, 4,
+ 1, 17, 17, 5, 1, 7, 7, 5, 6, 1, 2, 2, 6, 22, 1, 25,
+ 21, 22, 8, 24, 1, 21, 25, 24, 8, 18, 18, 23, 9, 20, 23, 33,
+ 29, 33, 20, 1, 19, 1, 29, 36, 9, 36, 19, 41, 28, 57, 32, 3,
+ 28, 3, 1, 27, 49, 49, 1, 32, 26, 26, 2, 4, 4, 7, 57, 41,
+ 2, 7, 10, 5, 37, 16, 10, 27, 8, 8, 13, 16, 37, 13, 1, 5 ],
+ valtab: [
+ 0, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1,
+ -1, 1, -1, 1, -1, 1, -1, 2, 1, -2, -1, 1, -1, 1, 1, -1,
+ -1, 1, -1, 1, -1, 1, 0, -1, 1, 1, 1, -1, 1, -1, -1, -1,
+ 1, 1, 2, -1, -1, 1, -1, -2, 1, 1, -1, -1, 1, 1, -1, -1,
+ 1, -1, 3, 1, -3, 2, -1, 1, 1, -2, -1, -1, -1, 1, 1, 1,
+ 1, 1, -1, -1, -1, 2, -1, -2, 1, 2, -2, -1, 1, 1, 2, -1,
+ -1, 1, -2, -1, 1, 1, -1, 2, 1, 2, -1, 1, -2, -1, -2, -1,
+ -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 4, -1, -1, -4,
+ 1, 1, 1, 2, -1, -1, 1, -1, -1, 1, -1, -1, 1, -2, 1, -1,
+ 1, 1, -1, -1, 1, 1, -1, -1, 3, 2, -3, -2, 2, 5, -2, 2,
+ 2, -5, -2, -2, -2, 2, -3, 3, 2, 3, -3, 2, -2, -2, 3, -3,
+ 6, 2, -2, 3, -6, 3, -3, -3, 3, 7, -4, 4, -3, 2, -7, 2,
+ 2, -2, -4, 2, 8, -2, -2, -2, 4, 2, -2, 2, 3, 2, -2, -2,
+ 2, 2, -2, -8, -2, 9, -2, 2, -3, -2, 2, -2, 2, 2, 2, 4,
+ -2, -4, 10, 2, 2, -2, -9, -2, 2, -2, 5, 4, -4, 4, -2, 2,
+ -5, -4, -3, 4, 2, -3, 3, -2, -5, 5, 3, 3, -2, -3, -10, -4 ],
+ },
+ RVMap { eob_sym: 2, esc_sym: 11, runtab: [
+ 1, 1, 0, 2, 2, 1, 1, 3, 3, 4, 4, 0, 1, 1, 5, 5,
+ 2, 2, 6, 6, 7, 7, 1, 8, 1, 8, 3, 3, 9, 9, 1, 2,
+ 2, 1, 4, 10, 4, 10, 11, 11, 1, 5, 12, 12, 1, 5, 13, 13,
+ 3, 3, 6, 6, 2, 2, 14, 14, 16, 16, 15, 7, 15, 8, 8, 7,
+ 1, 1, 17, 17, 4, 4, 1, 1, 18, 18, 2, 2, 5, 5, 25, 3,
+ 9, 3, 25, 9, 19, 24, 19, 24, 1, 21, 20, 1, 21, 22, 20, 22,
+ 23, 23, 8, 6, 33, 6, 8, 33, 7, 7, 26, 26, 1, 32, 1, 32,
+ 28, 4, 28, 10, 29, 27, 27, 10, 41, 4, 29, 2, 2, 41, 36, 31,
+ 49, 31, 34, 30, 34, 36, 30, 35, 1, 49, 11, 5, 35, 11, 1, 3,
+ 3, 5, 37, 37, 8, 40, 8, 40, 12, 12, 42, 42, 1, 38, 16, 57,
+ 1, 6, 16, 39, 38, 6, 7, 7, 13, 13, 39, 43, 2, 43, 57, 2,
+ 50, 9, 44, 9, 50, 4, 15, 48, 44, 4, 1, 15, 48, 14, 14, 1,
+ 45, 45, 8, 3, 5, 8, 51, 47, 3, 46, 46, 47, 5, 51, 1, 17,
+ 17, 58, 1, 58, 2, 52, 52, 2, 53, 7, 59, 6, 6, 56, 53, 55,
+ 7, 55, 1, 54, 59, 56, 54, 10, 1, 10, 4, 60, 1, 60, 8, 4,
+ 8, 64, 64, 61, 1, 63, 3, 63, 62, 61, 5, 11, 5, 3, 11, 62 ],
+ valtab: [
+ 1, -1, 0, 1, -1, 2, -2, 1, -1, 1, -1, 0, 3, -3, 1, -1,
+ 2, -2, 1, -1, 1, -1, 4, 1, -4, -1, 2, -2, 1, -1, 5, 3,
+ -3, -5, 2, 1, -2, -1, 1, -1, 6, 2, 1, -1, -6, -2, 1, -1,
+ 3, -3, 2, -2, 4, -4, 1, -1, 1, -1, 1, 2, -1, 2, -2, -2,
+ 7, -7, 1, -1, 3, -3, 8, -8, 1, -1, 5, -5, 3, -3, 1, 4,
+ 2, -4, -1, -2, 1, 1, -1, -1, 9, 1, 1, -9, -1, 1, -1, -1,
+ 1, -1, 3, -3, 1, 3, -3, -1, 3, -3, 1, -1, 10, 1, -10, -1,
+ 1, 4, -1, 2, 1, -1, 1, -2, 1, -4, -1, 6, -6, -1, 1, 1,
+ 1, -1, 1, 1, -1, -1, -1, 1, 11, -1, -2, 4, -1, 2, -11, 5,
+ -5, -4, -1, 1, 4, 1, -4, -1, -2, 2, 1, -1, 12, 1, -2, 1,
+ -12, 4, 2, 1, -1, -4, 4, -4, 2, -2, -1, 1, 7, -1, -1, -7,
+ -1, -3, 1, 3, 1, 5, 2, 1, -1, -5, 13, -2, -1, 2, -2, -13,
+ 1, -1, 5, 6, 5, -5, 1, 1, -6, 1, -1, -1, -5, -1, 14, 2,
+ -2, 1, -14, -1, 8, 1, -1, -8, 1, 5, 1, 5, -5, 1, -1, 1,
+ -5, -1, 15, 1, -1, -1, -1, 3, -15, -3, 6, 1, 16, -1, 6, -6,
+ -6, 1, -1, 1, -16, 1, 7, -1, 1, -1, -6, -3, 6, -7, 3, -1 ]
+ },
+ RVMap { eob_sym: 0, esc_sym: 35, runtab: [
+ 0, 1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 5, 5, 6, 6, 7,
+ 7, 8, 8, 9, 9, 2, 2, 10, 10, 1, 1, 11, 11, 12, 12, 3,
+ 3, 13, 13, 0, 14, 14, 16, 15, 16, 15, 4, 4, 17, 1, 17, 1,
+ 5, 5, 18, 18, 2, 2, 6, 6, 8, 19, 7, 8, 7, 19, 20, 20,
+ 21, 21, 22, 24, 22, 24, 23, 23, 1, 1, 25, 25, 3, 3, 26, 26,
+ 9, 9, 27, 27, 28, 28, 33, 29, 4, 33, 29, 1, 4, 1, 32, 32,
+ 2, 2, 31, 10, 30, 10, 30, 31, 34, 34, 5, 5, 36, 36, 35, 41,
+ 35, 11, 41, 11, 37, 1, 8, 8, 37, 6, 1, 6, 40, 7, 7, 40,
+ 12, 38, 12, 39, 39, 38, 49, 13, 49, 13, 3, 42, 3, 42, 16, 16,
+ 43, 43, 14, 14, 1, 1, 44, 15, 44, 15, 2, 2, 57, 48, 50, 48,
+ 57, 50, 4, 45, 45, 4, 46, 47, 47, 46, 1, 51, 1, 17, 17, 51,
+ 8, 9, 9, 5, 58, 8, 58, 5, 52, 52, 55, 56, 53, 56, 55, 59,
+ 59, 53, 54, 1, 6, 54, 7, 7, 6, 1, 2, 3, 2, 3, 64, 60,
+ 60, 10, 10, 64, 61, 62, 61, 63, 1, 63, 62, 1, 18, 24, 18, 4,
+ 25, 4, 8, 21, 21, 1, 24, 22, 25, 22, 8, 11, 19, 11, 23, 1,
+ 20, 23, 19, 20, 5, 12, 5, 1, 16, 2, 12, 13, 2, 13, 1, 16 ],
+ valtab: [
+ 0, 1, -1, 1, -1, 1, -1, 1, -1, 2, -2, 1, -1, 1, -1, 1,
+ -1, 1, -1, 1, -1, 2, -2, 1, -1, 3, -3, 1, -1, 1, -1, 2,
+ -2, 1, -1, 0, 1, -1, 1, 1, -1, -1, 2, -2, 1, 4, -1, -4,
+ 2, -2, 1, -1, -3, 3, 2, -2, 2, 1, 2, -2, -2, -1, 1, -1,
+ 1, -1, 1, 1, -1, -1, 1, -1, 5, -5, 1, -1, 3, -3, 1, -1,
+ 2, -2, 1, -1, 1, -1, 1, 1, 3, -1, -1, 6, -3, -6, -1, 1,
+ 4, -4, 1, 2, 1, -2, -1, -1, 1, -1, 3, -3, 1, -1, 1, 1,
+ -1, 2, -1, -2, 1, 7, -3, 3, -1, 3, -7, -3, 1, -3, 3, -1,
+ 2, 1, -2, 1, -1, -1, 1, 2, -1, -2, -4, -1, 4, 1, 2, -2,
+ 1, -1, -2, 2, 8, -8, -1, 2, 1, -2, -5, 5, 1, -1, -1, 1,
+ -1, 1, 4, -1, 1, -4, -1, -1, 1, 1, 9, 1, -9, 2, -2, -1,
+ -4, 3, -3, -4, -1, 4, 1, 4, 1, -1, 1, -1, 1, 1, -1, 1,
+ -1, -1, -1, 10, 4, 1, 4, -4, -4, -10, 6, 5, -6, -5, 1, -1,
+ 1, 3, -3, -1, 1, -1, -1, -1, 11, 1, 1, -11, -2, -2, 2, 5,
+ -2, -5, -5, 2, -2, 12, 2, -2, 2, 2, 5, -3, -2, 3, -2, -12,
+ -2, 2, 2, 2, -5, 3, 5, 13, -3, 7, -3, -3, -7, 3, -13, 3 ]
+ },
+ RVMap { eob_sym: 0, esc_sym: 34, runtab: [
+ 0, 1, 1, 1, 2, 2, 1, 3, 3, 1, 1, 1, 4, 4, 1, 5,
+ 2, 1, 5, 2, 1, 1, 6, 6, 1, 1, 1, 1, 1, 7, 3, 1,
+ 2, 3, 0, 1, 2, 7, 1, 1, 1, 8, 1, 1, 8, 1, 1, 1,
+ 9, 1, 9, 1, 2, 1, 1, 2, 1, 1, 10, 4, 1, 10, 1, 4,
+ 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 1, 5, 1, 1, 1,
+ 2, 5, 1, 11, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 1, 6, 1, 6, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 12,
+ 3, 1, 12, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1,
+ 4, 1, 1, 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 5,
+ 1, 1, 1, 1, 1, 7, 1, 7, 1, 1, 2, 3, 1, 1, 1, 1,
+ 5, 1, 1, 1, 1, 1, 1, 2, 13, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 13, 2, 1, 1, 4, 1, 1, 1,
+ 3, 1, 6, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 6, 1, 1,
+ 1, 1, 15, 2, 4, 1, 2, 3, 15, 1, 1, 1, 8, 1, 1, 8,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1 ],
+ valtab: [
+ 0, 1, -1, 2, 1, -1, -2, 1, -1, 3, -3, 4, 1, -1, -4, 1,
+ 2, 5, -1, -2, -5, 6, 1, -1, -6, 7, -7, 8, -8, 1, 2, 9,
+ 3, -2, 0, -9, -3, -1, 10, -10, 11, 1, -11, 12, -1, -12, 13, -13,
+ 1, 14, -1, -14, 4, 15, -15, -4, 16, -16, 1, 2, 17, -1, -17, -2,
+ 18, -18, 19, -19, 20, 3, -20, 21, -21, -3, 5, 22, 2, -22, -23, 23,
+ -5, -2, 24, 1, -24, -1, 25, -25, 26, -26, -27, 27, 28, 29, -28, -29,
+ 6, 30, 2, -31, -2, -30, 31, -6, -32, 32, 33, -33, 34, -35, -34, 1,
+ 4, -36, -1, 35, 37, 36, 7, -37, 38, -4, -38, 39, 41, 40, -40, -39,
+ 3, 42, -43, -41, -7, -42, 43, -3, 44, -44, 45, -45, 46, 47, 8, -47,
+ -48, -46, 50, -50, 48, 49, 51, -49, 52, -52, 5, -51, -8, -53, 53, 3,
+ -56, 56, 55, 54, -54, 2, 60, -2, -55, 58, 9, -5, 59, 57, -57, -63,
+ -3, -58, -60, -61, 61, -59, -62, -9, 1, 64, 62, 69, -64, 63, 65, -67,
+ -68, 66, -65, 68, -66, -69, 67, -70, -1, 10, 71, -71, 4, 73, 72, 70,
+ 6, -76, -3, 74, -78, -74, 1, 78, 80, -72, -75, 76, -1, 3, -73, 79,
+ 75, 77, 1, 11, -4, -79, -10, -6, -1, -77, -83, -80, 2, 81, -84, -2,
+ 83, -81, 82, -82, 84, -87, -86, 85, -11, -85, 86, -89, 87, -88, 88, 89 ]
+ },
+ RVMap { eob_sym: 2, esc_sym: 33, runtab: [
+ 1, 1, 0, 2, 1, 2, 1, 3, 3, 1, 1, 4, 4, 2, 2, 1,
+ 1, 5, 5, 6, 1, 6, 1, 7, 7, 3, 3, 2, 8, 2, 8, 1,
+ 1, 0, 9, 9, 1, 1, 10, 4, 10, 4, 11, 11, 2, 1, 2, 1,
+ 12, 12, 3, 3, 1, 1, 13, 5, 5, 13, 14, 1, 1, 14, 2, 2,
+ 6, 6, 15, 1, 1, 15, 16, 4, 7, 16, 4, 7, 1, 1, 3, 3,
+ 8, 8, 2, 2, 1, 1, 17, 17, 1, 1, 18, 18, 5, 5, 2, 2,
+ 1, 1, 9, 19, 9, 19, 20, 3, 3, 20, 1, 10, 21, 1, 10, 4,
+ 4, 21, 22, 6, 6, 22, 1, 1, 23, 24, 2, 2, 23, 24, 11, 1,
+ 1, 11, 7, 25, 7, 1, 1, 25, 8, 8, 3, 26, 3, 1, 12, 2,
+ 2, 26, 1, 12, 5, 5, 27, 4, 1, 4, 1, 27, 28, 1, 28, 13,
+ 1, 13, 2, 29, 2, 1, 32, 6, 1, 30, 14, 29, 14, 6, 3, 31,
+ 3, 1, 30, 1, 32, 31, 33, 9, 33, 1, 1, 7, 9, 7, 2, 2,
+ 1, 1, 4, 36, 34, 4, 5, 10, 10, 5, 34, 1, 1, 35, 8, 8,
+ 36, 3, 35, 1, 15, 3, 2, 1, 16, 15, 16, 2, 37, 1, 37, 1,
+ 1, 1, 6, 6, 38, 1, 38, 11, 1, 39, 39, 40, 11, 2, 41, 4,
+ 40, 1, 2, 4, 1, 1, 1, 41, 3, 1, 3, 1, 5, 7, 5, 7 ],
+ valtab: [
+ 1, -1, 0, 1, 2, -1, -2, 1, -1, 3, -3, 1, -1, 2, -2, 4,
+ -4, 1, -1, 1, 5, -1, -5, 1, -1, 2, -2, 3, 1, -3, -1, 6,
+ -6, 0, 1, -1, 7, -7, 1, 2, -1, -2, 1, -1, 4, 8, -4, -8,
+ 1, -1, 3, -3, 9, -9, 1, 2, -2, -1, 1, 10, -10, -1, 5, -5,
+ 2, -2, 1, 11, -11, -1, 1, 3, 2, -1, -3, -2, 12, -12, 4, -4,
+ 2, -2, -6, 6, 13, -13, 1, -1, 14, -14, 1, -1, 3, -3, 7, -7,
+ 15, -15, 2, 1, -2, -1, 1, 5, -5, -1, -16, 2, 1, 16, -2, 4,
+ -4, -1, 1, 3, -3, -1, 17, -17, 1, 1, -8, 8, -1, -1, 2, 18,
+ -18, -2, 3, 1, -3, 19, -19, -1, 3, -3, 6, 1, -6, 20, 2, 9,
+ -9, -1, -20, -2, 4, -4, 1, -5, 21, 5, -21, -1, 1, -22, -1, 2,
+ 22, -2, 10, 1, -10, 23, 1, 4, -23, 1, 2, -1, -2, -4, -7, 1,
+ 7, -24, -1, 24, -1, -1, 1, 3, -1, -25, 25, 4, -3, -4, 11, -11,
+ 26, -26, 6, 1, 1, -6, -5, -3, 3, 5, -1, -27, 27, 1, 4, -4,
+ -1, -8, -1, 28, 2, 8, -12, -28, -2, -2, 2, 12, -1, 29, 1, -29,
+ 30, -30, 5, -5, 1, -31, -1, 3, 31, -1, 1, 1, -3, -13, 1, -7,
+ -1, -32, 13, 7, 32, 33, -33, -1, -9, -34, 9, 34, -6, 5, 6, -5 ]
+ },
+ RVMap { eob_sym: 2, esc_sym: 13, runtab: [
+ 1, 1, 0, 1, 1, 2, 2, 1, 1, 3, 3, 1, 1, 0, 2, 2,
+ 4, 1, 4, 1, 1, 1, 5, 5, 1, 1, 6, 6, 2, 2, 1, 1,
+ 3, 3, 7, 7, 1, 1, 8, 8, 1, 1, 2, 2, 1, 9, 1, 9,
+ 4, 4, 10, 1, 1, 10, 1, 1, 11, 11, 3, 3, 1, 2, 1, 2,
+ 1, 1, 12, 12, 5, 5, 1, 1, 13, 1, 1, 13, 2, 2, 1, 1,
+ 6, 6, 1, 1, 4, 14, 4, 14, 3, 1, 3, 1, 1, 1, 15, 7,
+ 15, 2, 2, 7, 1, 1, 1, 8, 1, 8, 16, 16, 1, 1, 1, 1,
+ 2, 1, 1, 2, 1, 1, 3, 5, 5, 3, 4, 1, 1, 4, 1, 1,
+ 17, 17, 9, 1, 1, 9, 2, 2, 1, 1, 10, 10, 1, 6, 1, 1,
+ 6, 18, 1, 1, 18, 1, 1, 1, 2, 2, 3, 1, 3, 1, 1, 1,
+ 4, 1, 19, 1, 19, 7, 1, 1, 20, 1, 4, 20, 1, 7, 11, 2,
+ 1, 11, 21, 2, 8, 5, 1, 8, 1, 5, 21, 1, 1, 1, 22, 1,
+ 1, 22, 1, 1, 3, 3, 1, 23, 2, 12, 24, 1, 1, 2, 1, 1,
+ 12, 23, 1, 1, 24, 1, 1, 1, 4, 1, 1, 1, 2, 1, 6, 6,
+ 4, 2, 1, 1, 1, 1, 1, 1, 1, 14, 13, 3, 1, 25, 9, 25,
+ 14, 1, 9, 3, 13, 1, 1, 1, 1, 1, 10, 1, 1, 2, 10, 2 ],
+ valtab: [
+ -20, -1, 0, 2, -2, 1, -1, 3, -3, 1, -1, 4, -4, 0, 2, -2,
+ 1, 5, -1, -5, 6, -6, 1, -1, 7, -7, 1, -1, 3, -3, 8, -8,
+ 2, -2, 1, -1, 9, -9, 1, -1, 10, -10, 4, -4, 11, 1, -11, -1,
+ 2, -2, 1, 12, -12, -1, 13, -13, 1, -1, 3, -3, 14, 5, -14, -5,
+ -15, 15, -1, 1, 2, -2, 16, -16, 1, 17, -17, -1, 6, -6, 18, -18,
+ 2, -2, -19, 19, -3, 1, 3, -1, 4, 20, -4, 1, -21, 21, 1, 2,
+ -1, -7, 7, -2, 22, -22, 23, 2, -23, -2, 1, -1, -24, 24, -25, 25,
+ -8, -26, 26, 8, -27, 27, 5, 3, -3, -5, -4, 28, -28, 4, 29, -29,
+ 1, -1, -2, -30, 30, 2, 9, -9, -31, 31, 2, -2, -32, 3, 32, -33,
+ -3, 1, 33, -34, -1, 34, -35, 35, -10, 10, -6, 36, 6, -36, 37, -37,
+ -5, 38, 1, -38, -1, 3, 39, -39, -1, 40, 5, 1, -40, -3, 2, -11,
+ -41, -2, 1, 11, -3, -4, 41, 3, 42, 4, -1, -43, -42, 43, 1, -44,
+ 45, -1, 44, -45, -7, 7, -46, 1, -12, 2, 1, -47, 46, 12, 47, 48,
+ -2, -1, -48, 49, -1, -50, -49, 50, -6, -51, 51, 52, -13, 53, -4, 4,
+ 6, 13, -53, -52, -54, 55, 54, -55, -56, -2, 2, -8, 56, 1, -3, -1,
+ 2, 58, 3, 8, -2, 57, -58, -60, -59, -57, -3, 60, 59, -14, 3, 14 ]
+ },
+ RVMap { eob_sym: 2, esc_sym: 38, runtab: [
+ 1, 1, 0, 2, 2, 1, 1, 3, 3, 4, 4, 5, 5, 1, 1, 6,
+ 6, 2, 2, 7, 7, 8, 8, 1, 1, 3, 3, 9, 9, 10, 10, 1,
+ 1, 2, 2, 4, 4, 11, 0, 11, 12, 12, 13, 13, 1, 1, 5, 5,
+ 14, 14, 15, 16, 15, 16, 3, 3, 1, 6, 1, 6, 2, 2, 7, 7,
+ 8, 8, 17, 17, 1, 1, 4, 4, 18, 18, 2, 2, 1, 19, 1, 20,
+ 19, 20, 21, 21, 3, 3, 22, 22, 5, 5, 24, 1, 1, 23, 9, 23,
+ 24, 9, 2, 2, 10, 1, 1, 10, 6, 6, 25, 4, 4, 25, 7, 7,
+ 26, 8, 1, 8, 3, 1, 26, 3, 11, 11, 27, 27, 2, 28, 1, 2,
+ 28, 1, 12, 12, 5, 5, 29, 13, 13, 29, 32, 1, 1, 33, 31, 30,
+ 32, 4, 30, 33, 4, 31, 3, 14, 1, 1, 3, 34, 34, 2, 2, 14,
+ 6, 6, 35, 36, 35, 36, 1, 15, 1, 16, 16, 15, 7, 9, 7, 9,
+ 37, 8, 8, 37, 1, 1, 39, 2, 38, 39, 2, 40, 5, 38, 40, 5,
+ 3, 3, 4, 4, 10, 10, 1, 1, 1, 1, 41, 2, 41, 2, 6, 6,
+ 1, 1, 11, 42, 11, 43, 3, 42, 3, 17, 4, 43, 1, 17, 7, 1,
+ 8, 44, 4, 7, 44, 5, 8, 2, 5, 1, 2, 48, 45, 1, 12, 45,
+ 12, 48, 13, 13, 1, 9, 9, 46, 1, 46, 47, 47, 49, 18, 18, 49 ],
+ valtab: [
+ 1, -1, 0, 1, -1, 2, -2, 1, -1, 1, -1, 1, -1, 3, -3, 1,
+ -1, -2, 2, 1, -1, 1, -1, 4, -4, -2, 2, 1, -1, 1, -1, 5,
+ -5, -3, 3, 2, -2, 1, 0, -1, 1, -1, 1, -1, 6, -6, 2, -2,
+ 1, -1, 1, 1, -1, -1, -3, 3, 7, 2, -7, -2, -4, 4, 2, -2,
+ 2, -2, 1, -1, 8, -8, 3, -3, 1, -1, -5, 5, 9, 1, -9, 1,
+ -1, -1, 1, -1, -4, 4, 1, -1, 3, -3, 1, -10, 10, 1, 2, -1,
+ -1, -2, 6, -6, 2, 11, -11, -2, 3, -3, 1, -4, 4, -1, 3, -3,
+ 1, 3, 12, -3, -5, -12, -1, 5, 2, -2, 1, -1, -7, 1, 13, 7,
+ -1, -13, 2, -2, 4, -4, 1, 2, -2, -1, 1, 14, -14, 1, 1, 1,
+ -1, -5, -1, -1, 5, -1, -6, 2, -15, 15, 6, 1, -1, -8, 8, -2,
+ -4, 4, 1, 1, -1, -1, 16, 2, -16, -2, 2, -2, 4, 3, -4, -3,
+ -1, -4, 4, 1, -17, 17, -1, -9, 1, 1, 9, 1, -5, -1, -1, 5,
+ -7, 7, 6, -6, 3, -3, 18, -18, 19, -19, 1, -10, -1, 10, -5, 5,
+ 20, -20, -3, 1, 3, 1, 8, -1, -8, 2, 7, -1, -21, -2, 5, 21,
+ 5, -1, -7, -5, 1, -6, -5, -11, 6, 22, 11, 1, 1, -22, -3, -1,
+ 3, -1, 3, -3, -23, 4, -4, 1, 23, -1, 1, -1, 1, -2, 2, -1 ]
+ },
+ RVMap { eob_sym: 4, esc_sym: 11, runtab: [
+ 1, 1, 1, 1, 0, 2, 2, 1, 1, 3, 3, 0, 1, 1, 2, 2,
+ 4, 4, 1, 1, 5, 5, 1, 1, 2, 2, 3, 3, 6, 6, 1, 1,
+ 7, 7, 8, 1, 8, 2, 2, 1, 4, 4, 1, 3, 1, 3, 9, 9,
+ 2, 2, 1, 5, 1, 5, 10, 10, 1, 1, 11, 11, 3, 6, 3, 4,
+ 4, 6, 2, 2, 1, 12, 1, 12, 7, 13, 7, 13, 1, 1, 8, 8,
+ 2, 2, 14, 14, 16, 15, 16, 5, 5, 1, 3, 15, 1, 3, 4, 4,
+ 1, 1, 17, 17, 2, 2, 6, 6, 1, 18, 1, 18, 22, 21, 22, 21,
+ 25, 24, 25, 19, 9, 20, 9, 23, 19, 24, 20, 3, 23, 7, 3, 1,
+ 1, 7, 28, 26, 29, 5, 28, 26, 5, 8, 29, 4, 8, 27, 2, 2,
+ 4, 27, 1, 1, 10, 36, 10, 33, 33, 36, 30, 1, 32, 32, 1, 30,
+ 6, 31, 31, 35, 3, 6, 11, 11, 3, 2, 35, 2, 34, 1, 34, 1,
+ 37, 37, 12, 7, 12, 5, 41, 5, 4, 7, 1, 8, 13, 4, 1, 41,
+ 13, 38, 8, 38, 9, 1, 40, 40, 9, 1, 39, 2, 2, 49, 39, 42,
+ 3, 3, 14, 16, 49, 14, 16, 42, 43, 43, 6, 6, 15, 1, 1, 15,
+ 44, 44, 1, 1, 50, 48, 4, 5, 4, 7, 5, 2, 10, 10, 48, 7,
+ 50, 45, 2, 1, 45, 8, 8, 1, 46, 46, 3, 47, 47, 3, 1, 1 ],
+ valtab: [
+ 1, -1, 2, -2, 0, 1, -1, 3, -3, 1, -1, 0, 4, -4, 2, -2,
+ 1, -1, 5, -5, 1, -1, 6, -6, 3, -3, 2, -2, 1, -1, 7, -7,
+ 1, -1, 1, 8, -1, 4, -4, -8, 2, -2, 9, 3, -9, -3, 1, -1,
+ 5, -5, 10, 2, -10, -2, 1, -1, 11, -11, 1, -1, -4, 2, 4, 3,
+ -3, -2, 6, -6, 12, 1, -12, -1, 2, 1, -2, -1, 13, -13, 2, -2,
+ 7, -7, 1, -1, 1, 1, -1, 3, -3, 14, 5, -1, -14, -5, 4, -4,
+ 15, -15, 1, -1, 8, -8, -3, 3, 16, 1, -16, -1, 1, 1, -1, -1,
+ 1, 1, -1, 1, 2, 1, -2, 1, -1, -1, -1, 6, -1, 3, -6, 17,
+ -17, -3, 1, 1, 1, 4, -1, -1, -4, 3, -1, 5, -3, -1, -9, 9,
+ -5, 1, 18, -18, 2, 1, -2, 1, -1, -1, 1, 19, -1, 1, -19, -1,
+ 4, 1, -1, 1, 7, -4, -2, 2, -7, 10, -1, -10, 1, 20, -1, -20,
+ 1, -1, 2, 4, -2, 5, 1, -5, 6, -4, 21, 4, 2, -6, -21, -1,
+ -2, 1, -4, -1, -3, 22, -1, 1, 3, -22, -1, 11, -11, 1, 1, 1,
+ 8, -8, 2, 2, -1, -2, -2, -1, 1, -1, -5, 5, 2, 23, -23, -2,
+ 1, -1, 24, -24, -1, -1, 7, 6, -7, 5, -6, 12, -3, 3, 1, -5,
+ 1, 1, -12, 25, -1, -5, 5, -25, -1, 1, 9, 1, -1, -9, 26, -26 ]
+ }
+];
diff --git a/nihav-indeo/src/codecs/ividsp.rs b/nihav-indeo/src/codecs/ividsp.rs
new file mode 100644
index 0000000..88bc8cc
--- /dev/null
+++ b/nihav-indeo/src/codecs/ividsp.rs
@@ -0,0 +1,467 @@
+use super::ivi::{IVITransformType,TDir,TrFunc,TrFuncDC};
+
+#[inline(always)]
+fn hbutterfly(a: i32, b: i32) -> (i32, i32) {
+ ((a + b) >> 1, (a - b) >> 1)
+}
+#[inline(always)]
+fn butterfly(a: i32, b: i32) -> (i32, i32) {
+ (a + b, a - b)
+}
+#[inline(always)]
+fn ireflect(a: i32, b: i32) -> (i32, i32) {
+ (((b * 2 - a + 2) >> 2) - a, ((b + 2 * a + 2) >> 2) + b)
+}
+
+macro_rules! haar_transform {
+ ($c0:expr, $c1:expr, $c2:expr, $c3:expr) => {{
+ let (t0, t1) = hbutterfly($c0, $c1);
+ let (t2, t3) = hbutterfly(t0, $c2);
+ $c0 = t2;
+ $c1 = t3;
+ let (t4, t5) = hbutterfly(t1, $c3);
+ $c2 = t4;
+ $c3 = t5;
+ }};
+ ($c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr, $c6:expr, $c7:expr) => {{
+ let (a0, a1) = hbutterfly($c0 << 1, $c1 << 1);
+
+ let (t0, t1) = hbutterfly(a0, $c2);
+ let (t2, t3) = hbutterfly(a1, $c3);
+ let (u0, u1) = hbutterfly(t0, $c4);
+ let (u2, u3) = hbutterfly(t1, $c5);
+ let (u4, u5) = hbutterfly(t2, $c6);
+ let (u6, u7) = hbutterfly(t3, $c7);
+
+ $c0 = u0;
+ $c1 = u1;
+ $c2 = u2;
+ $c3 = u3;
+ $c4 = u4;
+ $c5 = u5;
+ $c6 = u6;
+ $c7 = u7;
+ }};
+}
+macro_rules! slant_transform {
+ ($c0:expr, $c1:expr, $c2:expr, $c3:expr, $output:ident) => {{
+ let (t0, t1) = butterfly($c0, $c2);
+ let (t2, t3) = ireflect ($c3, $c1);
+ let (t4, t5) = butterfly(t0, t3);
+ let (t6, t7) = butterfly(t1, t2);
+ $c0 = $output(t4);
+ $c1 = $output(t6);
+ $c2 = $output(t7);
+ $c3 = $output(t5);
+ }};
+ ($c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr, $c6:expr, $c7:expr, $output:ident) => {{
+ let t0 = $c3 + (($c1 * 4 - $c3 + 4) >> 3);
+ let t1 = $c1 + ((-$c1 - $c3 * 4 + 4) >> 3);
+
+ let (t2, t3) = butterfly($c0, t1);
+ let (t4, t5) = butterfly($c4, $c5);
+ let (t6, t7) = butterfly($c7, $c6);
+ let (t8, t9) = butterfly(t0, $c2);
+
+ let (u0, u1) = butterfly(t2, t4);
+ let (u2, u3) = ireflect (t7, t8);
+ let (u4, u5) = butterfly(t3, t5);
+ let (u6, u7) = ireflect (t6, t9);
+
+ let (t0, t1) = butterfly(u0, u3);
+ let (t2, t3) = butterfly(u1, u2);
+ let (t4, t5) = butterfly(u4, u7);
+ let (t6, t7) = butterfly(u5, u6);
+
+ $c0 = $output(t0);
+ $c1 = $output(t2);
+ $c2 = $output(t3);
+ $c3 = $output(t1);
+ $c4 = $output(t4);
+ $c5 = $output(t6);
+ $c6 = $output(t7);
+ $c7 = $output(t5);
+ }};
+}
+
+fn haar8x8_2d(blk: &mut[i32; 64]) {
+ for i in 0..4 {
+ let mut c0 = blk[i + 0*8] << 1;
+ let mut c1 = blk[i + 1*8] << 1;
+ let mut c2 = blk[i + 2*8] << 1;
+ let mut c3 = blk[i + 3*8] << 1;
+ haar_transform!(c0, c1, c2, c3,
+ blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8]);
+ blk[i + 0*8] = c0;
+ blk[i + 1*8] = c1;
+ blk[i + 2*8] = c2;
+ blk[i + 3*8] = c3;
+ }
+ for i in 4..8 {
+ haar_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+ blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8]);
+ }
+ for i in 0..8 {
+ let row = &mut blk[i*8..(i+1)*8];
+ haar_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
+ }
+}
+fn haar8x8_row(blk: &mut[i32; 64]) {
+ for i in 0..8 {
+ let row = &mut blk[i*8..(i+1)*8];
+ haar_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7]);
+ }
+}
+fn haar8x8_col(blk: &mut[i32; 64]) {
+ for i in 0..8 {
+ haar_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+ blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8]);
+ }
+}
+fn haar8x8_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = in0 >> 3;
+ for i in 0..64 { blk[i] = dc; }
+}
+
+fn haar4x4_2d(blk: &mut[i32; 64]) {
+ for i in 0..2 {
+ let mut c0 = blk[i + 0*4] << 1;
+ let mut c1 = blk[i + 1*4] << 1;
+ haar_transform!(c0, c1, blk[i + 2*4], blk[i + 3*4]);
+ blk[i + 0*4] = c0;
+ blk[i + 1*4] = c1;
+ }
+ for i in 2..4 {
+ haar_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4]);
+ }
+ for i in 0..4 {
+ let row = &mut blk[i*4..(i+1)*4];
+ haar_transform!(row[0], row[1], row[2], row[3]);
+ }
+}
+fn haar4x4_row(blk: &mut[i32; 64]) {
+ for i in 0..4 {
+ let row = &mut blk[i*4..(i+1)*4];
+ haar_transform!(row[0], row[1], row[2], row[3]);
+ }
+}
+fn haar4x4_col(blk: &mut[i32; 64]) {
+ for i in 0..4 {
+ haar_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4]);
+ }
+}
+fn haar4x4_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = in0 >> 3;
+ for i in 0..16 { blk[i] = dc; }
+}
+
+fn slant8x8_2d(blk: &mut[i32; 64]) {
+ let pass1 = |x: i32| x;
+ let pass2 = |x: i32| (x + 1) >> 1;
+
+ for i in 0..8 {
+ let mut s0 = 0;
+ for j in 0..8 { s0 |= blk[i + j*8]; }
+ if s0 == 0 { continue; }
+
+ slant_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+ blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8], pass1);
+ }
+ for i in 0..8 {
+ let row = &mut blk[i*8..(i+1)*8];
+ slant_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], pass2);
+ }
+}
+fn slant8x8_2d_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = (in0 + 1) >> 1;
+ for i in 0..64 { blk[i] = dc; }
+}
+fn slant8x8_row(blk: &mut[i32; 64]) {
+ let pass = |x: i32| (x + 1) >> 1;
+
+ for i in 0..8 {
+ let row = &mut blk[i*8..(i+1)*8];
+ slant_transform!(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], pass);
+ }
+}
+fn slant8x8_row_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = (in0 + 1) >> 1;
+
+ for i in 0..8 { blk[i] = dc; }
+ for i in 8..64 { blk[i] = 0; }
+}
+fn slant8x8_col(blk: &mut[i32; 64]) {
+ let pass = |x: i32| (x + 1) >> 1;
+
+ for i in 0..8 {
+ slant_transform!(blk[i + 0*8], blk[i + 1*8], blk[i + 2*8], blk[i + 3*8],
+ blk[i + 4*8], blk[i + 5*8], blk[i + 6*8], blk[i + 7*8], pass);
+ }
+}
+fn slant8x8_col_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = (in0 + 1) >> 1;
+
+ for i in 0..8 {
+ blk[i * 8] = dc;
+ for j in 1..8 { blk[i * 8 + j] = 0; }
+ }
+}
+
+fn slant4x4_2d(blk: &mut[i32; 64]) {
+ let pass1 = |x: i32| x;
+ let pass2 = |x: i32| (x + 1) >> 1;
+
+ for i in 0..4 {
+ slant_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4], pass1);
+ }
+ for i in 0..4 {
+ let row = &mut blk[i*4..(i+1)*4];
+ slant_transform!(row[0], row[1], row[2], row[3], pass2);
+ }
+}
+fn slant4x4_2d_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = (in0 + 1) >> 1;
+ for i in 0..16 { blk[i] = dc; }
+}
+fn slant4x4_row(blk: &mut[i32; 64]) {
+ let pass = |x: i32| (x + 1) >> 1;
+
+ for i in 0..4 {
+ let row = &mut blk[i*4..(i+1)*4];
+ slant_transform!(row[0], row[1], row[2], row[3], pass);
+ }
+}
+fn slant4x4_row_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = (in0 + 1) >> 1;
+
+ for i in 0..4 { blk[i] = dc; }
+ for i in 4..16 { blk[i] = 0; }
+}
+fn slant4x4_col(blk: &mut[i32; 64]) {
+ let pass = |x: i32| (x + 1) >> 1;
+
+ for i in 0..4 {
+ slant_transform!(blk[i + 0*4], blk[i + 1*4], blk[i + 2*4], blk[i + 3*4], pass);
+ }
+}
+fn slant4x4_col_dc(blk: &mut[i32; 64], in0: i32) {
+ let dc = (in0 + 1) >> 1;
+
+ for i in 0..4 {
+ blk[i * 4] = dc;
+ for j in 1..4 { blk[i * 4 + j] = 0; }
+ }
+}
+
+#[allow(unused_variables)]
+fn none8x8(blk: &mut[i32; 64]) {
+}
+fn none8x8_dc(blk: &mut[i32; 64], dc: i32) {
+ for i in 1..8 { blk[i] = dc; }
+ for i in 8..64 { blk[i] = 0; }
+}
+#[allow(unused_variables)]
+fn none4x4(blk: &mut[i32; 64]) {
+}
+fn none4x4_dc(blk: &mut[i32; 64], dc: i32) {
+ for i in 1..4 { blk[i] = dc; }
+ for i in 4..16 { blk[i] = 0; }
+}
+
+pub fn ivi_get_transform8x8_funcs(ttype: IVITransformType) -> (TrFunc, TrFuncDC) {
+ match ttype {
+ IVITransformType::Haar(_, ref dir) => {
+ match *dir {
+ TDir::TwoD => { (haar8x8_2d, haar8x8_dc) },
+ TDir::Row => { (haar8x8_row, haar8x8_dc) },
+ TDir::Col => { (haar8x8_col, haar8x8_dc) },
+ } },
+ IVITransformType::Slant(_, ref dir) => {
+ match *dir {
+ TDir::TwoD => { (slant8x8_2d, slant8x8_2d_dc) },
+ TDir::Row => { (slant8x8_row, slant8x8_row_dc) },
+ TDir::Col => { (slant8x8_col, slant8x8_col_dc) },
+ } },
+ IVITransformType::DCT(_, _) => { unimplemented!() },
+ IVITransformType::None(_) => { (none8x8, none8x8_dc) }
+ }
+}
+pub fn ivi_get_transform4x4_funcs(ttype: IVITransformType) -> (TrFunc, TrFuncDC) {
+ match ttype {
+ IVITransformType::Haar(_, ref dir) => {
+ match *dir {
+ TDir::TwoD => { (haar4x4_2d, haar4x4_dc) },
+ TDir::Row => { (haar4x4_row, haar4x4_dc) },
+ TDir::Col => { (haar4x4_col, haar4x4_dc) },
+ } },
+ IVITransformType::Slant(_, ref dir) => {
+ match *dir {
+ TDir::TwoD => { (slant4x4_2d, slant4x4_2d_dc) },
+ TDir::Row => { (slant4x4_row, slant4x4_row_dc) },
+ TDir::Col => { (slant4x4_col, slant4x4_col_dc) },
+ } },
+ IVITransformType::DCT(_, _) => { unimplemented!() },
+ IVITransformType::None(_) => { (none4x4, none4x4_dc) }
+ }
+}
+
+pub fn ivi_mc_put(dst: &mut [i16], dstride: usize, src: &[i16], sstride: usize, mode: u8, w: usize, h: usize) {
+ let mut sidx = 0;
+ let mut didx = 0;
+ if src.len() < w + h * sstride { return; }
+ match mode {
+ 0 => {
+ for _ in 0..h {
+ let dest = &mut dst[didx..didx+w];
+ dest.copy_from_slice(&src[sidx..sidx+w]);
+ sidx += sstride;
+ didx += dstride;
+ }
+ },
+ 1 => {
+ /*for _ in 0..h {
+ for x in 0..w {
+ let val = (src[sidx + x] + src[sidx + x + 1]) >> 1;
+ dst[didx + x] = val;
+ }
+ sidx += sstride;
+ didx += dstride;
+ }*/
+ unsafe {
+ let mut sptr = src.as_ptr();
+ let mut dptr = dst.as_mut_ptr();
+ for _ in 0..h {
+ let mut last = *sptr;
+ for x in 0..w {
+ let nv = *sptr.offset((x + 1) as isize);
+ *dptr.offset(x as isize) = nv.wrapping_add(last) >> 1;
+ last = nv;
+ }
+ sptr = sptr.offset(sstride as isize);
+ dptr = dptr.offset(dstride as isize);
+ }
+ }
+ },
+ 2 => {
+ /*for _ in 0..h {
+ for x in 0..w {
+ let val = (src[sidx + x] + src[sidx + x + sstride]) >> 1;
+ dst[didx + x] = val;
+ }
+ sidx += sstride;
+ didx += dstride;
+ }*/
+ unsafe {
+ let mut sptr0 = src.as_ptr();
+ let mut sptr1 = sptr0.offset(sstride as isize);
+ let mut dptr = dst.as_mut_ptr();
+ for _ in 0..h {
+ for x in 0..w {
+ let a = *sptr0.offset(x as isize);
+ let b = *sptr1.offset(x as isize);
+ *dptr.offset(x as isize) = a.wrapping_add(b) >> 1;
+ }
+ sptr0 = sptr0.offset(sstride as isize);
+ sptr1 = sptr1.offset(sstride as isize);
+ dptr = dptr.offset(sstride as isize);
+ }
+ }
+ },
+ 3 => {
+ /*for _ in 0..h {
+ for x in 0..w {
+ let val = (src[sidx + x + 0] + src[sidx + x + sstride + 0] +
+ src[sidx + x + 1] + src[sidx + x + sstride + 1]) >> 2;
+ dst[didx + x] = val;
+ }
+ sidx += sstride;
+ didx += dstride;
+ }*/
+ unsafe {
+ let mut sptr0 = src.as_ptr();
+ let mut sptr1 = sptr0.offset(sstride as isize);
+ let mut dptr = dst.as_mut_ptr();
+ let mut la = *sptr0;
+ let mut lb = *sptr1;
+ for _ in 0..h {
+ for x in 0..w {
+ let a = *sptr0.offset((x + 1) as isize);
+ let b = *sptr1.offset((x + 1) as isize);
+ let aas = a.wrapping_add(la);
+ let bbs = b.wrapping_add(lb);
+ *dptr.offset(x as isize) = aas.wrapping_add(bbs) >> 2;
+ la = a;
+ lb = b;
+ }
+ sptr0 = sptr0.offset(sstride as isize);
+ sptr1 = sptr1.offset(sstride as isize);
+ dptr = dptr.offset(dstride as isize);
+ }
+ }
+ },
+ _ => {},
+ }
+}
+fn ivi_mc_add(dst: &mut [i16], dstride: usize, src: &[i16], sstride: usize, mode: u8, w: usize, h: usize) {
+ let mut sidx = 0;
+ let mut didx = 0;
+ match mode {
+ 0 => {
+ for _ in 0..h {
+ for x in 0..w {
+ dst[didx + x] += src[sidx + x];
+ }
+ sidx += sstride;
+ didx += dstride;
+ }
+ },
+ 1 => {
+ for _ in 0..h {
+ for x in 0..w {
+ let val = (src[sidx + x] + src[sidx + x + 1]) >> 1;
+ dst[didx + x] += val;
+ }
+ sidx += sstride;
+ didx += dstride;
+ }
+ },
+ 2 => {
+ for _ in 0..h {
+ for x in 0..w {
+ let val = (src[sidx + x] + src[sidx + x + sstride]) >> 1;
+ dst[didx + x] += val;
+ }
+ sidx += sstride;
+ didx += dstride;
+ }
+ },
+ 3 => {
+ for _ in 0..h {
+ for x in 0..w {
+ let val = (src[sidx + x + 0] + src[sidx + x + sstride + 0] +
+ src[sidx + x + 1] + src[sidx + x + sstride + 1]) >> 2;
+ dst[didx + x] += val;
+ }
+ sidx += sstride;
+ didx += dstride;
+ }
+ },
+ _ => {},
+ }
+}
+pub fn ivi_mc_avg(dst: &mut [i16], dstride: usize,
+ src1: &[i16], sstride1: usize, mode1: u8,
+ src2: &[i16], sstride2: usize, mode2: u8,
+ w: usize, h: usize) {
+ let mut tidx = 0;
+ let tstride = 8;
+ let mut didx = 0;
+ let mut tmp: [i16; 64] = [0; 64];
+ ivi_mc_add(&mut tmp, tstride, src1, sstride1, mode1, w, h);
+ ivi_mc_add(&mut tmp, tstride, src2, sstride2, mode2, w, h);
+ for _ in 0..h {
+ for x in 0..w { dst[didx + x] = tmp[tidx + x] >> 1; }
+ tidx += tstride;
+ didx += dstride;
+ }
+}
diff --git a/nihav-indeo/src/codecs/mod.rs b/nihav-indeo/src/codecs/mod.rs
new file mode 100644
index 0000000..63bad83
--- /dev/null
+++ b/nihav-indeo/src/codecs/mod.rs
@@ -0,0 +1,50 @@
+use nihav_core::codecs::*;
+
+macro_rules! validate {
+ ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DecoderError::InvalidData); } };
+}
+
+#[cfg(feature="decoder_intel263")]
+mod intel263;
+#[cfg(feature="decoder_indeo2")]
+mod indeo2;
+#[cfg(feature="decoder_indeo3")]
+mod indeo3;
+#[cfg(feature="decoder_indeo4")]
+mod indeo4;
+#[cfg(feature="decoder_indeo5")]
+mod indeo5;
+
+#[cfg(any(feature="decoder_indeo4", feature="decoder_indeo5"))]
+mod ivi;
+#[cfg(any(feature="decoder_indeo4", feature="decoder_indeo5"))]
+mod ivibr;
+#[cfg(any(feature="decoder_indeo4", feature="decoder_indeo5"))]
+mod ividsp;
+
+#[cfg(feature="decoder_imc")]
+mod imc;
+
+const INDEO_CODECS: &[DecoderInfo] = &[
+#[cfg(feature="decoder_indeo2")]
+ DecoderInfo { name: "indeo2", get_decoder: indeo2::get_decoder },
+#[cfg(feature="decoder_indeo3")]
+ DecoderInfo { name: "indeo3", get_decoder: indeo3::get_decoder },
+#[cfg(feature="decoder_indeo4")]
+ DecoderInfo { name: "indeo4", get_decoder: indeo4::get_decoder },
+#[cfg(feature="decoder_indeo5")]
+ DecoderInfo { name: "indeo5", get_decoder: indeo5::get_decoder },
+#[cfg(feature="decoder_intel263")]
+ DecoderInfo { name: "intel263", get_decoder: intel263::get_decoder },
+
+#[cfg(feature="decoder_imc")]
+ DecoderInfo { name: "imc", get_decoder: imc::get_decoder_imc },
+#[cfg(feature="decoder_imc")]
+ DecoderInfo { name: "iac", get_decoder: imc::get_decoder_iac },
+];
+
+pub fn indeo_register_all_codecs(rd: &mut RegisteredDecoders) {
+ for decoder in INDEO_CODECS.into_iter() {
+ rd.add_decoder(decoder.clone());
+ }
+}