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::*;
+use nihav_codec_support::dsp::fft::*;
+use nihav_codec_support::dsp::window::*;
const BANDS: usize = 32;
const COEFFS: usize = 256;
self.skip_flag[i] = false;
}
}
+ #[allow(clippy::cognitive_complexity)]
fn calculate_bit_allocation(&mut self, ch_data: &mut IMCChannel, bits: usize, fixed_head: bool, adj_idx: usize) -> DecoderResult<()> {
let mut peak = 0.0;
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;
+ tmp[band] = f32::from(self.band_bits[band]) * -2.0 + ch_data.bit_est[band] - 0.415;
}
}
let mut peak = 0.0;
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;
+ tmp[band] = f32::from(self.band_bits[band]) * -2.0 + ch_data.bit_est[band] - 0.415 + 2.0;
}
}
while 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;
+ tmp[band] = f32::from(self.band_bits[band]) * -2.0 + ch_data.bit_est[band] - 0.415;
}
}
let mut used_bits: i32 = 0;
sqrt_tab[i] = (i as f32).sqrt();
}
- LUTs { exp_lev: exp_lev, exp_10: exp_10, sqrt_tab: sqrt_tab }
+ LUTs { exp_lev, exp_10, sqrt_tab }
}
}
chmap: NAChannelMap,
ainfo: NAAudioInfo,
- info: Rc<NACodecInfo>,
+ info: NACodecInfoRef,
codes: [[Codebook<u8>; 4]; 4],
ch_data: [IMCChannel; 2],
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];
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());
+ let codes = unsafe {
+ let mut ucodes: mem::MaybeUninit::<[[Codebook<u8>; 4]; 4]> = mem::MaybeUninit::uninit();
+ for i in 0..4 {
+ for j in 0..4 {
+ let mut cr = IMCCodeReader::new(i, j);
+ ptr::write(&mut (*ucodes.as_mut_ptr())[i][j], Codebook::new(&mut cr, CodebookMode::MSB).unwrap());
+ }
}
- }
- }
+ ucodes.assume_init()
+ };
IMCDecoder {
- is_imc: is_imc,
+ is_imc,
chmap: NAChannelMap::new(),
ainfo: NAAudioInfo::new(0, 0, SND_F32P_FORMAT, 0),
info: NACodecInfo::new_dummy(),
- codes: 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,
+ cycle1,
+ cycle2,
+ weights1,
+ weights2,
}
}
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);
+ let (c1, c2) = calc_maxcoef(f32::from(max_coef));
for i in 0..BANDS {
if i != maxc_pos {
let level = br.read(4)?;
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);
+ val = f64::from(ch_data.new_floor[band]).powi(2);
ch_data.log_floor2[band] = 2.0 * ch_data.log_floor[band];
} else {
val = 0.0;
}
if reset {
let ch_data = &mut self.ch_data[ch];
- let (mut c1, mut c2) = calc_maxcoef(level[0] as f32);
+ let (mut c1, mut c2) = calc_maxcoef(f32::from(level[0]));
ch_data.new_floor[0] = c1;
ch_data.log_floor[0] = c2;
for i in 1..BANDS {
lval = level[i] - 16;
}
c1 *= self.luts.exp_10[(lval + 16) as usize];
- c2 += 0.83048 * (lval as f32);
+ c2 += 0.83048 * f32::from(lval);
ch_data.new_floor[i] = c1;
ch_data.log_floor[i] = c2;
}
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;
+ ch_data.log_floor[i] += f32::from(lval) * 0.83048;
} else {
ch_data.new_floor[i] = ch_data.old_floor[i];
}
self.read_skip_flags(br)?;
- let mut ch_data = &mut self.ch_data[ch];
+ let 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];
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;
+ bits_freed += i32::from(self.ba.cw_len[i]);
self.ba.cw_len[i] = 0;
}
}
- bits_freed -= self.ba.skip_flag_bits[band] as i32;
+ bits_freed -= i32::from(self.ba.skip_flag_bits[band]);
}
if bits_freed < 0 { return Err(DecoderError::Bug); }
- self.ba.adjust_bit_allocation(&mut ch_data, bits_freed);
+ self.ba.adjust_bit_allocation(ch_data, bits_freed);
Ok(())
}
}
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 mut br = BitReader::new(&data[BLOCK_SIZE*ch..][..BLOCK_SIZE], BitReaderMode::LE16MSB);
let hdr = br.read(9)?;
validate!((hdr & 0x18) == 0);
posttwiddle[i] = FFTComplex::exp(consts::PI / 256.0 * n).scale(1.0/32768.0);
}
IMDCTContext {
- pretwiddle1: pretwiddle1,
- pretwiddle2: pretwiddle2,
- posttwiddle: posttwiddle,
+ pretwiddle1,
+ pretwiddle2,
+ posttwiddle,
tmp: [FFTC_ZERO; COEFFS/2],
- fft: FFTBuilder::new_fft(FFTMode::SplitRadix, COEFFS/2),
- window: window,
+ fft: FFTBuilder::new_fft(COEFFS/2, false),
+ window,
}
}
fn imdct(&mut self, coeffs: &[f32; COEFFS], dst: &mut [f32], last_im: &mut [f32; COEFFS/2]) {
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);
+ self.fft.do_ifft_inplace(&mut self.tmp);
for i in 0..COEFFS/2 {
let tmp = !(self.tmp[i] * self.posttwiddle[i]);
let c1 = self.window[i * 2];
const CHMAP_STEREO: [NAChannelType; 2] = [NAChannelType::L, NAChannelType::R];
impl NADecoder for IMCDecoder {
- fn init(&mut self, info: Rc<NACodecInfo>) -> DecoderResult<()> {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
if let NACodecTypeInfo::Audio(ainfo) = info.get_properties() {
self.chmap = NAChannelMap::new();
match ainfo.get_channels() {
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()));
+ self.info = info.replace_info(NACodecTypeInfo::Audio(self.ainfo));
if !self.is_imc {
self.generate_iac_tables(ainfo.get_sample_rate() as f32);
Err(DecoderError::InvalidData)
}
}
- fn decode(&mut self, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ fn decode(&mut self, _supp: &mut NADecoderSupport, 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 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 dst = adata.get_data_mut().unwrap();
let mut start: usize = 0;
let channels = self.ainfo.get_channels() as usize;
let mut frm = NAFrame::new_from_pkt(pkt, self.info.clone(), abuf);
frm.set_keyframe(true);
- Ok(Rc::new(RefCell::new(frm)))
+ Ok(frm.into_ref())
+ }
+ fn flush(&mut self) {
}
}
-pub fn get_decoder_imc() -> Box<NADecoder> {
+impl NAOptionHandler for IMCDecoder {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder_imc() -> Box<dyn NADecoder + Send> {
Box::new(IMCDecoder::new(true))
}
-pub fn get_decoder_iac() -> Box<NADecoder> {
+pub fn get_decoder_iac() -> Box<dyn NADecoder + Send> {
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 } }
+ fn new(sel1: usize, sel2: usize) -> Self { IMCCodeReader { sel1, 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 code(&mut self, idx: usize) -> u32 { u32::from(IMC_CODE_CODES[self.sel1][self.sel2][idx]) }
fn sym (&mut self, idx: usize) -> u8 { idx as u8 }
fn len(&mut self) -> usize { IMC_CODE_LENGTHS[0][0].len() }
}
#[cfg(test)]
mod test {
- use crate::test::dec_video::*;
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::indeo_register_all_decoders;
+ use nihav_commonfmt::generic_register_all_demuxers;
#[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");
+ let mut dmx_reg = RegisteredDemuxers::new();
+ generic_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ indeo_register_all_decoders(&mut dec_reg);
+
+// let file = "assets/Indeo/neal73_saber.avi";
+// let file = "assets/Indeo/IMC/hvalen.avi";
+ // sample from a private collection
+ let file = "assets/Indeo/IMC/8khz.avi";
+// let file = "assets/Indeo/STsKlassFist-1a.avi";
+// let file = "assets/Indeo/IMC/Angel Bday.avi";
+ test_decode_audio("avi", file, None, None/*Some("imc")*/, &dmx_reg, &dec_reg);
//test_file_decoding("avi", file, None, false, true, None);
}
}