nihav_duck = { path = "../nihav-duck" }
nihav_game = { path = "../nihav-game" }
nihav_indeo = { path = "../nihav-indeo" }
+nihav_llaudio = { path = "../nihav-llaudio" }
nihav_ms = { path = "../nihav-ms" }
nihav_qt = { path = "../nihav-qt" }
nihav_rad = { path = "../nihav-rad" }
extern crate nihav_duck;
extern crate nihav_game;
extern crate nihav_indeo;
+extern crate nihav_llaudio;
extern crate nihav_ms;
extern crate nihav_rad;
extern crate nihav_realmedia;
use nihav_indeo::indeo_register_all_decoders;
+use nihav_llaudio::llaudio_register_all_decoders;
+use nihav_llaudio::llaudio_register_all_demuxers;
+
use nihav_ms::ms_register_all_decoders;
use nihav_ms::ms_register_all_encoders;
duck_register_all_decoders(rd);
game_register_all_decoders(rd);
indeo_register_all_decoders(rd);
+ llaudio_register_all_decoders(rd);
ms_register_all_decoders(rd);
qt_register_all_decoders(rd);
rad_register_all_decoders(rd);
pub fn nihav_register_all_demuxers(rd: &mut RegisteredDemuxers) {
generic_register_all_demuxers(rd);
game_register_all_demuxers(rd);
+ llaudio_register_all_demuxers(rd);
rad_register_all_demuxers(rd);
realmedia_register_all_demuxers(rd);
}
--- /dev/null
+[package]
+name = "nihav_llaudio"
+version = "0.1.0"
+authors = ["Kostya Shishkov <kostya.shishkov@gmail.com>"]
+edition = "2018"
+
+[dependencies.nihav_core]
+path = "../nihav-core"
+features = []
+
+[dependencies.nihav_codec_support]
+path = "../nihav-codec-support"
+
+[features]
+default = ["all_decoders", "all_demuxers"]
+
+all_decoders = ["decoder_ape", "decoder_flac", "decoder_tta", "decoder_wavpack"]
+decoders = []
+decoder_ape = ["decoders"]
+decoder_flac = ["decoders"]
+decoder_tta = ["decoders"]
+decoder_wavpack = ["decoders"]
+
+all_demuxers = ["demuxer_ape", "demuxer_flac", "demuxer_tta", "demuxer_wavpack"]
+demuxers = []
+demuxer_ape = ["demuxers"]
+demuxer_flac = ["demuxers"]
+demuxer_tta = ["demuxers"]
+demuxer_wavpack = ["demuxers"]
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+
+use super::apepred::*;
+use super::apereader::*;
+
+struct APEDecoder {
+ ainfo: NAAudioInfo,
+ chmap: NAChannelMap,
+ version: u16,
+ decode_mono: fn(&mut Coder, &mut [i32]) -> DecoderResult<()>,
+ decode_stereo: fn(&mut Coder, &mut [i32], &mut [i32]) -> DecoderResult<()>,
+ is_stereo: bool,
+ left: Vec<i32>,
+ right: Vec<i32>,
+ fmode: FilterMode,
+ data: Vec<u8>,
+ blocksperframe: usize,
+}
+
+impl APEDecoder {
+ fn new() -> Self {
+ Self {
+ ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+ chmap: NAChannelMap::new(),
+ version: 0,
+ decode_mono: decode_mono_dummy,
+ decode_stereo: decode_stereo_dummy,
+ is_stereo: false,
+ left: Vec::new(),
+ right: Vec::new(),
+ fmode: FilterMode::None,
+ data: Vec::new(),
+ blocksperframe: 0,
+ }
+ }
+}
+
+impl NADecoder for APEDecoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+ if let Some(buf) = info.get_extradata() {
+ let mut mr = MemoryReader::new_read(&buf);
+ let mut br = ByteReader::new(&mut mr);
+ let version = br.read_u16le()?;
+ let compression = br.read_u16le()?;
+ let _flags = br.read_u16le()?;
+ let channels = br.read_byte()?;
+ let bits = br.read_byte()?;
+ let srate = br.read_u32le()?;
+ let blocksperframe = br.read_u32le()? as usize;
+
+ validate!(channels > 0);
+ validate!(bits > 0 && bits <= 32);
+ validate!((compression % 1000) == 0 && compression > 0 && compression <= 5000);
+ validate!(compression < 5000 || version >= 3930);
+ if bits != 16 {
+ return Err(DecoderError::NotImplemented);
+ }
+ if version > 3990 {
+ return Err(DecoderError::NotImplemented);
+ }
+
+ self.version = version;
+ self.blocksperframe = blocksperframe;
+ self.is_stereo = channels == 2;
+ self.left.resize(blocksperframe, 0);
+ if self.is_stereo {
+ self.right.resize(blocksperframe, 0);
+ }
+
+ self.decode_mono = if version >= 3990 {
+ decode_mono_3990
+ } else if version >= 3910 {
+ decode_mono_3910
+ } else if version >= 3900 {
+ decode_mono_3900
+ } else if version >= 3890 {
+ decode_mono_3890
+ } else if version >= 3860 {
+ decode_mono_3860
+ } else {
+ decode_mono_0000
+ };
+ self.decode_stereo = if version >= 3990 {
+ decode_stereo_3990
+ } else if version >= 3930 {
+ decode_stereo_3930
+ } else if version >= 3910 {
+ decode_stereo_3910
+ } else if version >= 3900 {
+ decode_stereo_3900
+ } else if version >= 3890 {
+ decode_stereo_3890
+ } else if version >= 3860 {
+ decode_stereo_3860
+ } else {
+ decode_stereo_0000
+ };
+ self.fmode = FilterMode::new(version, compression);
+
+ self.chmap = if channels == 1 {
+ NAChannelMap::from_str("C").unwrap()
+ } else if channels == 2 {
+ NAChannelMap::from_str("L,R").unwrap()
+ } else {
+ return Err(DecoderError::NotImplemented);
+ };
+ self.ainfo = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 4602);
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+ let pktbuf = pkt.get_buffer();
+ validate!(pktbuf.len() > 9);
+
+ let nblocks = read_u32le(&pktbuf[0..])? as usize;
+ validate!(nblocks > 0);
+ let bits = u32::from(pktbuf[4]);
+ validate!(bits < 32);
+ self.data.truncate(0);
+ self.data.reserve((pktbuf.len() & !3) + 2);
+ for word in pktbuf[8..].chunks_exact(4) {
+ self.data.push(word[3]);
+ self.data.push(word[2]);
+ self.data.push(word[1]);
+ self.data.push(word[0]);
+ }
+ if self.version < 3950 {
+ self.data.push(0);
+ self.data.push(0);
+ }
+
+ let (mut coder, ref_crc, fflags) = if self.version < 3900 {
+ let mut br = BitReader::new(&self.data, BitReaderMode::BE);
+ br.skip(bits)?;
+ let mut crc = br.read(32)?;
+ let fflags = if self.version >= 3830 && (crc & 0x80000000) != 0 {
+ crc ^= 0x80000000;
+ br.read(32)?
+ } else {
+ 0
+ };
+ (Coder::Rice(RiceCoder::new(br)), crc, fflags)
+ } else {
+ let mut boff = (bits / 8) as usize;
+ let mut crc = read_u32be(&self.data[boff..])?;
+ boff += 4;
+ let fflags = if (crc & 0x80000000) != 0 {
+ crc ^= 0x80000000;
+ let flg = read_u32be(&self.data[boff..])?;
+ boff += 4;
+ flg
+ } else {
+ 0
+ };
+ // it ignores first byte anyway
+ (Coder::Range(RangeCoder::new(&self.data[boff + 1..])), crc, fflags)
+ };
+ self.left.resize(nblocks, 0);
+ if self.is_stereo {
+ self.right.resize(nblocks, 0);
+ }
+ if (fflags & 3) == 0 {
+ if !self.is_stereo || (fflags & 4) != 0 {
+ (self.decode_mono)(&mut coder, &mut self.left)?;
+ self.fmode.filter_mono(&mut self.left);
+
+ if (fflags & 4) != 0 {
+ self.right.copy_from_slice(&self.left);
+ }
+ } else {
+ (self.decode_stereo)(&mut coder, &mut self.left, &mut self.right)?;
+ self.fmode.filter_stereo(&mut self.left, &mut self.right);
+ }
+ }
+
+ if self.version >= 0x3990 || nblocks == self.blocksperframe {
+ let mut crc = 0xFFFFFFFF;
+ if !self.is_stereo {
+ for el in self.left.iter() {
+ let byte1 = *el as u8;
+ let byte0 = (*el >> 8) as u8;
+ crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte1) as usize];
+ crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte0) as usize];
+ }
+ } else {
+ for (l, r) in self.left.iter().zip(self.right.iter()) {
+ let byte1 = *l as u8;
+ let byte0 = (*l >> 8) as u8;
+ crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte1) as usize];
+ crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte0) as usize];
+ let byte1 = *r as u8;
+ let byte0 = (*r >> 8) as u8;
+ crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte1) as usize];
+ crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte0) as usize];
+ }
+ }
+ crc = !crc;
+ if self.version >= 3830 {
+ crc >>= 1;
+ }
+ if crc != ref_crc {
+ return Err(DecoderError::ChecksumError);
+ }
+ }
+
+ let abuf = alloc_audio_buffer(self.ainfo, nblocks, self.chmap.clone())?;
+ let mut adata = abuf.get_abuf_i16().unwrap();
+ let off1 = adata.get_offset(1);
+ let dst = adata.get_data_mut().unwrap();
+ let (left, right) = dst.split_at_mut(off1);
+ for (dst, src) in left.iter_mut().zip(self.left.iter()) {
+ *dst = *src as i16;
+ }
+ if self.is_stereo {
+ for (dst, src) in right.iter_mut().zip(self.right.iter()) {
+ *dst = *src as i16;
+ }
+ }
+
+ let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+ frm.set_duration(Some(nblocks as u64));
+ Ok(frm.into_ref())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for APEDecoder {
+ 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() -> Box<dyn NADecoder + Send> {
+ Box::new(APEDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::llaudio_register_all_decoders;
+ use crate::llaudio_register_all_demuxers;
+ #[test]
+ fn test_ape_3990() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight.ape", Some(3), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x569e002b, 0xd93772a9, 0x1cfd81cd, 0xad81319a]));
+ }
+ #[test]
+ fn test_ape_3940() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac394b1-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+ }
+ #[test]
+ fn test_ape_3920() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac392b2-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+ }
+ #[test]
+ fn test_ape_3910() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac391b1-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+ }
+ #[test]
+ fn test_ape_3890() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac389b1-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+ }
+ #[test]
+ fn test_ape_3880() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac388-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+ }
+ #[test]
+ fn test_ape_3800() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac380-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+ }
+}
+
+const CRC32_TAB: [u32; 256] = [
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
+];
--- /dev/null
+const HISTORY_SIZE: usize = 512;
+
+fn val2sign(val: i32) -> i32 {
+ if val > 0 {
+ -1
+ } else if val < 0 {
+ 1
+ } else {
+ 0
+ }
+}
+
+pub struct OldFilt {
+ version: u16,
+ compression: u16,
+}
+
+pub struct NewFilt {
+ version: u16,
+ filters: [NFilterContext; 3],
+ lfilt: LastFilterContext,
+ rfilt: LastFilterContext,
+}
+
+#[allow(clippy::large_enum_variant)]
+pub enum FilterMode {
+ Old(OldFilt),
+ New(NewFilt),
+ None,
+}
+
+impl FilterMode {
+ pub fn new(version: u16, compression: u16) -> Self {
+ if version < 3930 {
+ FilterMode::Old(OldFilt::new(version, compression))
+ } else {
+ FilterMode::New(NewFilt::new(version, compression))
+ }
+ }
+ pub fn filter_mono(&mut self, l: &mut [i32]) {
+ match *self {
+ FilterMode::Old(ref mut ofilt) => ofilt.filter(l),
+ FilterMode::New(ref mut nfilt) => nfilt.filter_mono(l),
+ FilterMode::None => unreachable!(),
+ };
+ }
+ pub fn filter_stereo(&mut self, l: &mut [i32], r: &mut [i32]) {
+ match *self {
+ FilterMode::Old(ref mut ofilt) => {
+ ofilt.filter(l);
+ ofilt.filter(r);
+ for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+ let new_l = *l - *r / 2;
+ let new_r = *r + new_l;
+ *l = new_l;
+ *r = new_r;
+ }
+ },
+ FilterMode::New(ref mut nfilt) => {
+ nfilt.filter_stereo(l, r);
+ for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+ let new_l = *r - *l / 2;
+ let new_r = *l + new_l;
+ *l = new_l;
+ *r = new_r;
+ }
+ },
+ FilterMode::None => unreachable!(),
+ };
+ }
+}
+
+const NEW_FILTER_PARAMS: [[(u8, u8); 3]; 5] = [
+ [ (0, 0), ( 0, 0), ( 0, 0) ],
+ [ (1, 11), ( 0, 0), ( 0, 0) ],
+ [ (4, 11), ( 0, 0), ( 0, 0) ],
+ [ (2, 10), (16, 13), ( 0, 0) ],
+ [ (1, 11), (16, 13), (80, 15) ],
+];
+
+#[derive(Clone,Default)]
+struct NFilterContext {
+ buf: Vec<i32>,
+ coeffs: Vec<i32>,
+ order: usize,
+ bits: u8,
+ avg: i32,
+ new: bool,
+}
+
+impl NFilterContext {
+ fn new(ord16: u8, bits: u8, new: bool) -> Self {
+ let order = ord16 as usize * 16;
+ Self {
+ buf: if order > 0 { vec![0; order * 2 + HISTORY_SIZE] } else { Vec::new() },
+ coeffs: vec![0; order],
+ order,
+ bits,
+ avg: 0,
+ new,
+ }
+ }
+ fn reset(&mut self) {
+ for el in self.buf[..self.order * 2].iter_mut() { *el = 0; }
+ for el in self.coeffs.iter_mut() { *el = 0; }
+ self.avg = 0;
+ }
+ fn apply(&mut self, dst: &mut [i32]) {
+ if self.order == 0 { return; }
+ let mut adapt_pos = self.order;
+ let mut delay_pos = self.order * 2;
+ for el in dst.iter_mut() {
+ let mut sum = 0i32;
+ for (i, coef) in self.coeffs.iter_mut().enumerate() {
+ sum += *coef * self.buf[delay_pos - self.order + i];
+ if *el < 0 {
+ *coef += self.buf[adapt_pos - self.order + i];
+ } else if *el > 0 {
+ *coef -= self.buf[adapt_pos - self.order + i];
+ }
+ }
+ let pred = (sum + (1 << (self.bits - 1))) >> self.bits;
+ let val = *el + pred;
+ *el = val;
+ self.buf[delay_pos] = val.min(32767).max(-32768);
+ if self.new {
+ let aval = val.abs();
+ let sign = val2sign(val);
+ self.buf[adapt_pos] = if aval == 0 {
+ 0
+ } else if aval <= self.avg * 4 / 3 {
+ sign * 8
+ } else if aval <= self.avg * 3 {
+ sign * 16
+ } else {
+ sign * 32
+ };
+ self.avg += (aval - self.avg) / 16;
+ self.buf[adapt_pos - 1] >>= 1;
+ self.buf[adapt_pos - 2] >>= 1;
+ self.buf[adapt_pos - 8] >>= 1;
+ } else {
+ self.buf[adapt_pos] = 4 * val2sign(val);
+ self.buf[adapt_pos - 4] >>= 1;
+ self.buf[adapt_pos - 8] >>= 1;
+ }
+ delay_pos += 1;
+ adapt_pos += 1;
+ if delay_pos == HISTORY_SIZE + self.order * 2 {
+ delay_pos = self.order * 2;
+ adapt_pos = self.order;
+ for i in 0..self.order * 2 {
+ self.buf[i] = self.buf[HISTORY_SIZE + i];
+ }
+ }
+ }
+ }
+}
+
+#[derive(Clone,Copy,Default)]
+struct LastFilterContext {
+ last_a: i32,
+ filter_a: i32,
+ filter_b: i32,
+ coeffs_a: [i32; 4],
+ coeffs_b: [i32; 5],
+ delay_a: [i32; 4],
+ adapt_a: [i32; 4],
+ delay_b: [i32; 5],
+ adapt_b: [i32; 5],
+}
+
+impl LastFilterContext {
+ fn init(&mut self) {
+ const COEFFS_A_NEW: [i32; 4] = [360, 317, -109, 98];
+
+ self.filter_a = 0;
+ self.filter_b = 0;
+ self.coeffs_a = COEFFS_A_NEW;
+ self.coeffs_b = [0; 5];
+ self.last_a = 0;
+ self.delay_a = [0; 4];
+ self.adapt_a = [0; 4];
+ self.delay_b = [0; 5];
+ self.adapt_b = [0; 5];
+ }
+ fn predict_a(&mut self) -> i32 {
+ for i in (0..3).rev() {
+ self.delay_a[i + 1] = self.delay_a[i];
+ self.adapt_a[i + 1] = self.adapt_a[i];
+ }
+ self.delay_a[0] = self.last_a;
+ self.delay_a[1] = self.last_a - self.delay_a[1];
+ self.adapt_a[0] = val2sign(self.delay_a[0]);
+ self.adapt_a[1] = val2sign(self.delay_a[1]);
+
+ self.delay_a[0] * self.coeffs_a[0] +
+ self.delay_a[1] * self.coeffs_a[1] +
+ self.delay_a[2] * self.coeffs_a[2] +
+ self.delay_a[3] * self.coeffs_a[3]
+ }
+ fn predict_b(&mut self, other_a: i32) -> i32 {
+ for i in (0..4).rev() {
+ self.delay_b[i + 1] = self.delay_b[i];
+ self.adapt_b[i + 1] = self.adapt_b[i];
+ }
+ self.delay_b[0] = other_a - ((self.filter_b * 31) >> 5);
+ self.delay_b[1] = self.delay_b[0] - self.delay_b[1];
+ self.adapt_b[0] = val2sign(self.delay_b[0]);
+ self.adapt_b[1] = val2sign(self.delay_b[1]);
+
+ self.filter_b = other_a;
+
+ (self.delay_b[0] * self.coeffs_b[0] +
+ self.delay_b[1] * self.coeffs_b[1] +
+ self.delay_b[2] * self.coeffs_b[2] +
+ self.delay_b[3] * self.coeffs_b[3] +
+ self.delay_b[4] * self.coeffs_b[4]) >> 1
+ }
+ fn update_a(&mut self, pred: i32, diff: i32) -> i32 {
+ self.last_a = diff + (pred >> 10);
+ let sign = val2sign(diff);
+ for i in 0..4 {
+ self.coeffs_a[i] += self.adapt_a[i] * sign;
+ }
+ self.filter_a = self.last_a + ((self.filter_a * 31) >> 5);
+
+ self.filter_a
+ }
+ fn update_b(&mut self, diff: i32) {
+ let sign = val2sign(diff);
+ for i in 0..5 {
+ self.coeffs_b[i] += self.adapt_b[i] * sign;
+ }
+ }
+ fn predict_3930(&mut self, diff: i32) -> i32 {
+ for i in (0..3).rev() {
+ self.delay_a[i + 1] = self.delay_a[i];
+ }
+ self.delay_a[0] = self.last_a;
+ let d0 = self.delay_a[0];
+ let d1 = self.delay_a[0] - self.delay_a[1];
+ let d2 = self.delay_a[1] - self.delay_a[2];
+ let d3 = self.delay_a[2] - self.delay_a[3];
+
+ let pred = (self.coeffs_a[0] * d0 +
+ self.coeffs_a[1] * d1 +
+ self.coeffs_a[2] * d2 +
+ self.coeffs_a[3] * d3) >> 9;
+ self.last_a = diff + pred;
+ self.filter_a = self.last_a + ((self.filter_a * 31) >> 5);
+
+ let sign = val2sign(diff);
+ self.coeffs_a[0] += if d0 < 0 { sign } else { -sign };
+ self.coeffs_a[1] += if d1 < 0 { sign } else { -sign };
+ self.coeffs_a[2] += if d2 < 0 { sign } else { -sign };
+ self.coeffs_a[3] += if d3 < 0 { sign } else { -sign };
+
+ self.filter_a
+ }
+}
+
+impl NewFilt {
+ fn new(version: u16, compression: u16) -> Self {
+ let cidx = (compression / 1000) as usize - 1;
+ let mut obj = Self {
+ version,
+ filters: [NFilterContext::default(), NFilterContext::default(), NFilterContext::default()],
+ lfilt: LastFilterContext::default(),
+ rfilt: LastFilterContext::default(),
+ };
+ obj.version = version;
+ let new = version >= 3980;
+ for i in 0..3 {
+ let (ord16, bits) = NEW_FILTER_PARAMS[cidx][i];
+ obj.filters[i] = NFilterContext::new(ord16, bits, new);
+ }
+ obj
+ }
+ fn filter_mono(&mut self, dst: &mut [i32]) {
+ for filt in self.filters.iter_mut() {
+ filt.reset();
+ filt.apply(dst);
+ }
+ self.lfilt.init();
+ if self.version >= 3950 {
+ for el in dst.iter_mut() {
+ let pred = self.lfilt.predict_a();
+ *el = self.lfilt.update_a(pred, *el);
+ }
+ } else {
+ for el in dst.iter_mut() {
+ *el = self.lfilt.predict_3930(*el);
+ }
+ }
+ }
+ fn filter_stereo(&mut self, l: &mut [i32], r: &mut [i32]) {
+ for filt in self.filters.iter_mut() {
+ filt.reset();
+ filt.apply(l);
+ filt.reset();
+ filt.apply(r);
+ }
+ self.lfilt.init();
+ self.rfilt.init();
+ if self.version >= 3950 {
+ for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+ let mut pred = self.lfilt.predict_a();
+ pred += self.lfilt.predict_b(self.rfilt.filter_a);
+ let new_l = self.lfilt.update_a(pred, *l);
+ self.lfilt.update_b(*l);
+ *l = new_l;
+
+ let mut pred = self.rfilt.predict_a();
+ pred += self.rfilt.predict_b(self.lfilt.filter_a);
+ let new_r = self.rfilt.update_a(pred, *r);
+ self.rfilt.update_b(*r);
+ *r = new_r;
+ }
+ } else {
+ for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+ let new_l = self.lfilt.predict_3930(*r);
+ let new_r = self.rfilt.predict_3930(*l);
+ *l = new_l;
+ *r = new_r;
+ }
+ }
+ }
+}
+
+impl OldFilt {
+ fn new(version: u16, compression: u16) -> Self {
+ Self {
+ version, compression
+ }
+ }
+ fn filter(&mut self, dst: &mut [i32]) {
+ match self.compression {
+ 1000 => {
+ Self::filter_fast(dst);
+ },
+ 2000 => {
+ Self::filter_normal(dst, 4, 10);
+ },
+ 3000 => {
+ Self::filter_high(dst, 16, 9);
+ Self::filter_normal(dst, 16, 10);
+ },
+ 4000 => {
+ if self.version < 3830 {
+ Self::filter_high(dst, 128, 11);
+ Self::filter_normal(dst, 128, 10);
+ } else {
+ Self::filter_extra_high(dst);
+ Self::filter_high(dst, 256, 12);
+ Self::filter_normal(dst, 256, 11);
+ }
+ },
+ _ => unreachable!(),
+ };
+ }
+ fn filter_fast(dst: &mut [i32]) {
+ const COEFF_A_FAST: i32 = 375;
+
+ if dst.len() <= 3 {
+ return;
+ }
+ let mut delay = [dst[1], dst[0]];
+ let mut last = dst[2];
+ let mut filter = dst[2];
+ let mut weight = COEFF_A_FAST;
+ for el in dst[3..].iter_mut() {
+ delay[1] = delay[0];
+ delay[0] = last;
+ let pred = delay[0] * 2 - delay[1];
+ last = *el + ((pred * weight) >> 9);
+ if (*el ^ pred) > 0 {
+ weight += 1;
+ } else {
+ weight -= 1;
+ }
+ filter += last;
+ *el = filter;
+ }
+ }
+ fn filter_normal(dst: &mut [i32], start: usize, shift: u8) {
+ const COEFFS_A_NORMAL: [i32; 3] = [64, 115, 64];
+ const COEFFS_B_NORMAL: [i32; 2] = [740, 0];
+
+ let mut last = 0;
+ let mut coeffs_a = COEFFS_A_NORMAL;
+ let mut coeffs_b = COEFFS_B_NORMAL;
+ let mut filter_a = 0;
+ let mut filter_b = 0;
+ let mut delay_a = [0; 3];
+ let mut delay_b = [0; 2];
+
+ for (i, el) in dst.iter_mut().enumerate() {
+ delay_a[2] = delay_a[1]; delay_a[1] = delay_a[0]; delay_a[0] = last;
+ delay_b[1] = delay_b[0]; delay_b[0] = filter_b;
+ if i < start {
+ let val = *el + filter_a;
+ last = *el;
+ filter_b = *el;
+ filter_a = val;
+ *el = val;
+ continue;
+ }
+ let a0 = delay_a[0] + (delay_a[2] - delay_a[1]) * 8;
+ let a1 = (delay_a[0] - delay_a[1]) * 2;
+ let a2 = delay_a[0];
+ let b0 = delay_b[0] * 2 - delay_b[1];
+ let b1 = delay_b[0];
+
+ let pred_a = a0 * coeffs_a[0] + a1 * coeffs_a[1] + a2 * coeffs_a[2];
+ let pred_b = b0 * coeffs_b[0] - b1 * coeffs_b[1];
+
+ let sign = val2sign(*el);
+ coeffs_a[0] += (((a0 >> 30) & 2) - 1) * sign;
+ coeffs_a[1] += (((a1 >> 28) & 8) - 4) * sign;
+ coeffs_a[2] += (((a2 >> 28) & 8) - 4) * sign;
+ last = *el + (pred_a >> 11);
+
+ let sign = val2sign(last);
+ coeffs_b[0] += (((b0 >> 29) & 4) - 2) * sign;
+ coeffs_b[1] -= (((b1 >> 30) & 2) - 1) * sign;
+
+ filter_b = last + (pred_b >> shift);
+ filter_a = filter_b + ((filter_a * 31) >> 5);
+
+ *el = filter_a;
+ }
+ }
+ fn filter_high(dst: &mut [i32], order: usize, shift: u8) {
+ let mut coeffs = [0i32; 256];
+ let mut delay = [0i32; 256];
+ if dst.len() <= order {
+ return;
+ }
+ delay[..order].copy_from_slice(&dst[..order]);
+ for el in dst[order..].iter_mut() {
+ let sign = val2sign(*el);
+ let mut sum = 0;
+ for i in 0..order {
+ sum += delay[i] * coeffs[i];
+ coeffs[i] -= (((delay[i] >> 30) & 2) - 1) * sign;
+ }
+ *el -= sum >> shift;
+ for i in 0..order-1 {
+ delay[i] = delay[i + 1];
+ }
+ delay[order - 1] = *el;
+ }
+ }
+ fn filter_extra_high(dst: &mut [i32]) {
+ let mut coeffs = [0i32; 8];
+ let mut delay = [0i32; 8];
+ for el in dst[256..].iter_mut() {
+ let sign = val2sign(*el);
+ let mut sum = 0;
+ for i in 0..8 {
+ sum += delay[i] * coeffs[i];
+ coeffs[i] -= (((delay[i] >> 30) & 2) - 1) * sign;
+ }
+ for i in (0..7).rev() {
+ delay[i + 1] = delay[i];
+ }
+ delay[0] = *el;
+ *el -= sum >> 9;
+ }
+ }
+}
--- /dev/null
+use nihav_core::codecs::{DecoderError, DecoderResult};
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+pub struct RiceParams {
+ k: u8,
+ sum: u32
+}
+
+impl RiceParams {
+ pub fn new() -> Self {
+ let k = 10;
+ Self { k, sum: 1 << (k + 4) }
+ }
+ fn update(&mut self, val: u32) {
+ let limit = if self.k > 0 { 1 << (self.k + 4) } else { 0 };
+ self.sum -= (self.sum + 16) >> 5;
+ self.sum += (val + 1) / 2;
+ if self.sum < limit {
+ self.k -= 1;
+ } else if (self.sum >= (1 << (self.k + 5))) && (self.k < 27) {
+ self.k += 1;
+ }
+ }
+ fn update_old(&mut self, val: u32) {
+ let limit = if self.k > 0 { 1 << (self.k + 4) } else { 0 };
+ self.sum -= (self.sum + 8) >> 4;
+ self.sum += val;
+ if self.sum < limit {
+ self.k -= 1;
+ } else if (self.sum >= (1 << (self.k + 5))) && (self.k < 24) {
+ self.k += 1;
+ }
+ }
+}
+
+pub struct RiceCoder<'a> {
+ br: BitReader<'a>,
+ rice_x: RiceParams,
+ rice_y: RiceParams,
+}
+
+impl<'a> RiceCoder<'a> {
+ pub fn new(br: BitReader<'a>) -> Self {
+ Self {
+ br,
+ rice_x: RiceParams::new(),
+ rice_y: RiceParams::new(),
+ }
+ }
+}
+
+struct ARangeCoder<'a> {
+ src: &'a [u8],
+ pos: usize,
+ low: u32,
+ range: u32,
+ help: u32,
+ buffer: u32,
+ error: bool,
+}
+
+pub struct RangeCoder<'a> {
+ rc: ARangeCoder<'a>,
+ rice_x: RiceParams,
+ rice_y: RiceParams,
+}
+
+impl<'a> RangeCoder<'a> {
+ pub fn new(src: &'a [u8]) -> Self {
+ Self {
+ rc: ARangeCoder::new(src),
+ rice_x: RiceParams::new(),
+ rice_y: RiceParams::new(),
+ }
+ }
+ fn had_errors(&self) -> bool { self.rc.error }
+}
+
+const RANGE_BITS: u8 = 32;
+const TOP: u32 = 1 << (RANGE_BITS - 1);
+const BOTTOM: u32 = TOP >> 8;
+const START_BITS: u8 = ((RANGE_BITS - 2) & 7) + 1;
+
+const MAX_MODEL_VAL: u32 = 63;
+
+impl<'a> ARangeCoder<'a> {
+ fn new(src: &'a [u8]) -> Self {
+ let buffer = u32::from(src[0]);
+ Self {
+ src: &src[1..],
+ pos: 0,
+ low: buffer >> (8 - START_BITS),
+ range: 1 << START_BITS,
+ help: 0,
+ buffer,
+ error: false,
+ }
+ }
+ fn reset(&mut self) {
+ if self.pos == 0 {
+ self.error = true;
+ } else {
+ self.pos -= 1;
+ }
+ if self.pos < self.src.len() - 1 {
+ self.buffer = u32::from(self.src[self.pos]);
+ self.pos += 1;
+ }
+ self.low = self.buffer >> (8 - START_BITS);
+ self.range = 1 << START_BITS;
+ self.help = 0;
+ }
+ fn normalise(&mut self) {
+ while self.range <= BOTTOM {
+ self.buffer <<= 8;
+ if self.pos < self.src.len() {
+ self.buffer |= u32::from(self.src[self.pos]);
+ self.pos += 1;
+ } else {
+ self.error = true;
+ }
+ self.low <<= 8;
+ self.low |= (self.buffer >> 1) & 0xFF;
+ self.range <<= 8;
+ }
+ }
+ fn get_freq(&mut self, freq: u32) -> u32 {
+ self.normalise();
+ self.help = self.range / freq;
+ self.low / self.help
+ }
+ fn get_bits(&mut self, bits: u8) -> u32 {
+ self.normalise();
+ self.help = self.range >> bits;
+ self.low / self.help
+ }
+ fn update(&mut self, interval: u32, low: u32) {
+ self.low -= self.help * low;
+ self.range = self.help * interval;
+ }
+ fn decode_freq(&mut self, freq: u32) -> u32 {
+ let sym = self.get_freq(freq);
+ self.update(1, sym);
+ sym
+ }
+ fn decode_bits(&mut self, bits: u8) -> u32 {
+ let sym = self.get_bits(bits);
+ self.update(1, sym);
+ sym
+ }
+ fn decode_symbol(&mut self, freqs: &[u32; 22]) -> u32 {
+ let bits = self.get_bits(16);
+ if bits > 65492 {
+ let sym = bits + MAX_MODEL_VAL - 65535;
+ self.update(1, bits);
+ if bits > 65536 {
+ self.error = true;
+ }
+ sym
+ } else {
+ let mut sym = 0usize;
+ while freqs[sym + 1] <= bits {
+ sym += 1;
+ }
+ self.update(freqs[sym + 1] - freqs[sym], freqs[sym]);
+ sym as u32
+ }
+ }
+}
+
+pub enum Coder<'a> {
+ Rice(RiceCoder<'a>),
+ Range(RangeCoder<'a>),
+}
+
+fn to_signed(val: u32) -> i32 {
+ if (val & 1) != 0 {
+ (val >> 1) as i32 + 1
+ } else {
+ -((val >> 1) as i32)
+ }
+}
+
+pub fn decode_mono_dummy(_c: &mut Coder, _l: &mut [i32]) -> DecoderResult<()> {
+ unreachable!();
+}
+pub fn decode_stereo_dummy(_c: &mut Coder, _l: &mut [i32], _r: &mut [i32]) -> DecoderResult<()> {
+ unreachable!();
+}
+
+fn new_k(val: u32) -> u8 {
+ (32 - (val | 1).leading_zeros()) as u8
+}
+fn rice_limit(k: u8) -> u32 { if k > 0 { 1 << (k + 4) } else { 0 } }
+fn decode_channel_0000(br: &mut BitReader, dst: &mut [i32]) -> DecoderResult<()> {
+ let (part01, part2) = dst.split_at_mut(64);
+ let (part0, part1) = part01.split_at_mut(5);
+ let mut pos = 0;
+ let mut last = [0u32; 64];
+ let mut sum = 0;
+ for el in part0.iter_mut() {
+ let val = br.read_code(UintCodeType::Rice(10))?;
+ sum += val;
+ *el = to_signed(val);
+ last[pos] = val;
+ pos += 1;
+ }
+ if part1.is_empty() {
+ return Ok(());
+ }
+ let mut k = new_k(sum / 10);
+ let mut w = 12;
+ for el in part1.iter_mut() {
+ let val = br.read_code(UintCodeType::Rice(k))?;
+ sum += val;
+ *el = to_signed(val);
+ k = new_k(sum / w);
+ w += 2;
+ last[pos] = val;
+ pos += 1;
+ }
+ if part2.is_empty() {
+ return Ok(());
+ }
+ let mut top_limit = rice_limit(k + 1) * 4;
+ let mut bot_limit = rice_limit(k) * 4;
+ pos = 0;
+ for el in part2.iter_mut() {
+ let val = br.read_code(UintCodeType::Rice(k))?;
+ *el = to_signed(val);
+
+ sum = sum.wrapping_add(val.wrapping_sub(last[pos]));
+ while sum < bot_limit {
+ k -= 1;
+ bot_limit = rice_limit(k) * 4;
+ top_limit >>= 1;
+ }
+ while sum >= top_limit {
+ k += 1;
+ validate!(k < 24);
+ bot_limit = rice_limit(k) * 4;
+ top_limit <<= 1;
+ }
+
+ last[pos] = val;
+ pos = (pos + 1) & 63;
+ }
+
+ Ok(())
+}
+pub fn decode_mono_0000(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Rice(ref mut rr) = c {
+ decode_channel_0000(&mut rr.br, l)
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_0000(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Rice(ref mut rr) = c {
+ decode_channel_0000(&mut rr.br, l)?;
+ decode_channel_0000(&mut rr.br, r)?;
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+
+fn decode_value_3860(br: &mut BitReader, rice: &mut RiceParams) -> DecoderResult<i32> {
+ let overflow = br.read_code(UintCodeType::UnaryZeroes)?;
+
+ let val = (overflow << rice.k) | br.read(rice.k)?;
+ rice.update_old(val);
+ Ok(to_signed(val))
+}
+fn decode_value_3890(br: &mut BitReader, rice: &mut RiceParams) -> DecoderResult<i32> {
+ let mut overflow = br.read_code(UintCodeType::UnaryZeroes)?;
+ while overflow >= 16 {
+ overflow -= 16;
+ rice.k += 4;
+ }
+
+ let val = (overflow << rice.k) | br.read(rice.k)?;
+ rice.update_old(val);
+ Ok(to_signed(val))
+}
+pub fn decode_mono_3860(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Rice(ref mut rr) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3860(&mut rr.br, &mut rr.rice_y)?;
+ }
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_mono_3890(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Rice(ref mut rr) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3860(&mut rr.br, &mut rr.rice_y)?;
+ }
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_3860(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Rice(ref mut rr) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3860(&mut rr.br, &mut rr.rice_y)?;
+ }
+ for el in r.iter_mut() {
+ *el = decode_value_3860(&mut rr.br, &mut rr.rice_x)?;
+ }
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_3890(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Rice(ref mut rr) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3890(&mut rr.br, &mut rr.rice_y)?;
+ }
+ for el in r.iter_mut() {
+ *el = decode_value_3890(&mut rr.br, &mut rr.rice_x)?;
+ }
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+
+const COUNTS_3900: &[u32; 22] = &[
+ 0, 14824, 28224, 39348, 47855, 53994, 58171, 60926,
+ 62682, 63786, 64463, 64878, 65126, 65276, 65365, 65419,
+ 65450, 65469, 65480, 65487, 65491, 65493
+];
+fn decode_value_3900(rc: &mut ARangeCoder, rice: &mut RiceParams) -> i32 {
+ let mut overflow = rc.decode_symbol(COUNTS_3900);
+ let k = if overflow == MAX_MODEL_VAL {
+ overflow = 0;
+ rc.decode_bits(5) as u8
+ } else {
+ rice.k.saturating_sub(1)
+ };
+ let base = rc.decode_bits(k);
+ let val = base + (overflow << k);
+ rice.update(val);
+ to_signed(val)
+}
+fn decode_value_3910(rc: &mut ARangeCoder, rice: &mut RiceParams) -> i32 {
+ let mut overflow = rc.decode_symbol(COUNTS_3900);
+ let k = if overflow == MAX_MODEL_VAL {
+ overflow = 0;
+ rc.decode_bits(5) as u8
+ } else {
+ rice.k.saturating_sub(1)
+ };
+ let base = if k <= 16 {
+ rc.decode_bits(k)
+ } else if k <= 32 {
+ let low = rc.decode_bits(k);
+ let high = rc.decode_bits(k - 16);
+ (high << (k - 16)) | low
+ } else {
+ rc.error = true;
+ return 0;
+ };
+ let val = base + (overflow << k);
+ rice.update(val);
+ to_signed(val)
+}
+pub fn decode_mono_3900(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3900(&mut rc.rc, &mut rc.rice_y);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_mono_3910(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3910(&mut rc.rc, &mut rc.rice_y);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_3900(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3900(&mut rc.rc, &mut rc.rice_y);
+ }
+ rc.rc.normalise();
+ validate!(!rc.had_errors() && rc.rc.pos < rc.rc.src.len());
+ rc.rc.reset();
+ for el in r.iter_mut() {
+ *el = decode_value_3900(&mut rc.rc, &mut rc.rice_x);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_3910(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3910(&mut rc.rc, &mut rc.rice_y);
+ }
+ rc.rc.normalise();
+ validate!(!rc.had_errors() && rc.rc.pos < rc.rc.src.len());
+ rc.rc.reset();
+ for el in r.iter_mut() {
+ *el = decode_value_3910(&mut rc.rc, &mut rc.rice_x);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_3930(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+ *l = decode_value_3910(&mut rc.rc, &mut rc.rice_y);
+ *r = decode_value_3910(&mut rc.rc, &mut rc.rice_x);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+
+const COUNTS_3990: &[u32; 22] = &[
+ 0, 19578, 36160, 48417, 56323, 60899, 63265, 64435,
+ 64971, 65232, 65351, 65416, 65447, 65466, 65476, 65482,
+ 65485, 65488, 65490, 65491, 65492, 65493
+];
+fn decode_value_3990(rc: &mut ARangeCoder, rice: &mut RiceParams) -> i32 {
+ let pivot = (rice.sum >> 5).max(1);
+ let mut overflow = rc.decode_symbol(COUNTS_3990);
+ if overflow == MAX_MODEL_VAL {
+ overflow = rc.decode_bits(16) << 16;
+ overflow |= rc.decode_bits(16);
+ }
+ let base = if pivot < (1 << 16) {
+ rc.decode_freq(pivot)
+ } else {
+ let shift = (16 - pivot.trailing_zeros()) as u8;
+ let hi = rc.decode_freq((pivot >> shift) + 1);
+ let lo = rc.decode_bits(shift);
+ (hi << shift) | lo
+ };
+ let val = base + overflow * pivot;
+ rice.update(val);
+ to_signed(val)
+}
+pub fn decode_mono_3990(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for el in l.iter_mut() {
+ *el = decode_value_3990(&mut rc.rc, &mut rc.rice_y);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
+pub fn decode_stereo_3990(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+ if let Coder::Range(ref mut rc) = c {
+ for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+ *l = decode_value_3990(&mut rc.rc, &mut rc.rice_y);
+ *r = decode_value_3990(&mut rc.rc, &mut rc.rice_x);
+ }
+ validate!(!rc.had_errors());
+ Ok(())
+ } else {
+ Err(DecoderError::Bug)
+ }
+}
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+const MAX_SAMPLES: usize = 32768;
+
+#[derive(Clone,Copy,PartialEq)]
+enum StereoMode {
+ Normal,
+ LeftSide,
+ SideRight,
+ MidSide,
+}
+
+struct FlacDecoder {
+ ainfo: NAAudioInfo,
+ chmap: NAChannelMap,
+ min_blk_size: usize,
+ max_blk_size: usize,
+ min_frm_size: usize,
+ max_frm_size: usize,
+ channels: u8,
+ bits: u8,
+ srate: u32,
+ residues: [Vec<i32>; 8],
+}
+
+fn decode_partition(br: &mut BitReader, dst: &mut [i32], k: u8) -> DecoderResult<()> {
+ for el in dst.iter_mut() {
+ let val = br.read_code(UintCodeType::Rice(k))?;
+ if (val & 1) == 0 {
+ *el = (val >> 1) as i32;
+ } else {
+ *el = -(((val + 1) >> 1) as i32);
+ }
+ }
+ Ok(())
+}
+
+fn decode_residual(br: &mut BitReader, dst: &mut [i32], order: usize) -> DecoderResult<()> {
+ let mode = br.read(2)?;
+ validate!(mode < 2);
+ let rice_k = if mode == 0 { 4 } else { 5 };
+ let esc = (1 << rice_k) - 1;
+
+ let num_partitions = 1 << br.read(4)?;
+ let tot_size = dst.len() + order;
+ validate!((tot_size % num_partitions) == 0);
+ let psize = tot_size / num_partitions;
+ validate!(psize >= order);
+ let mut off = psize - order;
+ let k = br.read(rice_k)? as u8;
+ if k != esc {
+ decode_partition(br, &mut dst[..off], k)?;
+ } else {
+ let bits = br.read(5)? as u8;
+ for el in dst.iter_mut().take(off) {
+ *el = br.read_s(bits)?;
+ }
+ }
+ for _ in 1..num_partitions {
+ let k = br.read(rice_k)? as u8;
+ if k != esc {
+ decode_partition(br, &mut dst[off..][..psize], k)?;
+ } else {
+ let bits = br.read(5)? as u8;
+ for el in dst[off..].iter_mut().take(psize) {
+ *el = br.read_s(bits)?;
+ }
+ }
+ off += psize;
+ }
+
+ Ok(())
+}
+
+fn apply_fixed_predictor(dst: &mut [i32], order: usize) {
+ match order {
+ 1 => {
+ let mut last = dst[0];
+ for el in dst.iter_mut().skip(1) {
+ *el += last;
+ last = *el;
+ }
+ },
+ 2 => {
+ let mut last0 = dst[1];
+ let mut last1 = last0 - dst[0];
+ for el in dst.iter_mut().skip(2) {
+ last1 += *el;
+ last0 += last1;
+ *el = last0;
+ }
+ },
+ 3 => {
+ let mut last0 = dst[2];
+ let mut last1 = last0 - dst[1];
+ let mut last2 = last1 - dst[1] + dst[0];
+ for el in dst.iter_mut().skip(3) {
+ last2 += *el;
+ last1 += last2;
+ last0 += last1;
+ *el = last0;
+ }
+ },
+ 4 => {
+ let mut last0 = dst[3];
+ let mut last1 = last0 - dst[2];
+ let mut last2 = last1 - dst[2] + dst[1];
+ let mut last3 = last2 - dst[2] + 2 * dst[1] - dst[0];
+ for el in dst.iter_mut().skip(4) {
+ last3 += *el;
+ last2 += last3;
+ last1 += last2;
+ last0 += last1;
+ *el = last0;
+ }
+ },
+ _ => unreachable!(),
+ };
+}
+
+fn apply_lpc(dst: &mut [i32], filt: &[i32; 16], order: usize, shift: u8) {
+ for i in order..dst.len() {
+ let mut sum = 0i64;
+ for (coef, filt) in dst[i - order..].iter().take(order).zip(filt.iter()) {
+ sum += i64::from(*coef) * i64::from(*filt);
+ }
+ dst[i] += (sum >> shift) as i32;
+ }
+}
+
+impl FlacDecoder {
+ fn new() -> Self {
+ Self {
+ ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+ chmap: NAChannelMap::new(),
+ min_blk_size: 0,
+ max_blk_size: 0,
+ min_frm_size: 0,
+ max_frm_size: 0,
+ channels: 0,
+ bits: 0,
+ srate: 0,
+ residues: [vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES],
+ vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES],
+ vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES],
+ vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES]],
+ }
+ }
+ fn apply_chmod(&mut self, blocksize: usize, chmod: StereoMode) {
+ match chmod {
+ StereoMode::Normal => {},
+ StereoMode::LeftSide => {
+ for i in 0..blocksize {
+ self.residues[1][i] = self.residues[0][i].wrapping_sub(self.residues[1][i]);
+ }
+ },
+ StereoMode::SideRight => {
+ for i in 0..blocksize {
+ self.residues[0][i] = self.residues[0][i].wrapping_add(self.residues[1][i]);
+ }
+ },
+ StereoMode::MidSide => {
+ for i in 0..blocksize {
+ let r = self.residues[0][i].wrapping_sub(self.residues[1][i] >> 1);
+ self.residues[0][i] = self.residues[1][i].wrapping_add(r);
+ self.residues[1][i] = r;
+ }
+ },
+ };
+ }
+ fn decode_subframe(&mut self, br: &mut BitReader, channel: usize, blocksize: usize, mut samp_bits: u8) -> DecoderResult<()> {
+ let marker = br.read(1)?;
+ validate!(marker == 0);
+ let sftype = br.read(6)?;
+
+ if br.read_bool()? {
+ let nbits = br.read_code(UintCodeType::UnaryZeroes)?;
+ validate!(nbits < 32 && samp_bits > nbits as u8);
+ samp_bits -= nbits as u8;
+ }
+
+ let dst = &mut self.residues[channel][..blocksize];
+ match sftype {
+ 0x00 => {
+ let val = br.read_s(samp_bits)?;
+ for el in dst.iter_mut() {
+ *el = val;
+ }
+ },
+ 0x01 => {
+ for el in dst.iter_mut() {
+ *el = br.read_s(samp_bits)?;
+ }
+ },
+ 0x08..=0x0C => {
+ let order = (sftype - 0x08) as usize;
+ for el in dst.iter_mut().take(order) {
+ *el = br.read_s(samp_bits)?;
+ }
+ decode_residual(br, &mut dst[order..], order)?;
+ if order > 0 {
+ apply_fixed_predictor(dst, order);
+ }
+ },
+ 0x20..=0x3F => {
+ let order = (sftype - 0x20) as usize + 1;
+ for el in dst.iter_mut().take(order) {
+ *el = br.read_s(samp_bits)?;
+ }
+ let precision = br.read(4)? as u8 + 1;
+ validate!(precision < 16);
+ let shift = br.read(5)? as u8;
+ let mut filter = [0i32; 16];
+ for el in filter[..order].iter_mut().rev() {
+ *el = br.read_s(precision)?;
+ }
+ decode_residual(br, &mut dst[order..], order)?;
+ apply_lpc(dst, &filter, order, shift);
+ },
+ _ => return Err(DecoderError::InvalidData),
+ };
+
+ Ok(())
+ }
+}
+
+impl NADecoder for FlacDecoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ const DEFAULT_CHANNEL_MAPS: [&str; 8] = [
+ "C",
+ "L,R",
+ "L,R,C",
+ "L,R,Ls,Rs",
+ "L,R,C,Ls,Rs",
+ "L,R,C,LFE,Ls,Rs",
+ "L,R,C,LFE,Cs,Ls,Rs",
+ "L,R,C,LFE,Ls,Rs,Lss,Rss"
+ ];
+ if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+ if let Some(buf) = info.get_extradata() {
+ validate!(buf.len() >= 22);
+
+ let mut mr = MemoryReader::new_read(&buf);
+ let mut br = ByteReader::new(&mut mr);
+
+ self.min_blk_size = br.read_u16be()? as usize;
+ self.max_blk_size = br.read_u16be()? as usize;
+ self.min_frm_size = br.read_u24be()? as usize;
+ self.max_frm_size = br.read_u24be()? as usize;
+ let tmp = br.read_u64be()?;
+ self.srate = (tmp >> 44) as u32;
+ self.channels = (((tmp >> 41) & 7) + 1) as u8;
+ self.bits = (((tmp >> 36) & 0x1F) + 1) as u8;
+ //let tot_samples = tmp & ((1 << 36) - 1);
+
+ self.chmap = NAChannelMap::from_str(DEFAULT_CHANNEL_MAPS[(self.channels - 1) as usize]).unwrap();
+ let fmt = match self.bits {
+ 8 | 12 | 16 => SND_S16P_FORMAT,
+ 24 => SND_S32P_FORMAT,
+ _ => return Err(DecoderError::NotImplemented),
+ };
+
+ self.ainfo = NAAudioInfo::new(self.srate, self.channels as u8, fmt, self.max_blk_size.max(1));
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+ let pktbuf = pkt.get_buffer();
+ validate!(pktbuf.len() >= 9.max(self.min_frm_size));
+
+ let ref_crc = read_u16be(&pktbuf[pktbuf.len() - 2..]).unwrap_or(0);
+ let mut crc = 0;
+ for el in pktbuf.iter().take(pktbuf.len() - 2) {
+ crc = update_crc16(crc, *el);
+ }
+ if crc != ref_crc {
+ return Err(DecoderError::ChecksumError);
+ }
+
+ let mut br = BitReader::new(&pktbuf, BitReaderMode::BE);
+
+ let sync = br.read(14)?;
+ validate!(sync == 0x3FFE);
+ br.skip(1)?;
+ let _blocking = br.read(1)?;
+ let bsize_idx = br.read(4)?;
+ let srate_idx = br.read(4)?;
+ let chan_idx = br.read(4)?;
+ let bits_idx = br.read(3)?;
+ br.skip(1)?;
+ // UTF-8 encoded block or sample number
+ let byte = br.read(8)? as u8;
+ let len = (!byte).leading_zeros();
+ validate!(len <= 5 && len != 1);
+ if len > 1 {
+ for _ in 1..len {
+ let byte = br.read(8)?;
+ validate!((byte & 0xC0) == 0x80);
+ }
+ }
+ let blocksize = match bsize_idx {
+ 0 => return Err(DecoderError::InvalidData),
+ 1 => 192,
+ 2..=5 => 576 << (bsize_idx - 2),
+ 6 => br.read(8)? as usize + 1,
+ 7 => br.read(16)? as usize + 1,
+ _ => 256 << (bsize_idx - 8),
+ };
+ let srate = match srate_idx {
+ 0 => self.srate,
+ 1 => 88200,
+ 2 => 176400,
+ 3 => 192000,
+ 4 => 8000,
+ 5 => 16000,
+ 6 => 22050,
+ 7 => 24000,
+ 8 => 32000,
+ 9 => 44100,
+ 10 => 48000,
+ 11 => 96000,
+ 12 => br.read(8)? * 1000,
+ 13 => br.read(16)?,
+ 14 => br.read(16)? * 10,
+ _ => return Err(DecoderError::InvalidData),
+ };
+ validate!(srate != 0 && srate == self.srate);
+ let (channels, chmod) = match chan_idx {
+ 0..=7 => (chan_idx as u8 + 1, StereoMode::Normal),
+ 8 => (2, StereoMode::LeftSide),
+ 9 => (2, StereoMode::SideRight),
+ 10 => (2, StereoMode::MidSide),
+ _ => return Err(DecoderError::InvalidData),
+ };
+ validate!(channels == self.channels);
+ let bits = match bits_idx {
+ 0 => self.bits,
+ 1 => 8,
+ 2 => 12,
+ 4 => 16,
+ 5 => 20,
+ 6 => 24,
+ _ => return Err(DecoderError::InvalidData),
+ };
+ validate!(bits == self.bits);
+
+ let end = br.tell() / 8;
+ let ref_crc = br.read(8)? as u8;
+ let mut crc = 0;
+ for el in pktbuf.iter().take(end) {
+ crc = update_crc8(crc, *el);
+ }
+ if crc != ref_crc {
+ return Err(DecoderError::ChecksumError);
+ }
+
+ for ch in 0..(channels as usize) {
+ let samp_bits = match (chmod, ch) {
+ (StereoMode::LeftSide, 1) |
+ (StereoMode::SideRight, 0) |
+ (StereoMode::MidSide, 1) => self.bits + 1,
+ _ => self.bits,
+ };
+ validate!(samp_bits <= 32);
+ self.decode_subframe(&mut br, ch, blocksize, samp_bits)?;
+ }
+ if channels == 2 {
+ self.apply_chmod(blocksize, chmod);
+ }
+
+ let mut abuf = alloc_audio_buffer(self.ainfo, blocksize, self.chmap.clone())?;
+ let postshift = if self.bits == 24 { 8 } else { 16 - self.bits };
+ match abuf {
+ NABufferType::AudioI16(ref mut adata) => {
+ let stride = adata.get_stride();
+ let dst = adata.get_data_mut().unwrap();
+ let mut off = 0;
+ for residues in self.residues.iter().take(channels as usize) {
+ let dst = &mut dst[off..][..blocksize];
+ for (dst, src) in dst.iter_mut().zip(residues.iter()) {
+ *dst = (*src << postshift) as i16;
+ }
+ off += stride;
+ }
+ },
+ NABufferType::AudioI32(ref mut adata) => {
+ let stride = adata.get_stride();
+ let dst = adata.get_data_mut().unwrap();
+ let mut off = 0;
+ for residues in self.residues.iter().take(channels as usize) {
+ let dst = &mut dst[off..][..blocksize];
+ for (dst, src) in dst.iter_mut().zip(residues.iter()) {
+ *dst = *src << postshift;
+ }
+ off += stride;
+ }
+ },
+ _ => unreachable!(),
+ };
+
+ let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+ frm.set_duration(Some(blocksize as u64));
+ Ok(frm.into_ref())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for FlacDecoder {
+ 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() -> Box<dyn NADecoder + Send> {
+ Box::new(FlacDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::llaudio_register_all_decoders;
+ use crate::llaudio_register_all_demuxers;
+ #[test]
+ fn test_flac() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("flac", "flac", "assets/LLaudio/luckynight.flac", Some(6), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xe689787a, 0x032a98f7, 0xeb6e64f4, 0xfa652132]));
+ }
+}
+
+fn update_crc8(crc: u8, byte: u8) -> u8 {
+ CRC8_TABLE[(crc ^ byte) as usize]
+}
+
+fn update_crc16(crc: u16, byte: u8) -> u16 {
+ (crc << 8) ^ CRC16_TABLE[(((crc >> 8) as u8) ^ byte) as usize]
+}
+
+const CRC8_TABLE: [u8; 256] = [
+ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+ 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+ 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+ 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+ 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+ 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+ 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+ 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+ 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+ 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+ 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+ 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+ 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+ 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+ 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+ 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+ 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+];
+
+const CRC16_TABLE: [u16; 256] = [
+ 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
+ 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
+ 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
+ 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
+ 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
+ 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
+ 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
+ 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
+ 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
+ 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
+ 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
+ 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
+ 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
+ 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
+ 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
+ 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
+ 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
+];
--- /dev/null
+use nihav_core::codecs::*;
+
+macro_rules! validate {
+ ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DecoderError::InvalidData); } };
+}
+
+#[cfg(feature="decoder_ape")]
+pub mod ape;
+#[cfg(feature="decoder_ape")]
+mod apepred;
+#[cfg(feature="decoder_ape")]
+mod apereader;
+
+#[cfg(feature="decoder_flac")]
+pub mod flac;
+
+#[cfg(feature="decoder_tta")]
+pub mod tta;
+
+#[cfg(feature="decoder_wavpack")]
+pub mod wavpack;
+
+const LL_AUDIO_CODECS: &[DecoderInfo] = &[
+#[cfg(feature="decoder_ape")]
+ DecoderInfo { name: "ape", get_decoder: ape::get_decoder },
+#[cfg(feature="decoder_flac")]
+ DecoderInfo { name: "flac", get_decoder: flac::get_decoder },
+#[cfg(feature="decoder_tta")]
+ DecoderInfo { name: "tta", get_decoder: tta::get_decoder },
+#[cfg(feature="decoder_wavpack")]
+ DecoderInfo { name: "wavpack", get_decoder: wavpack::get_decoder },
+];
+
+/// Registers all available codecs provided by this crate.
+pub fn llaudio_register_all_decoders(rd: &mut RegisteredDecoders) {
+ for decoder in LL_AUDIO_CODECS.iter() {
+ rd.add_decoder(decoder.clone());
+ }
+}
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+#[derive(Default)]
+struct Filter {
+ predictor: i32,
+ error: i32,
+ round: i32,
+ shift: u8,
+ qm: [i32; 8],
+ dx: [i32; 8],
+ dl: [i32; 8],
+}
+
+impl Filter {
+ fn reset(&mut self, bpp: u8) {
+ const SHIFTS: [u8; 3] = [10, 9, 10];
+ self.shift = SHIFTS[(bpp - 1) as usize];
+ self.round = (1 << self.shift) >> 1;
+ self.error = 0;
+ self.qm = [0; 8];
+ self.dx = [0; 8];
+ self.dl = [0; 8];
+ self.predictor = 0;
+ }
+ fn hybrid_filt(&mut self, delta: i32) -> i32 {
+ if self.error < 0 {
+ for (qm, dx) in self.qm.iter_mut().zip(self.dx.iter()) {
+ *qm -= *dx;
+ }
+ } else if self.error > 0 {
+ for (qm, dx) in self.qm.iter_mut().zip(self.dx.iter()) {
+ *qm += *dx;
+ }
+ }
+
+ let mut sum = self.round;
+ for (dl, qm) in self.dl.iter().zip(self.qm.iter()) {
+ sum = sum.wrapping_add(*dl * *qm);
+ }
+ self.error = delta;
+ let val = (sum >> self.shift) + delta;
+
+ for i in 0..4 {
+ self.dx[i] = self.dx[i + 1];
+ self.dl[i] = self.dl[i + 1];
+ }
+ self.dx[4] = (self.dl[4] >> 30) | 1;
+ self.dx[5] = ((self.dl[5] >> 30) | 2) & !1;
+ self.dx[6] = ((self.dl[6] >> 30) | 2) & !1;
+ self.dx[7] = ((self.dl[7] >> 30) | 4) & !3;
+ self.dl[4] = -self.dl[5];
+ self.dl[5] = -self.dl[6];
+ self.dl[6] = val - self.dl[7];
+ self.dl[7] = val;
+ self.dl[5] += self.dl[6];
+ self.dl[4] += self.dl[5];
+
+ val
+ }
+ fn static_pred(&mut self, bpp: u8, mut val: i32) -> i32 {
+ val += match bpp {
+ 0 => ((i64::from(self.predictor) * 15) >> 4) as i32,
+ 1 | 2 => ((i64::from(self.predictor) * 31) >> 5) as i32,
+ _ => self.predictor,
+ };
+ self.predictor = val;
+ val
+ }
+}
+
+struct RiceDecoder {
+ k: u8,
+ sum: u32,
+}
+
+impl RiceDecoder {
+ fn new() -> Self {
+ let k = 10;
+ Self {
+ k, sum: RiceDecoder::limit(k)
+ }
+ }
+ fn reset(&mut self) {
+ self.k = 10;
+ self.sum = RiceDecoder::limit(self.k);
+ }
+ fn limit(k: u8) -> u32 { 1 << (k + 4).min(31) }
+ fn update(&mut self, val: u32) {
+ self.sum -= self.sum >> 4;
+ self.sum += val;
+ if self.k > 0 && self.sum < Self::limit(self.k) {
+ self.k -= 1;
+ } else if self.sum > Self::limit(self.k + 1) {
+ self.k += 1;
+ }
+ }
+}
+
+trait Output {
+ fn set(&mut self, val: i32);
+}
+
+impl Output for i16 {
+ fn set(&mut self, val: i32) { *self = val as i16; }
+}
+impl Output for i32 {
+ fn set(&mut self, val: i32) { *self = val; }
+}
+
+struct ChannelDecoder {
+ filt: Filter,
+ rice0: RiceDecoder,
+ rice1: RiceDecoder,
+ offset: usize,
+ sample: i32,
+}
+
+impl ChannelDecoder {
+ fn new() -> Self {
+ Self {
+ filt: Filter::default(),
+ rice0: RiceDecoder::new(),
+ rice1: RiceDecoder::new(),
+ offset: 0,
+ sample: 0,
+ }
+ }
+}
+
+struct TTADecoder {
+ ainfo: NAAudioInfo,
+ chmap: NAChannelMap,
+ bpp: u8,
+ framelen: u32,
+ nsamples: u32,
+ ch_dec: Vec<ChannelDecoder>,
+}
+
+impl TTADecoder {
+ fn new() -> Self {
+ Self {
+ ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+ chmap: NAChannelMap::new(),
+ bpp: 0,
+ framelen: 0,
+ nsamples: 0,
+ ch_dec: Vec::new(),
+ }
+ }
+ fn decode_frame<T: Output>(&mut self, br: &mut BitReader, dst: &mut [T], stride: usize) -> DecoderResult<bool> {
+ for (i, chdec) in self.ch_dec.iter_mut().enumerate() {
+ chdec.offset = i * stride;
+ chdec.rice0.reset();
+ chdec.rice1.reset();
+ chdec.filt.reset(self.bpp);
+ }
+
+ let channels = self.ch_dec.len();
+ let tail_len = self.nsamples % self.framelen;
+
+ for sample in 0..self.framelen {
+ for chdec in self.ch_dec.iter_mut() {
+ let pfx = br.read_code(UintCodeType::UnaryOnes)?;
+ let (k, pfx, level1) = if pfx == 0 {
+ (chdec.rice0.k, 0, false)
+ } else {
+ (chdec.rice1.k, pfx - 1, true)
+ };
+ let mut val = (pfx << k) | br.read(k)?;
+ if level1 {
+ chdec.rice1.update(val);
+ val += 1 << chdec.rice0.k;
+ }
+ chdec.rice0.update(val);
+ let delta = if (val & 1) == 0 {
+ -((val >> 1) as i32)
+ } else {
+ ((val + 1) >> 1) as i32
+ };
+ let hval = chdec.filt.hybrid_filt(delta);
+ chdec.sample = chdec.filt.static_pred(self.bpp, hval);
+ }
+ if channels > 1 {
+ self.ch_dec[channels - 1].sample += self.ch_dec[channels - 2].sample / 2;
+ let mut last = self.ch_dec[channels - 1].sample;
+ for chdec in self.ch_dec.iter_mut().rev().skip(1) {
+ chdec.sample = last - chdec.sample;
+ last = chdec.sample;
+ }
+ }
+ for chdec in self.ch_dec.iter_mut() {
+ dst[chdec.offset].set(chdec.sample);
+ chdec.offset += 1;
+ }
+ if (tail_len > 0) && (sample == tail_len - 1) && (br.left() < 40) {
+ return Ok(false);
+ }
+ }
+
+ Ok(true)
+ }
+}
+
+fn check_crc(buf: &[u8]) -> bool {
+ if buf.len() <= 4 {
+ return false;
+ }
+ let mut crc = 0xFFFFFFFF;
+ let ref_crc = read_u32le(&buf[buf.len() - 4..]).unwrap_or(0);
+ for el in buf.iter().take(buf.len() - 4) {
+ crc = CRC32_TAB[(crc as u8 ^ *el) as usize] ^ (crc >> 8);
+ }
+ crc == !ref_crc
+}
+
+impl NADecoder for TTADecoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+ if let Some(buf) = info.get_extradata() {
+ if !check_crc(&buf) {
+ return Err(DecoderError::ChecksumError);
+ }
+ let mut mr = MemoryReader::new_read(&buf);
+ let mut br = ByteReader::new(&mut mr);
+ let tag = br.read_tag()?;
+ validate!(&tag == b"TTA1");
+ let afmt = br.read_u16le()?;
+ if afmt != 1 {
+ return Err(DecoderError::NotImplemented);
+ }
+ let channels = br.read_u16le()?;
+ validate!(channels > 0 && channels < 256);
+ let bpp = br.read_u16le()?;
+ validate!(bpp > 0 && bpp <= 32);
+ let srate = br.read_u32le()?;
+ validate!(srate > 256 && srate < 1048576);
+ self.nsamples = br.read_u32le()?;
+ validate!(self.nsamples > 0);
+
+ self.framelen = srate * 256 / 245;
+
+ self.chmap = if channels == 1 {
+ NAChannelMap::from_str("C").unwrap()
+ } else if channels == 2 {
+ NAChannelMap::from_str("L,R").unwrap()
+ } else {
+ return Err(DecoderError::NotImplemented);
+ };
+ let fmt = match bpp {
+ 8 | 16 => SND_S16P_FORMAT,
+ 24 | 32 => SND_S32P_FORMAT,
+ _ => return Err(DecoderError::NotImplemented),
+ };
+ self.bpp = (bpp / 8) as u8;
+ self.ch_dec = Vec::with_capacity(channels as usize);
+ for _ in 0..channels {
+ self.ch_dec.push(ChannelDecoder::new());
+ }
+
+ self.ainfo = NAAudioInfo::new(srate, channels as u8, fmt, self.framelen as usize);
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+ let pktbuf = pkt.get_buffer();
+ validate!(pktbuf.len() > 4);
+ if !check_crc(&pktbuf) {
+ return Err(DecoderError::ChecksumError);
+ }
+
+ let mut br = BitReader::new(&pktbuf, BitReaderMode::LE);
+
+ let mut abuf = alloc_audio_buffer(self.ainfo, self.framelen as usize, self.chmap.clone())?;
+ let duration = match abuf {
+ NABufferType::AudioI16(ref mut adata) => {
+ let stride = adata.get_stride();
+ let dst = adata.get_data_mut().unwrap();
+ let not_last = self.decode_frame(&mut br, dst, stride)?;
+ if not_last {
+ self.framelen
+ } else {
+ adata.truncate((self.nsamples % self.framelen) as usize);
+ self.nsamples % self.framelen
+ }
+ },
+ NABufferType::AudioI32(ref mut adata) => {
+ let stride = adata.get_stride();
+ let dst = adata.get_data_mut().unwrap();
+ let not_last = self.decode_frame(&mut br, dst, stride)?;
+ if not_last {
+ self.framelen
+ } else {
+ adata.truncate((self.nsamples % self.framelen) as usize);
+ self.nsamples % self.framelen
+ }
+ },
+ _ => unreachable!(),
+ };
+
+ let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+ frm.set_duration(Some(u64::from(duration)));
+ Ok(frm.into_ref())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for TTADecoder {
+ 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() -> Box<dyn NADecoder + Send> {
+ Box::new(TTADecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::llaudio_register_all_decoders;
+ use crate::llaudio_register_all_demuxers;
+ #[test]
+ fn test_tta() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("tta", "tta", "assets/LLaudio/luckynight.tta", Some(3), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xce0fe9c4, 0xa69eefda, 0xe182008c, 0xe941db3f]));
+ }
+}
+
+const CRC32_TAB: [u32; 256] = [
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+];
--- /dev/null
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+const SAMPLE_RATES: [u32; 15] = [
+ 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000, 192000
+];
+const WV_FLAG_MONO: u32 = 1 << 2;
+const WV_FLAG_HYBRID: u32 = 1 << 3;
+const WV_FLAG_JSTEREO: u32 = 1 << 4;
+//const WV_FLAG_CH_DECORR: u32 = 1 << 5;
+//const WV_FLAG_HYB_NOISE_SHAPING: u32 = 1 << 6;
+const WV_FLAG_FLOATS: u32 = 1 << 7;
+const WV_FLAG_EXT_INTEGERS: u32 = 1 << 8;
+const WV_FLAG_HYB_BITRATE: u32 = 1 << 9;
+//const WV_FLAG_HYB_BALANCED_NOISE: u32 = 1 << 10;
+const WV_FLAG_START_BLOCK: u32 = 1 << 11;
+const WV_FLAG_END_BLOCK: u32 = 1 << 12;
+//const WV_FLAG_HAS_CRC: u32 = 1 << 28;
+const WV_FLAG_FALSE_STEREO: u32 = 1 << 30;
+const WV_FLAG_DSD_AUDIO: u32 = 1 << 31;
+
+const WV_STREAM_FLAGS: u32 = 0x8000018B;
+
+#[derive(Clone,Copy,Default)]
+struct WVHeader {
+ size: usize,
+ ver: u16,
+ tot_samples: u64,
+ block_index: u64,
+ block_samples: u32,
+ flags: u32,
+ crc: u32,
+}
+
+const WV_HEADER_SIZE: usize = 32;
+
+impl WVHeader {
+ fn parse(src: &[u8]) -> DecoderResult<Self> {
+ let mut mr = MemoryReader::new_read(src);
+ let mut br = ByteReader::new(&mut mr);
+ let tag = br.read_tag()?;
+ validate!(&tag == b"wvpk");
+ let mut hdr = Self::default();
+ hdr.size = br.read_u32le()? as usize;
+ validate!(hdr.size >= 24);
+ hdr.ver = br.read_u16le()?;
+ validate!(hdr.ver >= 0x402 || hdr.ver <= 0x410);
+ let top_idx = br.read_byte()?;
+ let top_samps = br.read_byte()?;
+ hdr.tot_samples = u64::from(br.read_u32le()?) | (u64::from(top_samps) << 32);
+ hdr.block_index = u64::from(br.read_u32le()?) | (u64::from(top_idx) << 32);
+ hdr.block_samples = br.read_u32le()?;
+ hdr.flags = br.read_u32le()?;
+ hdr.crc = br.read_u32le()?;
+ Ok(hdr)
+ }
+ fn stream_eq(&self, rval: &Self) -> bool {
+ self.ver == rval.ver &&
+ (self.flags & WV_STREAM_FLAGS) == (rval.flags & WV_STREAM_FLAGS)
+ }
+ fn block_eq(&self, rval: &Self) -> bool {
+ self.stream_eq(rval) && self.block_index == rval.block_index &&
+ self.tot_samples == rval.tot_samples &&
+ self.block_samples == rval.block_samples
+ }
+ fn is_start_block(&self) -> bool {
+ (self.flags & WV_FLAG_START_BLOCK) != 0
+ }
+ fn is_end_block(&self) -> bool {
+ (self.flags & WV_FLAG_END_BLOCK) != 0
+ }
+ fn get_num_channels(&self) -> u8 {
+ if (self.flags & WV_FLAG_MONO) != 0 && (self.flags & WV_FLAG_FALSE_STEREO) == 0 { 1 } else { 2 }
+ }
+ fn get_sample_rate(&self) -> u32 {
+ let idx = ((self.flags >> 23) & 0xF) as usize;
+ if idx != 15 {
+ SAMPLE_RATES[idx]
+ } else {
+ 0
+ }
+ }
+ fn get_size(&self) -> usize {
+ self.size - (WV_HEADER_SIZE - 8)
+ }
+ fn get_bits(&self) -> u8 {
+ (((self.flags & 3) + 1) * 8) as u8
+ }
+}
+
+fn wv_log2lin(val: i32) -> i32 {
+ let sign = val < 0;
+ let aval = val.abs();
+ let mant = 0x100 | i32::from(WV_EXP_TABLE[(aval & 0xFF) as usize]);
+ let exp = aval >> 8;
+ let aval = if exp >= 9 {
+ mant << (exp - 9)
+ } else {
+ mant >> (9 - exp)
+ };
+ if !sign {
+ aval
+ } else {
+ -aval
+ }
+}
+
+fn wv_lin2log(val: u32) -> u32 {
+ if val == 0 {
+ 0
+ } else if val == 1 {
+ 0x100
+ } else {
+ let val = val + (val >> 9);
+ let bits = 32 - val.leading_zeros();
+ if bits < 9 {
+ (bits << 8) + u32::from(WV_LOG_TABLE[((val << (9 - bits)) & 0xFF) as usize])
+ } else {
+ (bits << 8) + u32::from(WV_LOG_TABLE[((val >> (bits - 9)) & 0xFF) as usize])
+ }
+ }
+}
+
+#[derive(Clone,Copy,Default)]
+struct Decorrelator {
+ delta: i32,
+ value: i32,
+ weight_a: i32,
+ weight_b: i32,
+ samples_a: [i32; 8],
+ samples_b: [i32; 8],
+}
+
+impl Decorrelator {
+ fn decorrelate_mono(&mut self, l: i32, pos: usize) -> i32 {
+ let mode = self.value;
+ let (a, npos) = if mode > 8 {
+ let a = if (mode & 1) != 0 {
+ 2 * self.samples_a[0] - self.samples_a[1]
+ } else {
+ (3 * self.samples_a[0] - self.samples_a[1]) >> 1
+ };
+ self.samples_a[1] = self.samples_a[0];
+ (a, 0)
+ } else {
+ (self.samples_a[pos], (pos + mode as usize) & 7)
+ };
+ let l2 = l + ((i64::from(self.weight_a) * i64::from(a) + 512) >> 10) as i32;
+ if (a != 0) && (l != 0) {
+ self.weight_a -= ((((l ^ a) >> 30) & 2) - 1) * self.delta;
+ }
+ self.samples_a[npos] = l2;
+ l2
+ }
+ fn decorrelate_stereo(&mut self, l: i32, r: i32, pos: usize) -> (i32, i32) {
+ let mode = self.value;
+ if mode > 0 {
+ let (a, b, npos) = if mode > 8 {
+ let (a, b) = if (mode & 1) != 0 {
+ (2 * self.samples_a[0] - self.samples_a[1],
+ 2 * self.samples_b[0] - self.samples_b[1])
+ } else {
+ ((3 * self.samples_a[0] - self.samples_a[1]) >> 1,
+ (3 * self.samples_b[0] - self.samples_b[1]) >> 1)
+ };
+ self.samples_a[1] = self.samples_a[0];
+ self.samples_b[1] = self.samples_b[0];
+ (a, b, 0)
+ } else {
+ (self.samples_a[pos], self.samples_b[pos], (pos + mode as usize) & 7)
+ };
+ let l2 = l + ((i64::from(self.weight_a) * i64::from(a) + 512) >> 10) as i32;
+ let r2 = r + ((i64::from(self.weight_b) * i64::from(b) + 512) >> 10) as i32;
+ if (a != 0) && (l != 0) {
+ self.weight_a -= ((((l ^ a) >> 30) & 2) - 1) * self.delta;
+ }
+ if (b != 0) && (r != 0) {
+ self.weight_b -= ((((r ^ b) >> 30) & 2) - 1) * self.delta;
+ }
+ self.samples_a[npos] = l2;
+ self.samples_b[npos] = r2;
+ (l2, r2)
+ } else if mode == -1 {
+ let l2 = l + ((i64::from(self.weight_a) * i64::from(self.samples_a[0]) + 512) >> 10) as i32;
+ let r2 = r + ((i64::from(self.weight_b) * i64::from(l2) + 512) >> 10) as i32;
+ self.update_weight_a(self.samples_a[0], l);
+ self.update_weight_b(l2, r);
+ self.samples_a[0] = r2;
+ (l2, r2)
+ } else {
+ let r2 = r + ((i64::from(self.weight_b) * i64::from(self.samples_b[0]) + 512) >> 10) as i32;
+ self.update_weight_b(self.samples_b[0], r);
+ let rr = if mode == -3 {
+ let nr = self.samples_a[0];
+ self.samples_a[0] = r2;
+ nr
+ } else {
+ r2
+ };
+ let l2 = l + ((i64::from(self.weight_a) * i64::from(rr) + 512) >> 10) as i32;
+ self.update_weight_a(rr, l);
+ self.samples_b[0] = l2;
+ (l2, r2)
+ }
+ }
+ fn update_weight_a(&mut self, l: i32, r: i32) {
+ if (l != 0) && (r != 0) {
+ if (l ^ r) < 0 {
+ self.weight_a = (self.weight_a - self.delta).max(-1024)
+ } else {
+ self.weight_a = (self.weight_a + self.delta).min(1024)
+ }
+ }
+ }
+ fn update_weight_b(&mut self, l: i32, r: i32) {
+ if (l != 0) && (r != 0) {
+ if (l ^ r) < 0 {
+ self.weight_b = (self.weight_b - self.delta).max(-1024)
+ } else {
+ self.weight_b = (self.weight_b + self.delta).min(1024)
+ }
+ }
+ }
+}
+
+#[derive(Default)]
+struct DecState {
+ median: [[u32; 3]; 2],
+ zero: bool,
+ one: bool,
+ num_zeroes: u32,
+ ebits: u8,
+ shift: u8,
+ and: i32,
+ or: i32,
+ post_shift: u8,
+ slow_level: [u32; 2],
+ br_acc: [u32; 2],
+ br_delta: [u32; 2],
+ hyb_max: i32,
+ hyb_min: i32,
+ has_hbr: bool,
+ stereo: bool,
+ error_lim: [u32; 2],
+}
+
+fn read_biased_code(br: &mut BitReader) -> DecoderResult<u32> {
+ let val = br.read_code(UintCodeType::UnaryOnes)?;
+ validate!(val < 25);
+ if val < 2 {
+ Ok(val)
+ } else {
+ let bits = val - 1;
+ Ok((1 << bits) | br.read(bits as u8)?)
+ }
+}
+fn read_tail(br: &mut BitReader, bits: u32) -> DecoderResult<u32> {
+ if bits < 1 {
+ Ok(0)
+ } else {
+ let p = 31 - bits.leading_zeros();
+ let esc = (1 << (p + 1)) - (bits + 1);
+ let val = br.read(p as u8)?;
+ if val < esc {
+ Ok(val)
+ } else {
+ Ok(val * 2 - esc + br.read(1)?)
+ }
+ }
+}
+
+impl DecState {
+ fn read_sample(&mut self, br: &mut BitReader, channel: usize) -> DecoderResult<i32> {
+ if (self.median[0][0] < 2) && (self.median[1][0] < 2) && !self.zero && !self.one {
+ if self.num_zeroes > 0 {
+ self.num_zeroes -= 1;
+ if self.num_zeroes != 0 {
+ return Ok(0);
+ }
+ } else {
+ self.num_zeroes = read_biased_code(br)?;
+ if self.num_zeroes != 0 {
+ self.median = [[0; 3]; 2];
+ return Ok(0);
+ }
+ }
+ }
+ let val = if self.zero {
+ self.zero = false;
+ 0
+ } else {
+ let mut val = br.read_code(UintCodeType::UnaryOnes)?;
+ validate!(val <= 16);
+ if val == 16 {
+ val += read_biased_code(br)?;
+ }
+ let one = (val & 1) != 0;
+ val >>= 1;
+ if self.one {
+ val += 1;
+ }
+ self.one = one;
+ self.zero = !one;
+ val
+ };
+
+ let (base, add) = match val {
+ 0 => {
+ let add = self.get_median(channel, 0) - 1;
+ self.dec_median(channel, 0);
+ (0, add)
+ },
+ 1 => {
+ let base = self.get_median(channel, 0);
+ let add = self.get_median(channel, 1) - 1;
+ self.inc_median(channel, 0);
+ self.dec_median(channel, 1);
+ (base, add)
+ },
+ 2 => {
+ let base = self.get_median(channel, 0) + self.get_median(channel, 1);
+ let add = self.get_median(channel, 2) - 1;
+ self.inc_median(channel, 0);
+ self.inc_median(channel, 1);
+ self.dec_median(channel, 2);
+ (base, add)
+ },
+ _ => {
+ let base = self.get_median(channel, 0) + self.get_median(channel, 1) + self.get_median(channel, 2) * (val - 2);
+ let add = self.get_median(channel, 2) - 1;
+ self.inc_median(channel, 0);
+ self.inc_median(channel, 1);
+ self.inc_median(channel, 2);
+ (base, add)
+ },
+ };
+ let val = base + read_tail(br, add)?;
+
+ if !br.read_bool()? {
+ Ok(val as i32)
+ } else {
+ Ok(!val as i32)
+ }
+ }
+ fn read_sample_hyb(&mut self, br: &mut BitReader, channel: usize) -> DecoderResult<i32> {
+ if (self.median[0][0] < 2) && (self.median[1][0] < 2) && !self.zero && !self.one {
+ if self.num_zeroes > 0 {
+ self.num_zeroes -= 1;
+ if self.num_zeroes != 0 {
+ self.decay_slev(channel);
+ return Ok(0);
+ }
+ } else {
+ self.num_zeroes = read_biased_code(br)?;
+ if self.num_zeroes != 0 {
+ self.median = [[0; 3]; 2];
+ self.decay_slev(channel);
+ return Ok(0);
+ }
+ }
+ }
+ let val = if self.zero {
+ self.zero = false;
+ 0
+ } else {
+ let mut val = br.read_code(UintCodeType::UnaryOnes)?;
+ validate!(val <= 16);
+ if val == 16 {
+ val += read_biased_code(br)?;
+ }
+ let one = (val & 1) != 0;
+ val >>= 1;
+ if self.one {
+ val += 1;
+ }
+ self.one = one;
+ self.zero = !one;
+ val
+ };
+
+ if channel == 0 {
+ self.update_error_limit();
+ }
+
+ let (mut base, mut add) = match val {
+ 0 => {
+ let add = self.get_median(channel, 0) - 1;
+ self.dec_median(channel, 0);
+ (0, add)
+ },
+ 1 => {
+ let base = self.get_median(channel, 0);
+ let add = self.get_median(channel, 1) - 1;
+ self.inc_median(channel, 0);
+ self.dec_median(channel, 1);
+ (base, add)
+ },
+ 2 => {
+ let base = self.get_median(channel, 0) + self.get_median(channel, 1);
+ let add = self.get_median(channel, 2) - 1;
+ self.inc_median(channel, 0);
+ self.inc_median(channel, 1);
+ self.dec_median(channel, 2);
+ (base, add)
+ },
+ _ => {
+ let base = self.get_median(channel, 0) + self.get_median(channel, 1) + self.get_median(channel, 2) * (val - 2);
+ let add = self.get_median(channel, 2) - 1;
+ self.inc_median(channel, 0);
+ self.inc_median(channel, 1);
+ self.inc_median(channel, 2);
+ (base, add)
+ },
+ };
+ let val = if self.error_lim[channel] == 0 {
+ base + read_tail(br, add)?
+ } else {
+ let mut mid = (base * 2 + add + 1) >> 1;
+ while add > self.error_lim[channel] {
+ if br.read_bool()? {
+ add += base;
+ add -= mid;
+ base = mid;
+ } else {
+ add = mid - base - 1;
+ }
+ mid = (base * 2 + add + 1) >> 1;
+ }
+ mid
+ };
+
+ if self.has_hbr {
+ self.decay_slev(channel);
+ self.slow_level[channel] += wv_lin2log(val);
+ }
+
+ if !br.read_bool()? {
+ Ok(val as i32)
+ } else {
+ Ok(!val as i32)
+ }
+ }
+ fn decay_slev(&mut self, channel: usize) {
+ self.slow_level[channel] -= (self.slow_level[channel] + 0x80) >> 8;
+ }
+ fn update_error_limit(&mut self) {
+ let mut br = [0; 2];
+ let mut sl = [0; 2];
+
+ for i in 0..2 {
+ self.br_acc[i] += self.br_delta[i];
+ br[i] = self.br_acc[i] >> 16;
+ sl[i] = (self.slow_level[i] + 0x80) >> 8;
+ }
+
+ if self.stereo && self.has_hbr {
+ let balance = ((sl[1] as i32) - (sl[0] as i32) + (br[1] as i32) + 1) >> 1;
+ if balance > (br[0] as i32) {
+ br[1] = br[0] << 1;
+ br[0] = 0;
+ } else if -balance > (br[0] as i32) {
+ br[0] <<= 1;
+ br[1] = 0;
+ } else {
+ br[1] = ((br[0] as i32) + balance) as u32;
+ br[0] = ((br[0] as i32) - balance) as u32;
+ }
+ }
+ for i in 0..2 {
+ self.error_lim[i] = if self.has_hbr {
+ if sl[i] + 0x100 > br[i] {
+ wv_log2lin((sl[i] + 0x100 - br[i]) as i32) as u32
+ } else {
+ 0
+ }
+ } else {
+ wv_log2lin(br[i] as i32) as u32
+ };
+ }
+ }
+ fn get_median(&self, channel: usize, idx: usize) -> u32 {
+ (self.median[channel][idx] >> 4) + 1
+ }
+ fn inc_median(&mut self, channel: usize, idx: usize) {
+ self.median[channel][idx] += ((self.median[channel][idx] + (128 >> idx)) / (128 >> idx)) * 5;
+ }
+ fn dec_median(&mut self, channel: usize, idx: usize) {
+ self.median[channel][idx] -= ((self.median[channel][idx] + (128 >> idx) - 2) / (128 >> idx)) * 2;
+ }
+ fn produce_sample_common(&self, ebr: &mut BitReader, mut samp: i32) -> i32 {
+ if self.ebits > 0 {
+ samp <<= self.ebits;
+ if ebr.left() >= self.ebits as isize {
+ samp |= ebr.read(self.ebits).unwrap_or(0) as i32;
+ }
+ }
+ let bit = (samp & self.and) | self.or;
+ ((samp + bit) << self.shift) - bit
+ }
+ fn produce_sample(&self, ebr: &mut BitReader, samp: i32) -> i32 {
+ self.produce_sample_common(ebr, samp) << self.post_shift
+ }
+ fn produce_sample_hyb(&self, ebr: &mut BitReader, samp: i32) -> i32 {
+ self.produce_sample_common(ebr, samp).max(self.hyb_min).min(self.hyb_max) << self.post_shift
+ }
+}
+
+struct DecorrState {
+ decorr: [Decorrelator; 16],
+ num_decorr: usize,
+}
+
+impl DecorrState {
+ fn new() -> Self {
+ Self {
+ decorr: [Decorrelator::default(); 16],
+ num_decorr: 0,
+ }
+ }
+ fn reset(&mut self) {
+ self.decorr = [Decorrelator::default(); 16];
+ self.num_decorr = 0;
+ }
+}
+
+struct WavPackDecoder {
+ ainfo: NAAudioInfo,
+ chmap: NAChannelMap,
+ header: WVHeader,
+
+ dstate: DecorrState,
+}
+
+fn get_subblock(br: &mut ByteReader) -> DecoderResult<(u8, usize)> {
+ let id1 = br.read_byte()?;
+ let id = id1 & 0x3F;
+ let mut len = 2 * if (id1 & 0x80) == 0 {
+ br.read_byte()? as usize
+ } else {
+ br.read_u24le()? as usize
+ };
+ if (id1 & 0x40) != 0 {
+ validate!(len > 0);
+ len -= 1;
+ }
+ Ok((id, len))
+}
+
+trait Output {
+ fn set(&mut self, val: i32);
+}
+
+impl Output for i16 {
+ fn set(&mut self, val: i32) { *self = val as i16; }
+}
+impl Output for i32 {
+ fn set(&mut self, val: i32) { *self = val; }
+}
+
+fn unpack_mono<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], len: usize) -> DecoderResult<u32> {
+ let mut crc = 0xFFFFFFFFu32;
+
+ for (i, dst) in dst[..len].iter_mut().enumerate() {
+ let mut l = state.read_sample(br, 0)?;
+ for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+ l = decorr.decorrelate_mono(l, i & 7);
+ }
+ crc = crc.wrapping_mul(3).wrapping_add(l as u32);
+ l = state.produce_sample(ebr, l);
+ dst.set(l);
+ }
+
+ Ok(crc)
+}
+
+#[allow(clippy::too_many_arguments)]
+fn unpack_stereo<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], off0: usize, off1: usize, len: usize, is_joint: bool) -> DecoderResult<u32> {
+ let mut crc = 0xFFFFFFFFu32;
+
+ for i in 0..len {
+ let mut l = state.read_sample(br, 0)?;
+ let mut r = state.read_sample(br, 1)?;
+ for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+ let (pl, pr) = decorr.decorrelate_stereo(l, r, i & 7);
+ l = pl;
+ r = pr;
+ }
+ if is_joint {
+ r -= l >> 1;
+ l += r;
+ }
+ crc = crc.wrapping_mul(3).wrapping_add(l as u32).wrapping_mul(3).wrapping_add(r as u32);
+ l = state.produce_sample(ebr, l);
+ r = state.produce_sample(ebr, r);
+ dst[off0 + i].set(l);
+ dst[off1 + i].set(r);
+ }
+
+ Ok(crc)
+}
+
+fn unpack_mono_hyb<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], len: usize) -> DecoderResult<u32> {
+ let mut crc = 0xFFFFFFFFu32;
+
+ for (i, dst) in dst[..len].iter_mut().enumerate() {
+ let mut l = state.read_sample_hyb(br, 0)?;
+ for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+ l = decorr.decorrelate_mono(l, i & 7);
+ }
+ crc = crc.wrapping_mul(3).wrapping_add(l as u32);
+ l = state.produce_sample_hyb(ebr, l);
+ dst.set(l);
+ }
+
+ Ok(crc)
+}
+
+#[allow(clippy::too_many_arguments)]
+fn unpack_stereo_hyb<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], off0: usize, off1: usize, len: usize, is_joint: bool) -> DecoderResult<u32> {
+ let mut crc = 0xFFFFFFFFu32;
+
+ for i in 0..len {
+ let mut l = state.read_sample_hyb(br, 0)?;
+ let mut r = state.read_sample_hyb(br, 1)?;
+ for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+ let (pl, pr) = decorr.decorrelate_stereo(l, r, i & 7);
+ l = pl;
+ r = pr;
+ }
+ if is_joint {
+ r -= l >> 1;
+ l += r;
+ }
+ crc = crc.wrapping_mul(3).wrapping_add(l as u32).wrapping_mul(3).wrapping_add(r as u32);
+ l = state.produce_sample_hyb(ebr, l);
+ r = state.produce_sample_hyb(ebr, r);
+ dst[off0 + i].set(l);
+ dst[off1 + i].set(r);
+ }
+
+ Ok(crc)
+}
+
+impl WavPackDecoder {
+ fn new() -> Self {
+ Self {
+ ainfo: NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+ chmap: NAChannelMap::new(),
+ header: WVHeader::default(),
+
+ dstate: DecorrState::new(),
+ }
+ }
+ #[allow(clippy::cyclomatic_complexity)]
+ fn decode_block(&mut self, hdr: &WVHeader, src: &[u8], start_ch: usize, abuf: &mut NABufferType) -> DecoderResult<()> {
+ let mut mr = MemoryReader::new_read(src);
+ let mut br = ByteReader::new(&mut mr);
+ let mut has_terms = false;
+ let mut has_weights = false;
+ let mut has_samples = false;
+ let mut has_hybrid = false;
+ let is_mono = (hdr.flags & (WV_FLAG_MONO | WV_FLAG_FALSE_STEREO)) != 0;
+ let cur_channels = if is_mono { 1 } else { 2 };
+ let mut data_pos = 0;
+ let mut data_len = 0;
+ let mut ebits_pos = 0;
+ let mut ebits_len = 0;
+ let mut dec_state = DecState::default();
+ self.dstate.reset();
+ dec_state.post_shift = if (hdr.get_bits() & 8) != 0 { 8 } else { 0 };
+ dec_state.post_shift += ((hdr.flags >> 13) & 0x1F) as u8;
+ validate!(dec_state.post_shift < 32);
+ dec_state.hyb_max = 0x7FFFFFFF >> (32 - hdr.get_bits());
+ dec_state.hyb_min = -dec_state.hyb_max - 1;
+ let is_hybrid = (hdr.flags & WV_FLAG_HYBRID) != 0;
+ let has_hybrid_br = (hdr.flags & WV_FLAG_HYB_BITRATE) != 0;
+ dec_state.has_hbr = has_hybrid_br;
+ dec_state.stereo = !is_mono;
+ while br.left() > 0 {
+ let (id, len) = get_subblock(&mut br)?;
+ match id {
+ 0x02 => { //decorr terms
+ self.dstate.num_decorr = len;
+ validate!(self.dstate.num_decorr <= self.dstate.decorr.len());
+ for decorr in self.dstate.decorr[..self.dstate.num_decorr].iter_mut().rev() {
+ let val = br.read_byte()?;
+ decorr.value = i32::from(val & 0x1F) - 5;
+ decorr.delta = i32::from(val >> 5);
+ }
+ has_terms = true;
+ },
+ 0x03 => { //decorr weights
+ validate!(has_terms);
+ validate!(len <= self.dstate.num_decorr * cur_channels);
+ for decorr in self.dstate.decorr[..self.dstate.num_decorr].iter_mut().rev().take(len / cur_channels) {
+ let val = br.read_byte()? as i8;
+ decorr.weight_a = i32::from(val) << 3;
+ if decorr.weight_a > 0 {
+ decorr.weight_a += (decorr.weight_a + 64) >> 7;
+ }
+ if !is_mono {
+ let val = br.read_byte()? as i8;
+ decorr.weight_b = i32::from(val) << 3;
+ if decorr.weight_b > 0 {
+ decorr.weight_b += (decorr.weight_b + 64) >> 7;
+ }
+ }
+ }
+ has_weights = true;
+ },
+ 0x04 => { //decorr samples
+ validate!(has_weights);
+ let end = br.tell() + (len as u64);
+ for decorr in self.dstate.decorr[..self.dstate.num_decorr].iter_mut().rev() {
+ if br.tell() == end {
+ break;
+ }
+ if decorr.value > 8 {
+ let a0 = br.read_u16le()? as i16;
+ let a1 = br.read_u16le()? as i16;
+ decorr.samples_a[0] = wv_log2lin(i32::from(a0));
+ decorr.samples_a[1] = wv_log2lin(i32::from(a1));
+ if !is_mono {
+ let b0 = br.read_u16le()? as i16;
+ let b1 = br.read_u16le()? as i16;
+ decorr.samples_b[0] = wv_log2lin(i32::from(b0));
+ decorr.samples_b[1] = wv_log2lin(i32::from(b1));
+ }
+ } else if decorr.value < 0 {
+ let a0 = br.read_u16le()? as i16;
+ let b0 = br.read_u16le()? as i16;
+ decorr.samples_a[0] = wv_log2lin(i32::from(a0));
+ decorr.samples_b[0] = wv_log2lin(i32::from(b0));
+ } else {
+ let len = decorr.value as usize;
+ for i in 0..len {
+ let a = br.read_u16le()? as i16;
+ decorr.samples_a[i] = wv_log2lin(i32::from(a));
+ if !is_mono {
+ let b = br.read_u16le()? as i16;
+ decorr.samples_b[i] = wv_log2lin(i32::from(b));
+ }
+ }
+ }
+ }
+ has_samples = true;
+ },
+ 0x05 => { //entropy vars
+ validate!(len == 6 * cur_channels);
+ for el in dec_state.median[0].iter_mut() {
+ *el = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+ }
+ if !is_mono {
+ for el in dec_state.median[1].iter_mut() {
+ *el = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+ }
+ }
+ },
+ 0x06 => { //hybrid parameters
+ validate!(is_hybrid);
+ let end = br.tell() + (len as u64);
+ if has_hybrid_br {
+ for el in dec_state.slow_level.iter_mut().take(cur_channels) {
+ *el = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+ }
+ }
+ for el in dec_state.br_acc.iter_mut().take(cur_channels) {
+ *el = u32::from(br.read_u16le()?) << 16;
+ }
+ if br.tell() < end {
+ for el in dec_state.br_delta.iter_mut().take(cur_channels) {
+ *el = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+ }
+ }
+ validate!(br.tell() == end);
+ has_hybrid = true;
+ },
+ 0x08 => {
+ validate!((hdr.flags & WV_FLAG_FLOATS) != 0);
+ return Err(DecoderError::NotImplemented);
+ },
+ 0x09 => {
+ validate!((hdr.flags & WV_FLAG_EXT_INTEGERS) != 0);
+ validate!(len == 4);
+ let ebits = br.read_byte()?;
+ let mode1 = br.read_byte()?;
+ let mode2 = br.read_byte()?;
+ let mode3 = br.read_byte()?;
+ if ebits != 0 {
+ dec_state.ebits = ebits;
+ } else if mode1 != 0 {
+ dec_state.shift = mode1;
+ } else if mode2 != 0 {
+ dec_state.and = 1;
+ dec_state.or = 1;
+ dec_state.shift = mode2;
+ } else if mode3 != 0 {
+ dec_state.and = 1;
+ dec_state.shift = mode3;
+ }
+ if is_hybrid && hdr.get_bits() == 32 && dec_state.post_shift < 8 && dec_state.shift > 8 {
+ dec_state.post_shift += 8;
+ dec_state.shift -= 8;
+ dec_state.hyb_min >>= 8;
+ dec_state.hyb_max >>= 8;
+ }
+ },
+ 0x0A => { // normal stream
+ validate!(has_samples);
+ data_pos = br.tell() as usize;
+ data_len = len;
+ br.read_skip(len)?;
+ },
+ 0x0C => {
+ ebits_pos = br.tell() as usize;
+ ebits_len = len;
+ br.read_skip(len)?;
+ },
+ 0x0E => return Err(DecoderError::NotImplemented), // DSD
+ _ => { br.read_skip(len)?; },
+ };
+ if (len & 1) != 0 {
+ br.read_skip(1)?;
+ }
+ }
+ validate!(data_pos > 0 && data_len > 0);
+ if is_hybrid {
+ validate!(has_hybrid);
+ }
+
+ let mut br = BitReader::new(&src[data_pos..][..data_len], BitReaderMode::LE);
+ let mut ebr = BitReader::new(&src[ebits_pos..][..ebits_len], BitReaderMode::LE);
+ if is_mono {
+ let is_fstereo = (hdr.flags & WV_FLAG_FALSE_STEREO) != 0;
+ match abuf {
+ NABufferType::AudioI16(ref mut adata) => {
+ let off0 = adata.get_offset(start_ch);
+ let off1 = adata.get_offset(start_ch + 1);
+ let dst = adata.get_data_mut().unwrap();
+ let crc = if !is_hybrid {
+ unpack_mono(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+ } else {
+ unpack_mono_hyb(&mut br, &mut ebr, &mut dec_state, &mut
+ self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+ };
+ if crc != hdr.crc {
+ return Err(DecoderError::ChecksumError);
+ }
+ if is_fstereo {
+ for i in 0..(hdr.block_samples as usize) {
+ dst[off1 + i] = dst[off0 + i];
+ }
+ }
+ },
+ NABufferType::AudioI32(ref mut adata) => {
+ let off0 = adata.get_offset(start_ch);
+ let off1 = adata.get_offset(start_ch + 1);
+ let dst = adata.get_data_mut().unwrap();
+ let crc = if !is_hybrid {
+ unpack_mono(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+ } else {
+ unpack_mono_hyb(&mut br, &mut ebr, &mut dec_state, &mut
+ self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+ };
+ if crc != hdr.crc {
+ return Err(DecoderError::ChecksumError);
+ }
+ if is_fstereo {
+ for i in 0..(hdr.block_samples as usize) {
+ dst[off1 + i] = dst[off0 + i];
+ }
+ }
+ },
+ _ => unreachable!(),
+ }
+ } else {
+ let is_joint = (hdr.flags & WV_FLAG_JSTEREO) != 0;
+ match abuf {
+ NABufferType::AudioI16(ref mut adata) => {
+ let off0 = adata.get_offset(start_ch);
+ let off1 = adata.get_offset(start_ch + 1);
+ let dst = adata.get_data_mut().unwrap();
+ let crc = if !is_hybrid {
+ unpack_stereo(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+ } else {
+ unpack_stereo_hyb(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+ };
+ if crc != hdr.crc {
+ return Err(DecoderError::ChecksumError);
+ }
+ },
+ NABufferType::AudioI32(ref mut adata) => {
+ let off0 = adata.get_offset(start_ch);
+ let off1 = adata.get_offset(start_ch + 1);
+ let dst = adata.get_data_mut().unwrap();
+ let crc = if !is_hybrid {
+ unpack_stereo(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+ } else {
+ unpack_stereo_hyb(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+ };
+ if crc != hdr.crc {
+ return Err(DecoderError::ChecksumError);
+ }
+ },
+ _ => unreachable!(),
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl NADecoder for WavPackDecoder {
+ fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+ if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+ if let Some(buf) = info.get_extradata() {
+ let mut channels = 0;
+ let mut decl_channels = 0;
+ let mut channel_map = 0;
+ let mut off = 0;
+ while off < buf.len() {
+ let hdr = WVHeader::parse(&buf[off..])?;
+ if (hdr.flags & (WV_FLAG_FLOATS | WV_FLAG_DSD_AUDIO)) != 0 {
+ return Err(DecoderError::NotImplemented);
+ }
+ self.header = hdr;
+ off += WV_HEADER_SIZE;
+ let size = hdr.get_size();
+ let mut mr = MemoryReader::new_read(&buf[off..][..size]);
+ let mut br = ByteReader::new(&mut mr);
+ while br.left() > 0 {
+ let (id, len) = get_subblock(&mut br)?;
+ match id {
+ 0xD => {
+ validate!(len > 1);
+ decl_channels = br.read_byte()?;
+ if decl_channels == 0 {
+ return Err(DecoderError::NotImplemented);
+ }
+ channel_map = match len {
+ 2 => u32::from(br.read_byte()?),
+ 3 => u32::from(br.read_u16le()?),
+ 4 => br.read_u24le()?,
+ 5 => br.read_u32le()?,
+ _ => return Err(DecoderError::NotImplemented),
+ };
+ },
+ _ => br.read_skip(len)?,
+ };
+ if (len & 1) != 0 {
+ br.read_skip(1)?;
+ }
+ }
+ channels += hdr.get_num_channels();
+
+ if hdr.is_end_block() {
+ break;
+ }
+ off += size;
+ }
+ if decl_channels != 0 {
+ validate!(decl_channels == channels);
+ }
+ self.chmap = if channel_map != 0 {
+ NAChannelMap::from_ms_mapping(channel_map)
+ } else if channels == 1 {
+ NAChannelMap::from_str("C").unwrap()
+ } else if channels == 2 {
+ NAChannelMap::from_str("L,R").unwrap()
+ } else {
+ return Err(DecoderError::NotImplemented);
+ };
+ let bsamps = if self.header.block_samples == 0 {
+ self.header.get_sample_rate()
+ } else {
+ self.header.block_samples
+ } as usize;
+
+ let bits = self.header.get_bits();
+ let fmt = if (self.header.flags & WV_FLAG_FLOATS) != 0 {
+ SND_F32P_FORMAT
+ } else if bits <= 16 {
+ SND_S16P_FORMAT
+ } else {
+ SND_S32P_FORMAT
+ };
+
+ self.ainfo = NAAudioInfo::new(self.header.get_sample_rate(), channels, fmt, bsamps);
+ Ok(())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+ let info = pkt.get_stream().get_info();
+ if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+ let pktbuf = pkt.get_buffer();
+ validate!(pktbuf.len() > WV_HEADER_SIZE);
+ let refhdr = WVHeader::parse(&pktbuf)?;
+
+ if refhdr.block_samples == 0 {
+ let mut frm = NAFrame::new_from_pkt(pkt, info, NABufferType::None);
+ frm.set_frame_type(FrameType::Skip);
+ frm.set_keyframe(false);
+ return Ok(frm.into_ref());
+ }
+
+ let mut abuf = alloc_audio_buffer(self.ainfo, refhdr.block_samples as usize, self.chmap.clone())?;
+ let mut start_ch = 0;
+ let mut roff = 0;
+ let mut first = true;
+ let mut refhdr = WVHeader::default();
+ loop {
+ let hdr = WVHeader::parse(&pktbuf[roff..])?;
+ if first {
+ validate!(hdr.is_start_block());
+ validate!(self.header.stream_eq(&hdr));
+ refhdr = hdr;
+ first = false;
+ } else {
+ validate!(refhdr.block_eq(&hdr));
+ }
+ roff += WV_HEADER_SIZE;
+ let blk_size = hdr.get_size();
+ self.decode_block(&hdr, &pktbuf[roff..][..blk_size], start_ch, &mut abuf)?;
+ roff += blk_size;
+ if hdr.is_end_block() {
+ break;
+ }
+ start_ch += hdr.get_num_channels() as usize;
+ }
+ let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+ frm.set_duration(Some(u64::from(refhdr.block_samples)));
+ Ok(frm.into_ref())
+ } else {
+ Err(DecoderError::InvalidData)
+ }
+ }
+ fn flush(&mut self) {
+ }
+}
+
+impl NAOptionHandler for WavPackDecoder {
+ 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() -> Box<dyn NADecoder + Send> {
+ Box::new(WavPackDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+ use nihav_core::codecs::RegisteredDecoders;
+ use nihav_core::demuxers::RegisteredDemuxers;
+ use nihav_codec_support::test::dec_video::*;
+ use crate::llaudio_register_all_decoders;
+ use crate::llaudio_register_all_demuxers;
+ #[test]
+ fn test_wavpack_8bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/8bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x8157bf0f, 0xeb441905, 0xeb6b815d, 0x113480a8]));
+ }
+ #[test]
+ fn test_wavpack_12bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/12bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xe5faf18c, 0xbf2d3b12, 0x5b0b8f00, 0x162b805a]));
+ }
+ #[test]
+ fn test_wavpack_16bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/16bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xaf31b252, 0xdf8b282a, 0x2dc38947, 0xf64c68a1]));
+ }
+ #[test]
+ fn test_wavpack_24bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/24bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0xf5649972, 0xfe757241, 0x383d5ded, 0x0176a75b]));
+ }
+ #[test]
+ fn test_wavpack_hybrid() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/4.0_16-bit.wv", Some(100000), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x9cfa469a, 0x54af50e1, 0xe45434d1, 0x1bf987e2]));
+ }
+ #[test]
+ fn test_wavpack_hybrid_32bit() {
+ let mut dmx_reg = RegisteredDemuxers::new();
+ llaudio_register_all_demuxers(&mut dmx_reg);
+ let mut dec_reg = RegisteredDecoders::new();
+ llaudio_register_all_decoders(&mut dec_reg);
+
+ test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/4.0_32-bit_int.wv", Some(100000), &dmx_reg, &dec_reg,
+ ExpectedTestResult::MD5([0x21415549, 0xf48ddb55, 0xef5c4e7f, 0xa48d5ab9]));
+ }
+}
+
+const WV_EXP_TABLE: [u8; 256] = [
+ 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05,
+ 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10,
+ 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
+ 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+ 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29,
+ 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36,
+ 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
+ 0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52,
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+ 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61,
+ 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
+ 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
+ 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
+ 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
+ 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+ 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
+ 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
+ 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca,
+ 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
+ 0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde,
+ 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
+ 0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4,
+ 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
+];
+const WV_LOG_TABLE: [u8; 256] = [
+ 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a,
+ 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
+ 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20,
+ 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
+ 0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34,
+ 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
+ 0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48,
+ 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
+ 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+ 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
+ 0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
+ 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
+ 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
+ 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+ 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
+ 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c,
+ 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
+ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9,
+ 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
+ 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
+ 0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
+ 0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1,
+ 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee,
+ 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9,
+ 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
+];
--- /dev/null
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+#[derive(Clone,Copy)]
+struct Frame {
+ off: u32,
+ size: u32,
+ bits_off: u8,
+}
+
+struct APEDemuxer<'a> {
+ src: &'a mut ByteReader<'a>,
+ cur_frame: usize,
+ frames: Vec<Frame>,
+ normal_blocks: u32,
+ last_blocks: u32,
+ truncated: bool,
+}
+
+impl<'a> APEDemuxer<'a> {
+ fn new(io: &'a mut ByteReader<'a>) -> Self {
+ Self {
+ src: io,
+ cur_frame: 0,
+ frames: Vec::new(),
+ normal_blocks: 0,
+ last_blocks: 0,
+ truncated: false,
+ }
+ }
+}
+
+impl<'a> DemuxCore<'a> for APEDemuxer<'a> {
+ fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+ let src = &mut self.src;
+
+ let tag = src.read_tag()?;
+ validate!(&tag == b"MAC ");
+ let version = src.read_u16le()?;
+ validate!(version >= 3800 && version <= 3990);
+
+ let seektab_len;
+ let _wavtail_len;
+ let compr_type;
+ let flags;
+ let blocksperframe;
+ let finalblocks;
+ let nframes;
+ let bits;
+ let channels;
+ let srate;
+ if version >= 3980 {
+ src.read_skip(2)?;
+ let descriptor_len = src.read_u32le()? as usize;
+ let header_len = src.read_u32le()? as usize;
+ validate!(header_len == 24);
+ seektab_len = src.read_u32le()? as usize;
+ let _wavheader_len = src.read_u32le()? as usize;
+ let _audio_len = src.read_u64le()?;
+ _wavtail_len = src.read_u32le()? as usize;
+ src.read_skip(16)?; // unpacked data MD5
+ if descriptor_len > 52 {
+ src.read_skip(descriptor_len - 52)?;
+ }
+
+ compr_type = src.read_u16le()?;
+ flags = src.read_u16le()?;
+ blocksperframe = src.read_u32le()?;
+ finalblocks = src.read_u32le()?;
+ nframes = src.read_u32le()? as usize;
+ bits = src.read_u16le()?;
+ channels = src.read_u16le()?;
+ srate = src.read_u32le()?;
+ } else {
+ compr_type = src.read_u16le()?;
+ flags = src.read_u16le()?;
+ channels = src.read_u16le()?;
+ srate = src.read_u32le()?;
+
+ let wavheader_len = src.read_u32le()? as usize;
+ _wavtail_len = src.read_u32le()? as usize;
+ nframes = src.read_u32le()? as usize;
+ finalblocks = src.read_u32le()?;
+ if (flags & 0x04) != 0 {
+ src.read_u32le()?; // peak level
+ }
+ if (flags & 0x10) != 0 {
+ seektab_len = src.read_u32le()? as usize * 4;
+ } else {
+ seektab_len = nframes * 4;
+ }
+
+ if (flags & 0x01) != 0 {
+ bits = 8;
+ } else if (flags & 0x08) != 0 {
+ bits = 24;
+ } else {
+ bits = 16;
+ }
+
+ blocksperframe = 9216 * if version >= 3950 {
+ 32
+ } else if (version >= 3900) || ((version >= 3800) && (compr_type >= 4000)) {
+ 8
+ } else {
+ 1
+ };
+
+ if (flags & 0x20) == 0 {
+ src.read_skip(wavheader_len)?;
+ }
+ }
+ validate!(srate > 0);
+ validate!(channels > 0 && channels < 256);
+ validate!(bits > 0 && bits <= 32);
+ validate!(nframes > 0 && nframes < (1 << 28));
+ validate!(seektab_len == nframes * 4);
+
+ self.frames = Vec::with_capacity(nframes);
+ self.normal_blocks = blocksperframe;
+ self.last_blocks = finalblocks;
+
+ seek_index.mode = SeekIndexMode::Present;
+ let first_off = src.peek_u32le()?;
+ validate!(u64::from(first_off) >= src.tell() + ((nframes * 4) as u64));
+ let mut last_off = first_off - 1;
+ for i in 0..nframes {
+ let off = src.read_u32le()?;
+ validate!(off > last_off);
+ let diff = (off - first_off) & 3;
+ self.frames.push(Frame {
+ off: off - diff,
+ size: 0,
+ bits_off: (diff as u8) * 8,
+ });
+
+ last_off = off;
+
+ let time = (i as u64) * u64::from(blocksperframe) * 1000 / u64::from(srate);
+ seek_index.add_entry(0, SeekEntry { time, pts: i as u64, pos: i as u64 });
+ }
+ if version < 3810 {
+ for frame in self.frames.iter_mut() {
+ let bits = src.read_byte()?;
+ validate!(bits < 32);
+ frame.bits_off += bits;
+ }
+ }
+ src.seek(SeekFrom::End(0))?;
+ let fsize = src.tell();
+ validate!(fsize > u64::from(self.frames[0].off));
+ self.truncated = u64::from(self.frames[self.frames.len() - 1].off) >= fsize;
+ if self.truncated {
+ let mut valid_frames = self.frames.len();
+ for frame in self.frames.iter_mut().rev() {
+ if u64::from(frame.off) >= fsize {
+ valid_frames -= 1;
+ }
+ }
+ self.frames.truncate(valid_frames);
+ validate!(!self.frames.is_empty());
+ self.truncated = true;
+ }
+ let mut last_off = fsize as u32;
+ for frame in self.frames.iter_mut().rev() {
+ frame.size = last_off - frame.off;
+ last_off = frame.off + (if frame.bits_off > 0 { 4 } else { 0 });
+ }
+
+ let mut hdr = vec![0u8; 16];
+ write_u16le(&mut hdr[0..], version)?;
+ write_u16le(&mut hdr[2..], compr_type)?;
+ write_u16le(&mut hdr[4..], flags)?;
+ hdr[6] = channels as u8;
+ hdr[7] = bits as u8;
+ write_u32le(&mut hdr[8..], srate)?;
+ write_u32le(&mut hdr[12..], blocksperframe)?;
+
+ let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 1);
+ let ainfo = NACodecInfo::new("ape", NACodecTypeInfo::Audio(ahdr), Some(hdr));
+ strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, blocksperframe, srate)).unwrap();
+
+ self.cur_frame = 0;
+
+ Ok(())
+ }
+ fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+ if self.cur_frame >= self.frames.len() {
+ return Err(DemuxerError::EOF);
+ }
+
+ let size = self.frames[self.cur_frame].size as usize;
+ let off = self.frames[self.cur_frame].off;
+ let bits = self.frames[self.cur_frame].bits_off;
+ let nblocks = if (self.cur_frame < self.frames.len() - 1) || self.truncated { self.normal_blocks } else { self.last_blocks };
+
+ self.src.seek(SeekFrom::Start(off.into()))?;
+
+ let mut buf = vec![0u8; size + 8];
+ write_u32le(&mut buf[0..], nblocks)?;
+ buf[4] = bits;
+ self.src.read_buf(&mut buf[8..])?;
+
+ let stream = strmgr.get_stream(0).unwrap();
+ let (tb_num, tb_den) = stream.get_timebase();
+ let ts = NATimeInfo::new(Some(self.cur_frame as u64), None, None, tb_num, tb_den);
+ let pkt = NAPacket::new(stream, ts, true, buf);
+
+ self.cur_frame += 1;
+
+ Ok(pkt)
+ }
+ fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+ let ret = seek_index.find_pos(time);
+ if ret.is_none() {
+ return Err(DemuxerError::SeekError);
+ }
+ let seek_info = ret.unwrap();
+ self.cur_frame = seek_info.pts as usize;
+ if self.cur_frame >= self.frames.len() {
+ return Err(DemuxerError::SeekError);
+ }
+
+ Ok(())
+ }
+}
+
+impl<'a> NAOptionHandler for APEDemuxer<'a> {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct APEDemuxerCreator { }
+
+impl DemuxerCreator for APEDemuxerCreator {
+ fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+ Box::new(APEDemuxer::new(br))
+ }
+ fn get_name(&self) -> &'static str { "ape" }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn test_ape_demux() {
+ let mut file = File::open("assets/LLaudio/ape/luckynight.ape").unwrap();
+ let mut fr = FileReader::new_read(&mut file);
+ let mut br = ByteReader::new(&mut fr);
+ let mut dmx = APEDemuxer::new(&mut br);
+ let mut sm = StreamManager::new();
+ let mut si = SeekIndex::new();
+ dmx.open(&mut sm, &mut si).unwrap();
+ loop {
+ let pktres = dmx.get_frame(&mut sm);
+ if let Err(e) = pktres {
+ if (e as i32) == (DemuxerError::EOF as i32) { break; }
+ panic!("error");
+ }
+ let pkt = pktres.unwrap();
+ println!("Got {}", pkt);
+ }
+ }
+}
--- /dev/null
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+struct FLACDemuxer<'a> {
+ src: &'a mut ByteReader<'a>,
+ data_start: u64,
+ tot_samples: u64,
+ cur_samples: u64,
+ blk_samples: u16,
+ min_size: usize,
+ max_size: usize,
+}
+
+impl<'a> FLACDemuxer<'a> {
+ fn new(io: &'a mut ByteReader<'a>) -> Self {
+ Self {
+ src: io,
+ data_start: 0,
+ tot_samples: 0,
+ cur_samples: 0,
+ blk_samples: 0,
+ min_size: 0,
+ max_size: 0,
+ }
+ }
+}
+
+fn update_crc16(crc: u16, byte: u8) -> u16 {
+ (crc << 8) ^ CRC16_TABLE[(((crc >> 8) as u8) ^ byte) as usize]
+}
+
+fn read_utf8(src: &[u8]) -> DemuxerResult<u32> {
+ if (src[0] & 0x80) == 0 {
+ return Ok(u32::from(src[0]));
+ }
+ let len = (!src[0]).leading_zeros() as usize;
+ validate!(len != 1 && len <= 5 && src.len() >= len);
+ let mut val = u32::from(src[0] & 0x1F);
+ for byte in src.iter().take(len).skip(1) {
+ validate!((*byte & 0xC0) == 0x80);
+ val = (val << 6) | u32::from(*byte & 0x3F);
+ }
+ Ok(val)
+}
+
+impl<'a> DemuxCore<'a> for FLACDemuxer<'a> {
+ fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+ let tag = self.src.read_tag()?;
+ validate!(&tag == b"fLaC");
+ let mut streaminfo: Vec<u8> = Vec::new();
+ let mut srate = 0u32;
+ let mut channels = 0u8;
+ loop {
+ let id1 = self.src.read_byte()?;
+ let len = self.src.read_u24be()? as usize;
+ let id = id1 & 0x7F;
+
+ match id {
+ 0x00 => {
+ validate!(len >= 34);
+ streaminfo = vec![0u8; len];
+ self.src.read_buf(&mut streaminfo)?;
+ let min_bs = read_u16be(&streaminfo[0..])?;
+ let max_bs = read_u16be(&streaminfo[2..])?;
+ if min_bs == max_bs {
+ self.blk_samples = max_bs;
+ }
+ self.min_size = read_u24be(&streaminfo[4..])? as usize;
+ self.max_size = read_u24be(&streaminfo[7..])? as usize;
+ let word = read_u24be(&streaminfo[10..])?;
+ srate = word >> 4;
+ channels = (((word >> 1) & 7) + 1) as u8;
+ self.tot_samples = (u64::from(streaminfo[13] & 0xF) << 32) | u64::from(read_u32be(&streaminfo[14..])?);
+ },
+ 0x03 => {
+ validate!((len % 18) == 0);
+ seek_index.mode = SeekIndexMode::Present;
+ for _ in 0..len / 18 {
+ let sample = self.src.read_u64be()?;
+ let offset = self.src.read_u64be()?;
+ let _nsamps = self.src.read_u16be()?;
+ let time = sample * 1000 / u64::from(srate.max(1000));
+ seek_index.add_entry(0, SeekEntry { time, pts: sample, pos: offset });
+ }
+ },
+ _ => self.src.read_skip(len)?,
+ };
+
+ if (id1 & 0x80) != 0 {
+ break;
+ }
+ }
+ self.data_start = self.src.tell();
+ validate!(srate != 0);
+
+ let base = if self.blk_samples != 0 { u32::from(self.blk_samples) } else { 1 };
+ let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, base as usize);
+ let ainfo = NACodecInfo::new("flac", NACodecTypeInfo::Audio(ahdr), Some(streaminfo));
+ strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, base, srate)).unwrap();
+
+ Ok(())
+ }
+ fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+ if self.src.is_eof() || (self.tot_samples != 0 && self.cur_samples == self.tot_samples) { return Err(DemuxerError::EOF); }
+ let mut buf = Vec::with_capacity(self.min_size);
+ let mut crc = 0;
+ for _ in 0..5 {
+ let byte = self.src.read_byte()?;
+ buf.push(byte);
+ crc = update_crc16(crc, byte);
+ }
+ let mut ref_crc = self.src.read_u16be()?;
+ loop {
+ let byte = self.src.read_byte()?;
+ let old_byte = (ref_crc >> 8) as u8;
+ buf.push(old_byte);
+ ref_crc = (ref_crc << 8) | u16::from(byte);
+ crc = update_crc16(crc, old_byte);
+ if buf.len() + 2 >= self.min_size && crc == ref_crc {
+ let ret = self.src.peek_u16be();
+ if ret.is_err() || ((ret.unwrap_or(0) & 0xFFFE) == 0xFFF8) {
+ buf.push((ref_crc >> 8) as u8);
+ buf.push(ref_crc as u8);
+ break;
+ }
+ }
+ if (self.max_size > 0) && (buf.len() > self.max_size) {
+ return Err(DemuxerError::InvalidData);
+ }
+ if buf.len() > (1 << 23) {
+ return Err(DemuxerError::InvalidData);
+ }
+ }
+
+ let (duration, pts) = if self.blk_samples != 0 {
+ validate!((buf[1] & 1) == 0);
+ let blkno = u64::from(read_utf8(&buf[4..])?);
+ self.cur_samples = blkno * u64::from(self.blk_samples);
+ (u64::from(self.blk_samples), blkno)
+ } else {
+ validate!((buf[1] & 1) != 0);
+ let blksamps = u64::from(read_utf8(&buf[4..])?);
+ (blksamps, self.cur_samples)
+ };
+
+ let stream = strmgr.get_stream(0).unwrap();
+ let (tb_num, tb_den) = stream.get_timebase();
+ let ts = NATimeInfo::new(Some(pts), None, Some(duration), tb_num, tb_den);
+ let pkt = NAPacket::new(stream, ts, true, buf);
+
+ self.cur_samples += duration;
+
+ Ok(pkt)
+ }
+ fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+ let ret = seek_index.find_pos(time);
+ if ret.is_none() {
+ return Err(DemuxerError::SeekError);
+ }
+ let seek_info = ret.unwrap();
+ self.cur_samples = seek_info.pts;
+ self.src.seek(SeekFrom::Start(self.data_start + seek_info.pos))?;
+
+ Ok(())
+ }
+}
+
+impl<'a> NAOptionHandler for FLACDemuxer<'a> {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct FLACDemuxerCreator { }
+
+impl DemuxerCreator for FLACDemuxerCreator {
+ fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+ Box::new(FLACDemuxer::new(br))
+ }
+ fn get_name(&self) -> &'static str { "flac" }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn test_flac_demux() {
+ let mut file = File::open("assets/LLaudio/luckynight.flac").unwrap();
+ let mut fr = FileReader::new_read(&mut file);
+ let mut br = ByteReader::new(&mut fr);
+ let mut dmx = FLACDemuxer::new(&mut br);
+ let mut sm = StreamManager::new();
+ let mut si = SeekIndex::new();
+ dmx.open(&mut sm, &mut si).unwrap();
+ loop {
+ let pktres = dmx.get_frame(&mut sm);
+ if let Err(e) = pktres {
+ if (e as i32) == (DemuxerError::EOF as i32) { break; }
+ panic!("error");
+ }
+ let pkt = pktres.unwrap();
+ println!("Got {}", pkt);
+ }
+ }
+}
+
+const CRC16_TABLE: [u16; 256] = [
+ 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041,
+ 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2,
+ 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
+ 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1,
+ 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
+ 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1,
+ 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1,
+ 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
+ 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342,
+ 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
+ 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2,
+ 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2,
+ 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291,
+ 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2,
+ 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
+ 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1,
+ 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202
+];
--- /dev/null
+use nihav_core::demuxers::*;
+
+#[allow(unused_macros)]
+macro_rules! validate {
+ ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DemuxerError::InvalidData); } };
+}
+
+#[cfg(feature="demuxer_ape")]
+mod ape;
+#[cfg(feature="demuxer_flac")]
+mod flac;
+#[cfg(feature="demuxer_tta")]
+mod tta;
+#[cfg(feature="demuxer_wavpack")]
+mod wavpack;
+
+const LL_AUDIO_DEMUXERS: &[&DemuxerCreator] = &[
+#[cfg(feature="demuxer_ape")]
+ &ape::APEDemuxerCreator {},
+#[cfg(feature="demuxer_flac")]
+ &flac::FLACDemuxerCreator {},
+#[cfg(feature="demuxer_tta")]
+ &tta::TTADemuxerCreator {},
+#[cfg(feature="demuxer_wavpack")]
+ &wavpack::WavPackDemuxerCreator {},
+];
+
+/// Registers all available demuxers provided by this crate.
+pub fn llaudio_register_all_demuxers(rd: &mut RegisteredDemuxers) {
+ for demuxer in LL_AUDIO_DEMUXERS.iter() {
+ rd.add_demuxer(*demuxer);
+ }
+}
--- /dev/null
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+struct TTADemuxer<'a> {
+ src: &'a mut ByteReader<'a>,
+ cur_frame: u32,
+ nframes: u32,
+ nsamples: u32,
+ offtab: Vec<u64>,
+ sizetab: Vec<u32>,
+ framelen: u32,
+}
+
+impl<'a> TTADemuxer<'a> {
+ fn new(io: &'a mut ByteReader<'a>) -> Self {
+ Self {
+ src: io,
+ cur_frame: 0,
+ nframes: 0,
+ nsamples: 0,
+ offtab: Vec::new(),
+ sizetab: Vec::new(),
+ framelen: 0,
+ }
+ }
+}
+
+impl<'a> DemuxCore<'a> for TTADemuxer<'a> {
+ fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+
+ let mut hdr = vec![0; 22];
+ self.src.read_buf(&mut hdr)?;
+
+ validate!(&hdr[..4] == b"TTA1");
+ let _afmt = read_u16le(&hdr[4..])?;
+ let channels = read_u16le(&hdr[6..])?;
+ validate!(channels > 0 && channels < 256);
+ let bpp = read_u16le(&hdr[8..])?;
+ validate!(bpp > 0 && bpp <= 32);
+ let srate = read_u32le(&hdr[10..])?;
+ validate!(srate > 256 && srate < 1048576);
+ self.nsamples = read_u32le(&hdr[14..])?;
+ validate!(self.nsamples > 0);
+ let _crc = read_u32le(&hdr[18..])?;
+
+ self.framelen = srate * 256 / 245;
+
+ self.nframes = (self.nsamples + self.framelen - 1) / self.framelen;
+
+ seek_index.mode = SeekIndexMode::Present;
+ let mut off = u64::from(self.nframes) * 4 + 4 + 22;
+ let mut cur_time = 0;
+ for pts in 0..self.nframes {
+ let fsize = self.src.read_u32le()?;
+ self.sizetab.push(fsize);
+ self.offtab.push(off);
+ let time = u64::from(cur_time) * 1000 / u64::from(srate);
+ seek_index.add_entry(0, SeekEntry { time, pts: u64::from(pts), pos: off });
+ off += u64::from(fsize);
+ cur_time += self.framelen;
+ }
+
+ let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 1);
+ let ainfo = NACodecInfo::new("tta", NACodecTypeInfo::Audio(ahdr), Some(hdr));
+ strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, self.framelen, srate)).unwrap();
+
+ self.cur_frame = 0;
+
+ Ok(())
+ }
+ fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+ if self.cur_frame >= self.nframes {
+ return Err(DemuxerError::EOF);
+ }
+
+ let size = self.sizetab[self.cur_frame as usize] as usize;
+ let off = self.offtab[self.cur_frame as usize];
+ self.src.seek(SeekFrom::Start(off))?;
+
+ let stream = strmgr.get_stream(0).unwrap();
+ let (tb_num, tb_den) = stream.get_timebase();
+ let ts = NATimeInfo::new(Some(self.cur_frame.into()), None, None, tb_num, tb_den);
+ let pkt = self.src.read_packet(stream, ts, true, size)?;
+
+ self.cur_frame += 1;
+
+ Ok(pkt)
+ }
+ fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+ let ret = seek_index.find_pos(time);
+ if ret.is_none() {
+ return Err(DemuxerError::SeekError);
+ }
+ let seek_info = ret.unwrap();
+ self.cur_frame = seek_info.pts as u32;
+
+ Ok(())
+ }
+}
+
+impl<'a> NAOptionHandler for TTADemuxer<'a> {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct TTADemuxerCreator { }
+
+impl DemuxerCreator for TTADemuxerCreator {
+ fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+ Box::new(TTADemuxer::new(br))
+ }
+ fn get_name(&self) -> &'static str { "tta" }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn test_tta_demux() {
+ let mut file = File::open("assets/LLaudio/luckynight.tta").unwrap();
+ let mut fr = FileReader::new_read(&mut file);
+ let mut br = ByteReader::new(&mut fr);
+ let mut dmx = TTADemuxer::new(&mut br);
+ let mut sm = StreamManager::new();
+ let mut si = SeekIndex::new();
+ dmx.open(&mut sm, &mut si).unwrap();
+ loop {
+ let pktres = dmx.get_frame(&mut sm);
+ if let Err(e) = pktres {
+ if (e as i32) == (DemuxerError::EOF as i32) { break; }
+ panic!("error");
+ }
+ let pkt = pktres.unwrap();
+ println!("Got {}", pkt);
+ }
+ }
+}
--- /dev/null
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+const SAMPLE_RATES: [u32; 15] = [
+ 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000,
+ 32000, 44100, 48000, 64000, 88200, 96000, 192000
+];
+const WV_FLAG_MONO: u32 = 1 << 2;
+//const WV_FLAG_HYBRID: u32 = 1 << 3;
+//const WV_FLAG_JSTEREO: u32 = 1 << 4;
+//const WV_FLAG_CH_DECORR: u32 = 1 << 5;
+//const WV_FLAG_HYB_NOISE_SHAPING: u32 = 1 << 6;
+const WV_FLAG_FLOATS: u32 = 1 << 7;
+//const WV_FLAG_EXT_INTEGERS: u32 = 1 << 8;
+//const WV_FLAG_HYB_BITRATE: u32 = 1 << 9;
+//const WV_FLAG_HYB_BALANCED_NOISE: u32 = 1 << 10;
+const WV_FLAG_START_BLOCK: u32 = 1 << 11;
+const WV_FLAG_END_BLOCK: u32 = 1 << 12;
+//const WV_FLAG_HAS_CRC: u32 = 1 << 28;
+const WV_FLAG_FALSE_STEREO: u32 = 1 << 30;
+//const WV_FLAG_DSD_AUDIO: u32 = 1 << 31;
+
+const WV_STREAM_FLAGS: u32 = 0x8000018B;
+
+#[derive(Clone,Copy,Default)]
+struct WVHeader {
+ size: usize,
+ ver: u16,
+ tot_samples: u64,
+ block_index: u64,
+ block_samples: u32,
+ flags: u32,
+ crc: u32,
+}
+
+const WV_HEADER_SIZE: usize = 32;
+
+impl WVHeader {
+ fn parse(src: &[u8]) -> DemuxerResult<Self> {
+ let mut mr = MemoryReader::new_read(src);
+ let mut br = ByteReader::new(&mut mr);
+ let tag = br.read_tag()?;
+ validate!(&tag == b"wvpk");
+ let mut hdr = Self::default();
+ hdr.size = br.read_u32le()? as usize;
+ validate!(hdr.size >= 24);
+ hdr.ver = br.read_u16le()?;
+ validate!(hdr.ver >= 0x402 || hdr.ver <= 0x410);
+ let top_idx = br.read_byte()?;
+ let top_samps = br.read_byte()?;
+ hdr.tot_samples = u64::from(br.read_u32le()?) | (u64::from(top_samps) << 32);
+ hdr.block_index = u64::from(br.read_u32le()?) | (u64::from(top_idx) << 32);
+ hdr.block_samples = br.read_u32le()?;
+ hdr.flags = br.read_u32le()?;
+ hdr.crc = br.read_u32le()?;
+ Ok(hdr)
+ }
+ fn stream_eq(&self, rval: &Self) -> bool {
+ self.ver == rval.ver &&
+ (self.flags & WV_STREAM_FLAGS) == (rval.flags & WV_STREAM_FLAGS)
+ }
+ fn block_eq(&self, rval: &Self) -> bool {
+ self.stream_eq(rval) && self.tot_samples == rval.tot_samples &&
+ self.block_index == rval.block_index &&
+ self.block_samples == rval.block_samples
+ }
+ fn is_start_block(&self) -> bool {
+ (self.flags & WV_FLAG_START_BLOCK) != 0
+ }
+ fn is_end_block(&self) -> bool {
+ (self.flags & WV_FLAG_END_BLOCK) != 0
+ }
+ fn get_num_channels(&self) -> u8 {
+ if (self.flags & WV_FLAG_MONO) != 0 && (self.flags & WV_FLAG_FALSE_STEREO) == 0 { 1 } else { 2 }
+ }
+ fn get_sample_rate(&self) -> u32 {
+ let idx = ((self.flags >> 23) & 0xF) as usize;
+ if idx != 15 {
+ SAMPLE_RATES[idx]
+ } else {
+ 0
+ }
+ }
+ fn get_size(&self) -> usize {
+ self.size - (WV_HEADER_SIZE - 8)
+ }
+}
+
+#[derive(Clone,Copy,Default)]
+struct FrameSeekInfo {
+ off: u64,
+ samplepos: u64,
+}
+
+struct WavPackDemuxer<'a> {
+ src: &'a mut ByteReader<'a>,
+ samplepos: u64,
+ nsamples: u64,
+ first_blocks: Option<(WVHeader, Vec<u8>)>,
+ srate: u32,
+ known_frames: Vec<FrameSeekInfo>,
+}
+
+impl<'a> WavPackDemuxer<'a> {
+ fn new(io: &'a mut ByteReader<'a>) -> Self {
+ Self {
+ src: io,
+ samplepos: 0,
+ nsamples: 0,
+ first_blocks: None,
+ srate: 0,
+ known_frames: Vec::new(),
+ }
+ }
+ fn read_blocks(&mut self) -> DemuxerResult<(WVHeader, Vec<u8>)> {
+ let mut hdrbuf = [0u8; WV_HEADER_SIZE];
+ let mut buf: Vec<u8> = Vec::new();
+ let mut first = true;
+ let mut refhdr = WVHeader::default();
+ loop {
+ self.src.read_buf(&mut hdrbuf)?;
+ let hdr = WVHeader::parse(&hdrbuf)?;
+ if first {
+ validate!(hdr.is_start_block());
+ refhdr = hdr;
+ first = false;
+ } else {
+ validate!(refhdr.block_eq(&hdr));
+ }
+ buf.extend_from_slice(&hdrbuf);
+ let pos = buf.len();
+ buf.resize(pos + hdr.get_size(), 0);
+ self.src.read_buf(&mut buf[pos..])?;
+
+ if hdr.is_end_block() {
+ break;
+ }
+ }
+ Ok((refhdr, buf))
+ }
+}
+
+impl<'a> DemuxCore<'a> for WavPackDemuxer<'a> {
+ fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+
+ let (hdr, buf) = self.read_blocks()?;
+
+ let srate = hdr.get_sample_rate();
+ validate!(srate != 0);
+ let channels = if !hdr.is_end_block() {
+ let mut ch_count = 0;
+ let mut off = 0;
+ loop {
+ let hdr = WVHeader::parse(&buf[off..]).unwrap();
+ off += WV_HEADER_SIZE + hdr.get_size();
+ ch_count += hdr.get_num_channels();
+ if hdr.is_end_block() {
+ break;
+ }
+ }
+ ch_count
+ } else {
+ hdr.get_num_channels()
+ };
+
+ self.nsamples = hdr.tot_samples;
+
+ let mut fmt = SND_S16P_FORMAT;
+ if (hdr.flags & WV_FLAG_FLOATS) != 0 {
+ fmt.float = true;
+ } else {
+ fmt.bits = (((hdr.flags & 3) + 1) * 8) as u8;
+ }
+
+ let ahdr = NAAudioInfo::new(srate, channels, SND_S16P_FORMAT, 1);
+ let ainfo = NACodecInfo::new("wavpack", NACodecTypeInfo::Audio(ahdr), Some(buf.clone()));
+ strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, srate)).unwrap();
+ seek_index.mode = SeekIndexMode::Automatic;
+ self.srate = srate;
+ self.known_frames = Vec::with_capacity(((self.nsamples + u64::from(srate) - 1) / u64::from(srate)) as usize);
+ self.known_frames.push(FrameSeekInfo { off: 0, samplepos: hdr.block_index });
+
+ self.first_blocks = Some((hdr, buf));
+ Ok(())
+ }
+ fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+ if self.first_blocks.is_some() {
+ let mut fb = None;
+ std::mem::swap(&mut fb, &mut self.first_blocks);
+ let (refhdr, buf) = fb.unwrap();
+ let stream = strmgr.get_stream(0).unwrap();
+ let (tb_num, tb_den) = stream.get_timebase();
+ let ts = NATimeInfo::new(Some(self.samplepos), None, None, tb_num, tb_den);
+ let pkt = NAPacket::new(stream, ts, true, buf);
+
+ self.samplepos += u64::from(refhdr.block_samples);
+
+ return Ok(pkt);
+ }
+ if self.samplepos == self.nsamples {
+ return Err(DemuxerError::EOF);
+ }
+ let cur_off = self.src.tell();
+ let cur_spos = self.samplepos;
+ let (refhdr, buf) = self.read_blocks()?;
+
+ let stream = strmgr.get_stream(0).unwrap();
+ let (tb_num, tb_den) = stream.get_timebase();
+ let ts = NATimeInfo::new(Some(self.samplepos), None, None, tb_num, tb_den);
+ let pkt = NAPacket::new(stream, ts, true, buf);
+
+ self.samplepos += u64::from(refhdr.block_samples);
+ if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos < cur_spos {
+ self.known_frames.push(FrameSeekInfo{off: cur_off, samplepos: cur_spos });
+ }
+
+ Ok(pkt)
+ }
+ fn seek(&mut self, time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
+ self.first_blocks = None;
+ if let NATimePoint::Milliseconds(ms) = time {
+ let samppos = ms * u64::from(self.srate) / 1000;
+ if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos >= samppos {
+ for point in self.known_frames.iter().rev() {
+ if point.samplepos <= samppos {
+ self.src.seek(SeekFrom::Start(point.off))?;
+ self.samplepos = point.samplepos;
+ return Ok(());
+ }
+ }
+ } else {
+ let mut hdrbuf = [0u8; WV_HEADER_SIZE];
+ loop {
+ self.src.peek_buf(&mut hdrbuf)?;
+ let hdr = WVHeader::parse(&hdrbuf)?;
+ if hdr.is_start_block() {
+ self.known_frames.push(FrameSeekInfo{off: self.src.tell(), samplepos: hdr.block_index });
+ if hdr.block_index <= samppos && hdr.block_index + u64::from(hdr.block_samples) > samppos {
+ self.samplepos = hdr.block_index;
+ return Ok(());
+ }
+ if hdr.block_index > samppos {
+ break;
+ }
+ }
+ self.src.read_skip(WV_HEADER_SIZE + hdr.get_size())?
+ }
+ }
+ Err(DemuxerError::SeekError)
+ } else {
+ Err(DemuxerError::NotPossible)
+ }
+ }
+}
+
+impl<'a> NAOptionHandler for WavPackDemuxer<'a> {
+ fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+ fn set_options(&mut self, _options: &[NAOption]) { }
+ fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+
+pub struct WavPackDemuxerCreator { }
+
+impl DemuxerCreator for WavPackDemuxerCreator {
+ fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+ Box::new(WavPackDemuxer::new(br))
+ }
+ fn get_name(&self) -> &'static str { "wavpack" }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use std::fs::File;
+
+ #[test]
+ fn test_wavpack_demux() {
+ let mut file = File::open("assets/LLaudio/wv/false_stereo.wv").unwrap();
+ let mut fr = FileReader::new_read(&mut file);
+ let mut br = ByteReader::new(&mut fr);
+ let mut dmx = WavPackDemuxer::new(&mut br);
+ let mut sm = StreamManager::new();
+ let mut si = SeekIndex::new();
+ dmx.open(&mut sm, &mut si).unwrap();
+ loop {
+ let pktres = dmx.get_frame(&mut sm);
+ if let Err(e) = pktres {
+ if (e as i32) == (DemuxerError::EOF as i32) { break; }
+ panic!("error");
+ }
+ let pkt = pktres.unwrap();
+ println!("Got {}", pkt);
+ }
+ }
+}
--- /dev/null
+extern crate nihav_core;
+extern crate nihav_codec_support;
+
+#[allow(clippy::unreadable_literal)]
+#[allow(clippy::verbose_bit_mask)]
+mod codecs;
+#[allow(clippy::unreadable_literal)]
+mod demuxers;
+pub use crate::codecs::llaudio_register_all_decoders;
+pub use crate::demuxers::llaudio_register_all_demuxers;
extensions: ".smk",
conditions: &[CheckItem{offs: 0, cond: &CC::Or(&CC::Str(b"SMK2"), &CC::Str(b"SMK4"))}],
},
+ DetectConditions {
+ demux_name: "ape",
+ extensions: ".ape",
+ conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"MAC ") },
+ CheckItem{offs: 4, cond: &CC::In(Arg::U16LE(3800), Arg::U16LE(3990))}],
+ },
+ DetectConditions {
+ demux_name: "flac",
+ extensions: ".flac",
+ conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"fLaC") }],
+ },
+ DetectConditions {
+ demux_name: "tta",
+ extensions: ".tta",
+ conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"TTA1") }],
+ },
+ DetectConditions {
+ demux_name: "wavpack",
+ extensions: ".wv",
+ conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"wvpk") },
+ CheckItem{offs: 8, cond: &CC::In(Arg::U16LE(0x402), Arg::U16LE(0x410))}],
+ },
DetectConditions {
demux_name: "vivo",
extensions: ".viv",
CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
caps: CODEC_CAP_LOSSLESS | CODEC_CAP_INTRAONLY }
});
+ (audio-hyb; $n:expr, $fn:expr) => ({
+ CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
+ caps: CODEC_CAP_HYBRID }
+ });
}
/// Returns codec description for the provided codec short name if it is found.
desc!(video; "vivo2", "VivoActive Video 2.0", CODEC_CAP_REORDER),
desc!(audio; "g723.1", "ITU G.723.1"),
desc!(audio; "siren", "Polycom Siren"),
+
+ desc!(audio-ll; "ape", "Monkey's Audio"),
+ desc!(audio-ll; "flac", "Free Lossless Audio Codec"),
+ desc!(audio-ll; "tta", "True Audio codec"),
+ desc!(audio-hyb; "wavpack", "WavPack"),
];
static AVI_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[