--- /dev/null
+use nihav_core::frame::*;
+use nihav_core::muxers::*;
+use super::RMStreamWriter;
+
+// fourcc, codec name, interleaver, version
+static AUDIO_CODEC_REGISTRY: &[(&[u8;4], &str, &[u8;4], u8)] = &[
+ (b"lpcJ", "ra14.4", b"Int0", 3),
+ (b"28_8", "ra28.8", b"Int4", 4),
+ (b"cook", "cook", b"genr", 5),
+ (b"dnet", "ac3", b"Int0", 4),
+ (b"sipr", "sipro", b"sipr", 4),
+ (b"atrc", "atrac3", b"genr", 5),
+ (b"LSD:", "ralf", b"Int0", 6),
+ (b"raac", "aac", b"vbrs", 5),
+ (b"racp", "aac", b"vbrf", 5),
+];
+
+struct InterleaveParams {
+ block_size: usize,
+ factor: usize,
+ frames_per_blk: usize,
+}
+
+trait Interleaver {
+ fn get_flavor(&self) -> usize;
+ fn get_block_size(&self) -> usize;
+ fn get_factor(&self) -> usize;
+ fn get_frames_per_block(&self) -> usize;
+ fn add_packet(&mut self, src: &[u8]) -> bool;
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)>;
+ fn flush(&mut self);
+
+ fn get_frame_size(&self) -> usize { self.get_block_size() / self.get_frames_per_block() }
+}
+
+struct NoInterleaver {
+ frame_size: usize,
+ pkt: Option<Vec<u8>>,
+}
+impl Interleaver for NoInterleaver {
+ fn get_flavor(&self) -> usize { 0 }
+ fn get_block_size(&self) -> usize { self.frame_size }
+ fn get_factor(&self) -> usize { 1 }
+ fn get_frames_per_block(&self) -> usize { 1 }
+ fn add_packet(&mut self, src: &[u8]) -> bool {
+ if self.pkt.is_none() {
+ self.pkt = Some(src.to_vec());
+ true
+ } else {
+ false
+ }
+ }
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> {
+ let mut ret = None;
+ std::mem::swap(&mut self.pkt, &mut ret);
+ if let Some(pkt) = ret {
+ Some((pkt, true))
+ } else {
+ None
+ }
+ }
+ fn flush(&mut self) {}
+}
+
+struct Int4Interleaver {
+ flavor: usize,
+ factor: usize,
+ frame_size: usize,
+ block_size: usize,
+ fpb: usize,
+ cur_frame: usize,
+ rd_block: usize,
+ buf: Vec<u8>,
+ map: Vec<usize>,
+}
+impl Int4Interleaver {
+ fn new(frame_size: usize) -> MuxerResult<Self> {
+ let params = RA_28_8_INTERLEAVE_PARAMS;
+ for (flavor, entry) in params.iter().enumerate() {
+ if entry.block_size / entry.frames_per_blk == frame_size {
+ let full_size = entry.frames_per_blk * entry.factor;
+ let mut map = vec![0; full_size];
+ for i in 0..full_size {
+ let fval = i * entry.factor;
+ let mapped = (fval % full_size) + fval / full_size;
+ map[mapped] = i;
+ }
+
+ return Ok(Self {
+ flavor,
+ frame_size,
+ map,
+ factor: entry.factor,
+ block_size: entry.block_size,
+ fpb: entry.frames_per_blk,
+ cur_frame: 0,
+ rd_block: 0,
+ buf: vec![0; entry.block_size * entry.factor],
+ });
+ }
+ }
+ Err(MuxerError::UnsupportedFormat)
+ }
+}
+impl Interleaver for Int4Interleaver {
+ fn get_flavor(&self) -> usize { self.flavor }
+ fn get_block_size(&self) -> usize { self.block_size }
+ fn get_factor(&self) -> usize { self.factor }
+ fn get_frames_per_block(&self) -> usize { self.fpb }
+ fn add_packet(&mut self, src: &[u8]) -> bool {
+ if self.cur_frame == self.factor * self.fpb {
+ return false;
+ }
+ let pos = self.map[self.cur_frame];
+ self.buf[pos * self.frame_size..][..self.frame_size].copy_from_slice(&src);
+ self.cur_frame += 1;
+ true
+ }
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> {
+ if self.cur_frame == self.factor * self.fpb {
+ let first = self.rd_block == 0;
+ let src = &self.buf[self.rd_block * self.block_size..][..self.block_size];
+ self.rd_block += 1;
+ if self.rd_block == self.factor {
+ self.rd_block = 0;
+ self.cur_frame = 0;
+ }
+ Some((src.to_vec(), first))
+ } else {
+ None
+ }
+ }
+ fn flush(&mut self) {
+ if self.cur_frame != 0 {
+ self.cur_frame = self.factor * self.fpb;
+ }
+ }
+}
+
+struct GenericInterleaver {
+ flavor: usize,
+ factor: usize,
+ frame_size: usize,
+ block_size: usize,
+ fpb: usize,
+ cur_frame: usize,
+ rd_block: usize,
+ buf: Vec<u8>,
+ map: Vec<usize>,
+}
+impl GenericInterleaver {
+ fn new(frame_size: usize, fcc: [u8; 4]) -> MuxerResult<Self> {
+ let params = match &fcc {
+ b"atrc" => ATRAC_INTERLEAVE_PARAMS,
+ b"cook" => COOK_INTERLEAVE_PARAMS,
+ b"sipr" => SIPRO_INTERLEAVE_PARAMS,
+ _ => return Err(MuxerError::UnsupportedFormat),
+ };
+ for (flavor, entry) in params.iter().enumerate() {
+ if entry.block_size / entry.frames_per_blk == frame_size {
+ let full_size = entry.frames_per_blk * entry.factor;
+ let mut map = vec![0; full_size];
+
+ let mut frm = 0;
+ let mut blk = 0;
+ let mut even = true;
+ for dst in map.iter_mut() {
+ let mapped = blk * entry.frames_per_blk + frm;
+ blk += 2;
+ if blk >= entry.factor {
+ if even {
+ blk = 1;
+ } else {
+ blk = 0;
+ frm += 1;
+ }
+ even = !even;
+ }
+ *dst = mapped;
+ }
+
+ return Ok(Self {
+ flavor,
+ frame_size,
+ map,
+ factor: entry.factor,
+ block_size: entry.block_size,
+ fpb: entry.frames_per_blk,
+ cur_frame: 0,
+ rd_block: 0,
+ buf: vec![0; entry.block_size * entry.factor],
+ });
+ }
+ }
+ Err(MuxerError::UnsupportedFormat)
+ }
+}
+impl Interleaver for GenericInterleaver {
+ fn get_flavor(&self) -> usize { self.flavor }
+ fn get_block_size(&self) -> usize { self.block_size }
+ fn get_factor(&self) -> usize { self.factor }
+ fn get_frames_per_block(&self) -> usize { self.fpb }
+ fn add_packet(&mut self, src: &[u8]) -> bool {
+ if self.cur_frame == self.factor * self.fpb {
+ return false;
+ }
+ let pos = self.map[self.cur_frame];
+ self.buf[pos * self.frame_size..][..self.frame_size].copy_from_slice(&src);
+ self.cur_frame += 1;
+ true
+ }
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> {
+ if self.cur_frame == self.factor * self.fpb {
+ let first = self.rd_block == 0;
+ let src = &self.buf[self.rd_block * self.block_size..][..self.block_size];
+ self.rd_block += 1;
+ if self.rd_block == self.factor {
+ self.rd_block = 0;
+ self.cur_frame = 0;
+ }
+ Some((src.to_vec(), first))
+ } else {
+ None
+ }
+ }
+ fn flush(&mut self) {
+ if self.cur_frame != 0 {
+ self.cur_frame = self.factor * self.fpb;
+ }
+ }
+}
+
+struct SiproInterleaver {
+ block_size: usize,
+ factor: usize,
+ flavor: usize,
+ buf: Vec<u8>,
+ wr_pos: usize,
+ rd_pos: usize,
+}
+impl SiproInterleaver {
+ fn new(mut frame_size: usize) -> MuxerResult<Self> {
+ if frame_size == 0 {
+ return Err(MuxerError::UnsupportedFormat);
+ }
+ while frame_size < 200 {
+ frame_size <<= 1;
+ }
+ for (flavor, entry) in SIPRO_INTERLEAVE_PARAMS.iter().enumerate() {
+ if entry.block_size == frame_size {
+ return Ok(Self {
+ block_size: entry.block_size,
+ factor: entry.factor,
+ flavor,
+ buf: vec![0; entry.block_size * entry.factor],
+ wr_pos: 0,
+ rd_pos: 0,
+ });
+ }
+ }
+ Err(MuxerError::UnsupportedFormat)
+ }
+}
+impl Interleaver for SiproInterleaver {
+ fn get_flavor(&self) -> usize { self.flavor }
+ fn get_block_size(&self) -> usize { self.block_size }
+ fn get_factor(&self) -> usize { self.factor }
+ fn get_frames_per_block(&self) -> usize { 1 }
+ fn add_packet(&mut self, src: &[u8]) -> bool {
+ if self.wr_pos < self.factor {
+ self.buf[self.wr_pos * self.block_size..][..self.block_size].copy_from_slice(src);
+ self.wr_pos += 1;
+ true
+ } else {
+ false
+ }
+ }
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> {
+ if self.wr_pos == self.factor {
+ let first = self.rd_pos == 0;
+ if self.rd_pos == 0 {
+ sipro_scramble(&mut self.buf, self.factor, self.block_size);
+ }
+ let ret = self.buf[self.rd_pos * self.block_size..][..self.block_size].to_vec();
+ self.rd_pos += 1;
+ if self.rd_pos == self.factor {
+ self.rd_pos = 0;
+ self.wr_pos = 0;
+ }
+ Some((ret, first))
+ } else {
+ None
+ }
+ }
+ fn flush(&mut self) {
+ if self.wr_pos != self.factor {
+ self.wr_pos = self.factor;
+ }
+ }
+}
+
+fn sipro_scramble(buf: &mut [u8], factor: usize, fsize: usize) {
+ let stride = factor * fsize * 2 / 96;
+ for &swap_pair in SIPRO_SWAPS.iter() {
+ let mut sidx = usize::from(swap_pair[0]) * stride;
+ let mut didx = usize::from(swap_pair[1]) * stride;
+ for _ in 0..stride {
+ let in0 = buf[sidx >> 1];
+ let in1 = buf[didx >> 1];
+ let nib0 = (in0 >> ((sidx & 1) * 4)) & 0xF;
+ let nib1 = (in1 >> ((didx & 1) * 4)) & 0xF;
+
+ buf[didx >> 1] = (nib0 << (4 * (didx & 1))) | (in1 & (0xF << (4 * (!didx & 1))));
+ buf[sidx >> 1] = (nib1 << (4 * (sidx & 1))) | (in0 & (0xF << (4 * (!sidx & 1))));
+
+ sidx += 1;
+ didx += 1;
+ }
+ }
+}
+
+struct AACInterleaver {
+ frame_size: usize,
+ data: Vec<u8>,
+ sizes: Vec<usize>,
+ full: bool,
+}
+impl AACInterleaver {
+ fn new(frame_size: usize) -> Self {
+ Self {
+ frame_size,
+ data: Vec::with_capacity(frame_size * 3 / 2),
+ sizes: Vec::with_capacity((frame_size / 128).max(8)),
+ full: false,
+ }
+ }
+}
+impl Interleaver for AACInterleaver {
+ fn get_flavor(&self) -> usize { 0 }
+ fn get_block_size(&self) -> usize { self.frame_size }
+ fn get_factor(&self) -> usize { 1 }
+ fn get_frames_per_block(&self) -> usize { 1 }
+ fn add_packet(&mut self, src: &[u8]) -> bool {
+ if !self.full {
+ self.data.extend_from_slice(src);
+ self.sizes.push(src.len());
+ if self.data.len() >= self.frame_size {
+ self.full = true;
+ }
+ true
+ } else {
+ false
+ }
+ }
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> {
+ if self.full {
+ let mut dst = Vec::with_capacity(self.frame_size);
+ let mut gw = GrowableMemoryWriter::new_write(&mut dst);
+ let mut bw = ByteWriter::new(&mut gw);
+ bw.write_u16be((self.sizes.len() * 16) as u16).unwrap();
+ for &pkt_size in self.sizes.iter() {
+ bw.write_u16be(pkt_size as u16).unwrap();
+ }
+ bw.write_buf(&self.data).unwrap();
+
+ self.data.clear();
+ self.sizes.clear();
+ self.full = false;
+
+ Some((dst, true))
+ } else {
+ None
+ }
+ }
+ fn flush(&mut self) {
+ if !self.sizes.is_empty() {
+ self.full = true;
+ }
+ }
+}
+
+struct InterleaveInfo {
+ fcc: [u8; 4],
+ il_fcc: [u8; 4],
+ block_size: usize,
+ frame_size: usize,
+ factor: usize,
+ flavor: usize,
+}
+
+struct AudioStreamWriter {
+ fcc: [u8; 4],
+ il_fcc: [u8; 4],
+ is_raw: bool,
+ version: u8,
+ header_pos: u64,
+ interleave: Box<dyn Interleaver>,
+ data_size: usize,
+}
+
+impl RMStreamWriter for AudioStreamWriter {
+ fn write_header(&mut self, bw: &mut ByteWriter, astream: &NAStream) -> MuxerResult<()> {
+ self.header_pos = bw.tell();
+ if self.version < 6 {
+ bw.write_buf(b".ra\xFD")?;
+ bw.write_u16be(self.version.into())?;
+ }
+
+ let il_info = InterleaveInfo {
+ fcc: self.fcc,
+ il_fcc: self.il_fcc,
+ block_size: self.interleave.get_block_size(),
+ frame_size: self.interleave.get_frame_size(),
+ factor: self.interleave.get_factor(),
+ flavor: self.interleave.get_flavor(),
+ };
+
+ match self.version {
+ 3 => write_aformat3(bw, astream, &il_info)?,
+ 4 => write_aformat4(bw, astream, &il_info)?,
+ 5 => write_aformat5(bw, astream, &il_info)?,
+ 6 => write_lsd(bw, astream)?,
+ _ => unreachable!(),
+ }
+ Ok(())
+ }
+ fn queue_packet(&mut self, pkt: NAPacket) -> bool {
+ let src = pkt.get_buffer();
+ self.data_size += src.len();
+ let frame_size = self.interleave.get_frame_size();
+ if !self.is_raw {
+ let mut ret = false;
+ for frame in src.chunks(frame_size) {
+ ret = self.interleave.add_packet(frame);
+ }
+ ret
+ } else {
+ self.interleave.add_packet(&src)
+ }
+ }
+ fn get_packet(&mut self) -> Option<(Vec<u8>, bool)> { self.interleave.get_packet() }
+ fn flush(&mut self) { self.interleave.flush() }
+ fn finish(&mut self, bw: &mut ByteWriter) -> MuxerResult<()> {
+ let cur_pos = bw.tell();
+ match self.version {
+ 3 => {
+ bw.seek(SeekFrom::Start(self.header_pos + 18))?;
+ bw.write_u32be(self.data_size as u32)?;
+ },
+ 4 | 5 => {
+ bw.seek(SeekFrom::Start(self.header_pos + 12))?;
+ bw.write_u32be(self.data_size/*+header_size*/ as u32)?;
+ bw.seek(SeekFrom::Current(12))?;
+ bw.write_u32be(self.data_size as u32)?;
+ },
+ 6 => unimplemented!(),
+ _ => unreachable!(),
+ };
+ bw.seek(SeekFrom::Start(cur_pos))?;
+ Ok(())
+ }
+}
+
+fn write_audio_metadata(bw: &mut ByteWriter) -> MuxerResult<()> {
+ bw.write_byte(0)?; // title_string_length
+ bw.write_byte(0)?; // author_string_length
+ bw.write_byte(0)?; // copyright_string_length
+ bw.write_byte(0)?; // user_string_length
+ Ok(())
+}
+
+fn write_aformat3(bw: &mut ByteWriter, _stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> {
+ let start = bw.tell();
+ bw.write_u16be(0)?; // header_bytes
+ bw.write_u16be(il_info.flavor as u16)?;
+ bw.write_u32be(il_info.frame_size as u32)?; // granularity
+ bw.write_u32be(0)?; // bytes per minute
+ bw.write_u32be(0)?; // total bytes
+ write_audio_metadata(bw)?;
+ bw.write_byte(0)?; //can_copy
+ bw.write_byte(4)?; // FCC length
+ bw.write_buf(&il_info.fcc)?;
+ let end = bw.tell();
+ bw.seek(SeekFrom::Start(start))?;
+ bw.write_u16be((end - start - 2) as u16)?;
+ bw.seek(SeekFrom::Start(end))?;
+
+ Ok(())
+}
+
+fn write_aformat4(bw: &mut ByteWriter, stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> {
+ let info = stream.get_info().get_properties().get_audio_info().unwrap();
+
+ bw.write_u16be(0)?;
+ let start = bw.tell();
+ bw.write_buf(b".ra4")?;
+ bw.write_u32be(0)?; // data size
+ bw.write_u16be(4)?; // version
+ bw.write_u16be(0)?; // revision
+ bw.write_u16be(0)?; // header_bytes
+ bw.write_u16be(il_info.flavor as u16)?;
+ bw.write_u32be(il_info.frame_size as u32)?; // granularity
+ bw.write_u32be(0)?; // total bytes
+ bw.write_u32be(0)?; // bytes_per_minute
+ bw.write_u32be(0)?; // bytes_per_minute2
+ bw.write_u16be(il_info.factor as u16)?;
+ bw.write_u16be(il_info.block_size as u16)?;
+ bw.write_u16be(0)?; // user data
+ bw.write_u32be(info.sample_rate)?; // sample rate
+ bw.write_u32be(info.format.bits.into())?; // sample size
+ bw.write_u16be(info.channels.into())?; // num channels
+ bw.write_byte(4)?; // ileave ID len
+ bw.write_buf(&il_info.il_fcc)?;
+ bw.write_byte(4)?; // codec ID len
+ bw.write_buf(&il_info.fcc)?;
+ bw.write_byte(if &il_info.il_fcc == b"Int0" { 0 } else { 1 })?;
+ bw.write_byte(7)?; // can_copy
+ bw.write_byte(0)?; // stream_type
+ write_audio_metadata(bw)?;
+ let end = bw.tell();
+ bw.seek(SeekFrom::Start(start + 12))?;
+ bw.write_u16be((end - start - 4) as u16)?;
+ bw.seek(SeekFrom::Start(end))?;
+
+ Ok(())
+}
+
+fn write_aformat5(bw: &mut ByteWriter, stream: &NAStream, il_info: &InterleaveInfo) -> MuxerResult<()> {
+ let info = stream.get_info().get_properties().get_audio_info().unwrap();
+
+ bw.write_u16be(0)?;
+ let start = bw.tell();
+ bw.write_buf(b".ra5")?;
+ bw.write_u32be(0)?; // data size
+ bw.write_u16be(5)?; // version
+ bw.write_u16be(0)?; // revision
+ bw.write_u16be(0)?; // header_bytes
+ bw.write_u16be(il_info.flavor as u16)?;
+ bw.write_u32be(il_info.block_size as u32)?; // granularity
+ bw.write_u32be(0)?; // total bytes
+ bw.write_u32be(0)?; // bytes_per_minute
+ bw.write_u32be(0)?; // bytes_per_minute2
+ bw.write_u16be(il_info.factor as u16)?;
+ bw.write_u16be(il_info.block_size as u16)?;
+ bw.write_u16be(il_info.frame_size as u16)?;
+ bw.write_u16be(0)?; // user data
+ bw.write_u32be(info.sample_rate)?; // sample rate
+ bw.write_u32be(info.sample_rate)?; // actual sample rate
+ bw.write_u32be(info.format.bits.into())?; // sample size
+ bw.write_u16be(info.channels.into())?; // num channels
+ bw.write_buf(&il_info.il_fcc)?;
+ bw.write_buf(&il_info.fcc)?;
+ bw.write_byte(if &il_info.il_fcc == b"Int0" { 0 } else { 1 })?;
+ bw.write_byte(7)?; // can_copy
+ bw.write_byte(0)?; // stream_type
+ bw.write_byte(0)?; // has_interleave_pattern
+ if let Some(edata) = stream.get_info().get_extradata() {
+ if !matches!(&il_info.fcc, b"raac" | b"racp") {
+ bw.write_u32be(edata.len() as u32)?;
+ bw.write_buf(&edata)?;
+ } else {
+ bw.write_u32be((edata.len() + 1) as u32)?;
+ bw.write_byte(2)?;
+ bw.write_buf(&edata)?;
+ }
+ } else {
+ bw.write_u32be(0)?;
+ }
+ let end = bw.tell();
+ bw.seek(SeekFrom::Start(start + 12))?;
+ bw.write_u16be((end - start - 4) as u16)?;
+ bw.seek(SeekFrom::Start(end))?;
+
+ Ok(())
+}
+
+fn write_lsd(bw: &mut ByteWriter, stream: &NAStream) -> MuxerResult<()> {
+ if let Some(edata) = stream.get_info().get_extradata() {
+ bw.write_buf(&edata)?;
+ }
+ Ok(())
+}
+
+fn create_interleaver(id: [u8; 4], fcc: [u8; 4], ainfo: NAAudioInfo) -> MuxerResult<Box<dyn Interleaver>> {
+ let frame_size = ainfo.block_len;
+ match &id {
+ b"Int0" => Ok(Box::new(NoInterleaver{ frame_size, pkt: None })),
+ b"Int4" => Ok(Box::new(Int4Interleaver::new(frame_size)?)),
+ b"sipr" => Ok(Box::new(SiproInterleaver::new(frame_size)?)),
+ b"genr" => Ok(Box::new(GenericInterleaver::new(frame_size, fcc)?)),
+ b"vbrs" | b"vbrf" => Ok(Box::new(AACInterleaver::new(1024))),
+ _ => unimplemented!(),
+ }
+}
+
+pub fn create_audio_stream(stream: &NAStream) -> MuxerResult<Box<dyn RMStreamWriter>> {
+ let info = stream.get_info();
+ let cname = info.get_name();
+ let mut fourcc = [0u8; 4];
+ let mut ileave = [0u8; 4];
+ let mut version = 0;
+ for &(fcc, name, ileaver, cversion) in AUDIO_CODEC_REGISTRY.iter() {
+ if name == cname {
+ fourcc = *fcc;
+ ileave = *ileaver;
+ version = cversion;
+ break;
+ }
+ }
+ if version > 0 {
+ let ainfo = info.get_properties().get_audio_info().unwrap();
+ Ok(Box::new(AudioStreamWriter {
+ fcc: fourcc,
+ il_fcc: ileave,
+ is_raw: &ileave == b"Int0",
+ version,
+ interleave: create_interleaver(ileave, fourcc, ainfo)?,
+ header_pos: 0,
+ data_size: 0,
+ }))
+ } else {
+ Err(MuxerError::UnsupportedFormat)
+ }
+}
+
+const SIPRO_SWAPS: [[u8; 2]; 38] = [
+ [ 0, 63 ], [ 1, 22 ], [ 2, 44 ], [ 3, 90 ],
+ [ 5, 81 ], [ 7, 31 ], [ 8, 86 ], [ 9, 58 ],
+ [ 10, 36 ], [ 12, 68 ], [ 13, 39 ], [ 14, 73 ],
+ [ 15, 53 ], [ 16, 69 ], [ 17, 57 ], [ 19, 88 ],
+ [ 20, 34 ], [ 21, 71 ], [ 24, 46 ], [ 25, 94 ],
+ [ 26, 54 ], [ 28, 75 ], [ 29, 50 ], [ 32, 70 ],
+ [ 33, 92 ], [ 35, 74 ], [ 38, 85 ], [ 40, 56 ],
+ [ 42, 87 ], [ 43, 65 ], [ 45, 59 ], [ 48, 79 ],
+ [ 49, 93 ], [ 51, 89 ], [ 55, 95 ], [ 61, 76 ],
+ [ 67, 83 ], [ 77, 80 ]
+];
+
+const RA_28_8_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
+ InterleaveParams { block_size: 228, factor: 12, frames_per_blk: 6 },
+];
+const SIPRO_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
+ InterleaveParams { block_size: 232, factor: 6, frames_per_blk: 16 },
+ InterleaveParams { block_size: 304, factor: 6, frames_per_blk: 16 },
+ InterleaveParams { block_size: 296, factor: 6, frames_per_blk: 16 },
+ InterleaveParams { block_size: 320, factor: 6, frames_per_blk: 16 }
+];
+const ATRAC_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
+ InterleaveParams { block_size: 768, factor: 20, frames_per_blk: 4 },
+ InterleaveParams { block_size: 1088, factor: 20, frames_per_blk: 4 },
+ InterleaveParams { block_size: 912, factor: 30, frames_per_blk: 3 },
+ InterleaveParams { block_size: 1152, factor: 30, frames_per_blk: 3 },
+ InterleaveParams { block_size: 1272, factor: 30, frames_per_blk: 3 },
+ InterleaveParams { block_size: 1024, factor: 30, frames_per_blk: 2 },
+ InterleaveParams { block_size: 768, factor: 10, frames_per_blk: 1 },
+ InterleaveParams { block_size: 1024, factor: 10, frames_per_blk: 1 }
+];
+const COOK_INTERLEAVE_PARAMS: &[InterleaveParams] = &[
+ InterleaveParams { block_size: 288, factor: 8, frames_per_blk: 9 },
+ InterleaveParams { block_size: 352, factor: 8, frames_per_blk: 11 },
+ InterleaveParams { block_size: 564, factor: 8, frames_per_blk: 12 },
+ InterleaveParams { block_size: 600, factor: 9, frames_per_blk: 10 },
+ InterleaveParams { block_size: 651, factor: 14, frames_per_blk: 7 },
+ InterleaveParams { block_size: 640, factor: 15, frames_per_blk: 5 },
+ InterleaveParams { block_size: 744, factor: 20, frames_per_blk: 4 },
+ InterleaveParams { block_size: 558, factor: 16, frames_per_blk: 6 },
+ InterleaveParams { block_size: 288, factor: 6, frames_per_blk: 12 },
+ InterleaveParams { block_size: 580, factor: 10, frames_per_blk: 10 },
+ InterleaveParams { block_size: 564, factor: 14, frames_per_blk: 6 },
+ InterleaveParams { block_size: 640, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 744, factor: 20, frames_per_blk: 4 },
+ InterleaveParams { block_size: 834, factor: 30, frames_per_blk: 3 },
+ InterleaveParams { block_size: 644, factor: 20, frames_per_blk: 4 },
+ InterleaveParams { block_size: 600, factor: 9, frames_per_blk: 10 },
+ InterleaveParams { block_size: 651, factor: 14, frames_per_blk: 7 },
+ InterleaveParams { block_size: 528, factor: 8, frames_per_blk: 11 },
+ InterleaveParams { block_size: 600, factor: 10, frames_per_blk: 10 },
+ InterleaveParams { block_size: 600, factor: 10, frames_per_blk: 10 },
+ InterleaveParams { block_size: 465, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 465, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 640, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 640, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 930, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 1400, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 376, factor: 8, frames_per_blk: 11 },
+ InterleaveParams { block_size: 930, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 1400, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 640, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 1395, factor: 16, frames_per_blk: 5 },
+ InterleaveParams { block_size: 1143, factor: 10, frames_per_blk: 3 },
+ InterleaveParams { block_size: 1064, factor: 10, frames_per_blk: 2 },
+ InterleaveParams { block_size: 778, factor: 1, frames_per_blk: 1 }
+];