From 8809c626d8dbe3c3f09f15396410680cc4c1fbba Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Sat, 7 Dec 2019 18:57:59 +0100 Subject: [PATCH] core/soundcvt: fix some bugs and switch to generic sample reader/writers --- nihav-core/src/soundcvt/mod.rs | 424 +++++++++++++++++---------------- 1 file changed, 219 insertions(+), 205 deletions(-) diff --git a/nihav-core/src/soundcvt/mod.rs b/nihav-core/src/soundcvt/mod.rs index 9db0b79..bc34b23 100644 --- a/nihav-core/src/soundcvt/mod.rs +++ b/nihav-core/src/soundcvt/mod.rs @@ -81,15 +81,6 @@ fn remix_f32(ch_op: &ChannelOp, src: &Vec, dst: &mut Vec) { } } -fn read_samples(src: &NAAudioBuffer, mut idx: usize, dst: &mut Vec) { - let stride = src.get_stride(); - let data = src.get_data(); - for out in dst.iter_mut() { - *out = data[idx]; - idx += stride; - } -} - trait FromFmt { fn cvt_from(val: T) -> Self; } @@ -155,102 +146,167 @@ impl IntoFmt for T where U: FromFmt { } -fn read_samples_i32(src: &NAAudioBuffer, mut idx: usize, dst: &mut Vec) where i32: FromFmt { - let stride = src.get_stride(); - let data = src.get_data(); - for out in dst.iter_mut() { - *out = i32::cvt_from(data[idx]); - idx += stride; +trait SampleReader { + fn get_samples_i32(&self, pos: usize, dst: &mut Vec); + fn get_samples_f32(&self, pos: usize, dst: &mut Vec); +} + +struct GenericSampleReader<'a, T:Copy> { + data: &'a [T], + stride: usize, +} + +impl<'a, T:Copy+IntoFmt+IntoFmt> SampleReader for GenericSampleReader<'a, T> { + fn get_samples_i32(&self, pos: usize, dst: &mut Vec) { + let mut off = pos; + for el in dst.iter_mut() { + *el = self.data[off].cvt_into(); + off += self.stride; + } } + fn get_samples_f32(&self, pos: usize, dst: &mut Vec) { + let mut off = pos; + for el in dst.iter_mut() { + *el = self.data[off].cvt_into(); + off += self.stride; + } + } +} + +struct PackedSampleReader<'a> { + data: &'a [u8], + fmt: NASoniton, + bpp: usize, } -fn read_samples_f32(src: &NAAudioBuffer, mut idx: usize, dst: &mut Vec) where f32: FromFmt { - let stride = src.get_stride(); - let data = src.get_data(); - for out in dst.iter_mut() { - *out = f32::cvt_from(data[idx]); - idx += stride; +impl<'a> PackedSampleReader<'a> { + fn new(data: &'a [u8], fmt: NASoniton) -> Self { + if (fmt.bits & 7) != 0 { unimplemented!(); } + let bpp = (fmt.bits >> 3) as usize; + Self { data, fmt, bpp } + } + fn get_samples(&self, pos: usize, dst: &mut Vec) where u8: IntoFmt, i16: IntoFmt, i32: IntoFmt, f32: IntoFmt { + let mut offset = pos * self.bpp * dst.len(); + + for el in dst.iter_mut() { + let src = &self.data[offset..]; + *el = if !self.fmt.float { + match (self.bpp, self.fmt.be) { + (1, _) => src[0].cvt_into(), + (2, true) => (read_u16be(src).unwrap() as i16).cvt_into(), + (2, false) => (read_u16le(src).unwrap() as i16).cvt_into(), + (3, true) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(), + (3, false) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(), + (4, true) => (read_u32be(src).unwrap() as i32).cvt_into(), + (4, false) => (read_u32be(src).unwrap() as i32).cvt_into(), + _ => unreachable!(), + } + } else { + match (self.bpp, self.fmt.be) { + (4, true) => read_f32be(src).unwrap().cvt_into(), + (4, false) => read_f32le(src).unwrap().cvt_into(), + (8, true) => (read_f64be(src).unwrap() as f32).cvt_into(), + (8, false) => (read_f64le(src).unwrap() as f32).cvt_into(), + (_, _) => unreachable!(), + } + }; + offset += self.bpp; + } } } -fn read_packed(src: &NAAudioBuffer, idx: usize, dst: &mut Vec, fmt: &NASoniton) where u8: IntoFmt, i16: IntoFmt, i32: IntoFmt, f32: IntoFmt { - if (fmt.bits & 7) != 0 { unimplemented!(); } - let bytes = (fmt.bits >> 3) as usize; - let mut offset = idx * bytes * dst.len(); - let data = src.get_data(); - - for el in dst.iter_mut() { - let src = &data[offset..]; - *el = if !fmt.float { - match (bytes, fmt.be) { - (1, _) => src[0].cvt_into(), - (2, true) => (read_u16be(src).unwrap() as i16).cvt_into(), - (2, false) => (read_u16le(src).unwrap() as i16).cvt_into(), - (3, true) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(), - (3, false) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(), - (4, true) => (read_u32be(src).unwrap() as i32).cvt_into(), - (4, false) => (read_u32be(src).unwrap() as i32).cvt_into(), - _ => unreachable!(), - } - } else { - match (bytes, fmt.be) { - (4, true) => read_f32be(src).unwrap().cvt_into(), - (4, false) => read_f32le(src).unwrap().cvt_into(), - (8, true) => (read_f64be(src).unwrap() as f32).cvt_into(), - (8, false) => (read_f64le(src).unwrap() as f32).cvt_into(), - (_, _) => unreachable!(), - } - }; - offset += bytes; +impl SampleReader for PackedSampleReader<'_> { + fn get_samples_i32(&self, pos: usize, dst: &mut Vec) { + self.get_samples(pos, dst); + } + fn get_samples_f32(&self, pos: usize, dst: &mut Vec) { + self.get_samples(pos, dst); } } -fn store_samples(dst: &mut NAAudioBuffer, mut idx: usize, src: &Vec) where U: IntoFmt { - let stride = dst.get_stride(); - let data = dst.get_data_mut().unwrap(); - for src_el in src.iter() { - data[idx] = (*src_el).cvt_into(); - idx += stride; +trait SampleWriter { + fn store_samples_i32(&mut self, pos: usize, src: &Vec); + fn store_samples_f32(&mut self, pos: usize, src: &Vec); +} + +struct GenericSampleWriter<'a, T:Copy> { + data: &'a mut [T], + stride: usize, +} + +impl<'a, T:Copy+FromFmt+FromFmt> SampleWriter for GenericSampleWriter<'a, T> { + fn store_samples_i32(&mut self, pos: usize, src: &Vec) { + let mut off = pos; + for el in src.iter() { + self.data[off] = (*el).cvt_into(); + off += self.stride; + } + } + fn store_samples_f32(&mut self, pos: usize, src: &Vec) { + let mut off = pos; + for el in src.iter() { + self.data[off] = (*el).cvt_into(); + off += self.stride; + } } } -fn store_packed(dst: &mut NAAudioBuffer, idx: usize, src: &Vec, fmt: &NASoniton) where u8: FromFmt, i16: FromFmt, i32: FromFmt, f32: FromFmt { - if (fmt.bits & 7) != 0 { unimplemented!(); } - let bytes = (fmt.bits >> 3) as usize; - let mut offset = idx * bytes * src.len(); - let data = dst.get_data_mut().unwrap(); - - for el in src.iter() { - let dst = &mut data[offset..]; - if !fmt.float { - match (bytes, fmt.be) { - (1, _) => { - dst[0] = u8::cvt_from(*el); - }, - (2, true) => write_u16be(dst, i16::cvt_from(*el) as u16).unwrap(), - (2, false) => write_u16le(dst, i16::cvt_from(*el) as u16).unwrap(), - (3, true) => write_u24be(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(), - (3, false) => write_u24le(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(), - (4, true) => write_u32be(dst, i32::cvt_from(*el) as u32).unwrap(), - (4, false) => write_u32le(dst, i32::cvt_from(*el) as u32).unwrap(), - _ => unreachable!(), - }; - } else { - match (bytes, fmt.be) { - (4, true) => write_f32be(dst, f32::cvt_from(*el)).unwrap(), - (4, false) => write_f32le(dst, f32::cvt_from(*el)).unwrap(), - (8, true) => write_f64be(dst, f32::cvt_from(*el) as f64).unwrap(), - (8, false) => write_f64le(dst, f32::cvt_from(*el) as f64).unwrap(), - (_, _) => unreachable!(), - }; +struct PackedSampleWriter<'a> { + data: &'a mut [u8], + fmt: NASoniton, + bpp: usize, +} + +impl<'a> PackedSampleWriter<'a> { + fn new(data: &'a mut [u8], fmt: NASoniton) -> Self { + if (fmt.bits & 7) != 0 { unimplemented!(); } + let bpp = (fmt.bits >> 3) as usize; + Self { data, fmt, bpp } + } + + fn store_samples(&mut self, pos: usize, src: &Vec) where u8: FromFmt, i16: FromFmt, i32: FromFmt, f32: FromFmt { + let mut offset = pos * self.bpp * src.len(); + for el in src.iter() { + let dst = &mut self.data[offset..]; + if !self.fmt.float { + match (self.bpp, self.fmt.be) { + (1, _) => { + dst[0] = u8::cvt_from(*el); + }, + (2, true) => write_u16be(dst, i16::cvt_from(*el) as u16).unwrap(), + (2, false) => write_u16le(dst, i16::cvt_from(*el) as u16).unwrap(), + (3, true) => write_u24be(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(), + (3, false) => write_u24le(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(), + (4, true) => write_u32be(dst, i32::cvt_from(*el) as u32).unwrap(), + (4, false) => write_u32le(dst, i32::cvt_from(*el) as u32).unwrap(), + _ => unreachable!(), + }; + } else { + match (self.bpp, self.fmt.be) { + (4, true) => write_f32be(dst, f32::cvt_from(*el)).unwrap(), + (4, false) => write_f32le(dst, f32::cvt_from(*el)).unwrap(), + (8, true) => write_f64be(dst, f32::cvt_from(*el) as f64).unwrap(), + (8, false) => write_f64le(dst, f32::cvt_from(*el) as f64).unwrap(), + (_, _) => unreachable!(), + }; + } + offset += self.bpp; } - offset += bytes; + } +} + +impl SampleWriter for PackedSampleWriter<'_> { + fn store_samples_i32(&mut self, pos: usize, src: &Vec) { + self.store_samples(pos, src); + } + fn store_samples_f32(&mut self, pos: usize, src: &Vec) { + self.store_samples(pos, src); } } pub fn convert_audio_frame(src: &NABufferType, dst_info: &NAAudioInfo, dst_chmap: &NAChannelMap) -> Result { - let nsamples = src.get_audio_length(); + let mut nsamples = src.get_audio_length(); if nsamples == 0 { return Err(SoundConvertError::InvalidInput); } @@ -260,6 +316,10 @@ Result { return Err(SoundConvertError::InvalidInput); } + if let NABufferType::AudioPacked(_) = src { + nsamples = nsamples * 8 / (src_info.get_format().get_bits() as usize) / src_chmap.num_channels(); + } + let needs_remix = src_chmap.num_channels() != dst_chmap.num_channels(); let no_channel_needs = !needs_remix && channel_maps_equal(src_chmap, dst_chmap); let needs_reorder = !needs_remix && !no_channel_needs && channel_maps_reordered(src_chmap, dst_chmap); @@ -299,134 +359,88 @@ Result { } let mut dst_buf = ret.unwrap(); - if no_conversion { - match (src, &mut dst_buf) { - (NABufferType::AudioU8(sb), NABufferType::AudioU8(ref mut db)) => { - let mut svec = vec![0; src_chmap.num_channels()]; - let mut tvec1 = vec![0; src_chmap.num_channels()]; - let mut tvec2 = vec![0; dst_chmap.num_channels()]; - let mut dvec = vec![0; dst_chmap.num_channels()]; - for i in 0..nsamples { - read_samples(sb, i, &mut svec); - if !channel_op.is_remix() { - apply_channel_op(&channel_op, &svec, &mut dvec); - } else { - for (oel, iel) in tvec1.iter_mut().zip(svec.iter()) { - *oel = (*iel as i32) - 128; - } - remix_i32(&channel_op, &tvec1, &mut tvec2); - for (oel, iel) in dvec.iter_mut().zip(tvec2.iter()) { - *oel = (*iel + 128).min(255).max(0) as u8; - } - } - store_samples(db, i, &dvec); - } + let sr: Box = match src { + NABufferType::AudioU8(ref ab) => { + let stride = ab.get_stride(); + let data = ab.get_data(); + Box::new(GenericSampleReader { data, stride }) }, - (NABufferType::AudioI16(sb), NABufferType::AudioI16(ref mut db)) => { - let mut svec = vec![0; src_chmap.num_channels()]; - let mut tvec1 = vec![0; src_chmap.num_channels()]; - let mut tvec2 = vec![0; dst_chmap.num_channels()]; - let mut dvec = vec![0; dst_chmap.num_channels()]; - for i in 0..nsamples { - read_samples(sb, i, &mut svec); - if !channel_op.is_remix() { - apply_channel_op(&channel_op, &svec, &mut dvec); - } else { - for (oel, iel) in tvec1.iter_mut().zip(svec.iter()) { - *oel = *iel as i32; - } - remix_i32(&channel_op, &tvec1, &mut tvec2); - for (oel, iel) in dvec.iter_mut().zip(tvec2.iter()) { - *oel = (*iel).min(16383).max(-16384) as i16; - } - } - store_samples(db, i, &dvec); - } + NABufferType::AudioI16(ref ab) => { + let data = ab.get_data(); + let stride = ab.get_stride(); + Box::new(GenericSampleReader { data, stride }) }, - (NABufferType::AudioI32(sb), NABufferType::AudioI32(ref mut db)) => { - let mut svec = vec![0; src_chmap.num_channels()]; - let mut dvec = vec![0; dst_chmap.num_channels()]; - for i in 0..nsamples { - read_samples(sb, i, &mut svec); - if !channel_op.is_remix() { - apply_channel_op(&channel_op, &svec, &mut dvec); - } else { - remix_i32(&channel_op, &svec, &mut dvec); - } - store_samples(db, i, &dvec); - } + NABufferType::AudioI32(ref ab) => { + let data = ab.get_data(); + let stride = ab.get_stride(); + Box::new(GenericSampleReader { data, stride }) }, - (NABufferType::AudioF32(sb), NABufferType::AudioF32(ref mut db)) => { - let mut svec = vec![0.0; src_chmap.num_channels()]; - let mut dvec = vec![0.0; dst_chmap.num_channels()]; - for i in 0..nsamples { - read_samples(sb, i, &mut svec); - if !channel_op.is_remix() { - apply_channel_op(&channel_op, &svec, &mut dvec); - } else { - remix_f32(&channel_op, &svec, &mut dvec); - } - store_samples(db, i, &dvec); - } + NABufferType::AudioF32(ref ab) => { + let data = ab.get_data(); + let stride = ab.get_stride(); + Box::new(GenericSampleReader { data, stride }) + }, + NABufferType::AudioPacked(ref ab) => { + let data = ab.get_data(); + Box::new(PackedSampleReader::new(data, src_fmt)) }, _ => unimplemented!(), }; - } else { - let into_float = dst_fmt.float; - if !into_float { - let mut svec = vec![0i32; src_chmap.num_channels()]; - let mut dvec = vec![0i32; dst_chmap.num_channels()]; - for i in 0..nsamples { - match src { - NABufferType::AudioU8 (ref sb) => read_samples_i32(sb, i, &mut svec), - NABufferType::AudioI16(ref sb) => read_samples_i32(sb, i, &mut svec), - NABufferType::AudioI32(ref sb) => read_samples_i32(sb, i, &mut svec), - NABufferType::AudioF32(ref sb) => read_samples_i32(sb, i, &mut svec), - NABufferType::AudioPacked(ref sb) => read_packed(sb, i, &mut svec, &src_fmt), - _ => unreachable!(), - }; - if !channel_op.is_remix() { - apply_channel_op(&channel_op, &svec, &mut dvec); - } else { - remix_i32(&channel_op, &svec, &mut dvec); - } - match dst_buf { - NABufferType::AudioU8 (ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioI16(ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioI32(ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioF32(ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioPacked(ref mut buf) => store_packed(buf, i, &dvec, &dst_fmt), - _ => unreachable!(), - }; + let mut sw: Box = match dst_buf { + NABufferType::AudioU8(ref mut ab) => { + let stride = ab.get_stride(); + let data = ab.get_data_mut().unwrap(); + Box::new(GenericSampleWriter { data, stride }) + }, + NABufferType::AudioI16(ref mut ab) => { + let stride = ab.get_stride(); + let data = ab.get_data_mut().unwrap(); + Box::new(GenericSampleWriter { data, stride }) + }, + NABufferType::AudioI32(ref mut ab) => { + let stride = ab.get_stride(); + let data = ab.get_data_mut().unwrap(); + Box::new(GenericSampleWriter { data, stride }) + }, + NABufferType::AudioF32(ref mut ab) => { + let stride = ab.get_stride(); + let data = ab.get_data_mut().unwrap(); + Box::new(GenericSampleWriter { data, stride }) + }, + NABufferType::AudioPacked(ref mut ab) => { + let data = ab.get_data_mut().unwrap(); + Box::new(PackedSampleWriter::new(data, dst_fmt)) + }, + _ => unimplemented!(), + }; + + let into_float = dst_fmt.float; + if !into_float { + let mut svec = vec![0; src_chmap.num_channels()]; + let mut dvec = vec![0; dst_chmap.num_channels()]; + for i in 0..nsamples { + sr.get_samples_i32(i, &mut svec); + if !channel_op.is_remix() { + apply_channel_op(&channel_op, &svec, &mut dvec); + } else { + remix_i32(&channel_op, &svec, &mut dvec); } - } else { - let mut svec = vec![0.0f32; src_chmap.num_channels()]; - let mut dvec = vec![0.0f32; dst_chmap.num_channels()]; - for i in 0..nsamples { - match src { - NABufferType::AudioU8 (ref sb) => read_samples_f32(sb, i, &mut svec), - NABufferType::AudioI16(ref sb) => read_samples_f32(sb, i, &mut svec), - NABufferType::AudioI32(ref sb) => read_samples_f32(sb, i, &mut svec), - NABufferType::AudioF32(ref sb) => read_samples_f32(sb, i, &mut svec), - NABufferType::AudioPacked(ref sb) => read_packed(sb, i, &mut svec, &src_fmt), - _ => unreachable!(), - }; - if !channel_op.is_remix() { - apply_channel_op(&channel_op, &svec, &mut dvec); - } else { - remix_f32(&channel_op, &svec, &mut dvec); - } - match dst_buf { - NABufferType::AudioU8 (ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioI16(ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioI32(ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioF32(ref mut db) => store_samples(db, i, &dvec), - NABufferType::AudioPacked(ref mut buf) => store_packed(buf, i, &dvec, &dst_fmt), - _ => unreachable!(), - }; + sw.store_samples_i32(i, &dvec); + } + } else { + let mut svec = vec![0.0; src_chmap.num_channels()]; + let mut dvec = vec![0.0; dst_chmap.num_channels()]; + for i in 0..nsamples { + sr.get_samples_f32(i, &mut svec); + if !channel_op.is_remix() { + apply_channel_op(&channel_op, &svec, &mut dvec); + } else { + remix_f32(&channel_op, &svec, &mut dvec); } + sw.store_samples_f32(i, &dvec); } } + drop(sw); Ok(dst_buf) } -- 2.30.2