#![warn(rust_2018_idioms)]
#![forbid(unsafe_code)]
use symphonia_core::support_codec;
use symphonia_core::audio::{AudioBuffer, AudioBufferRef, AsAudioBufferRef, Signal, SignalSpec};
use symphonia_core::codecs::{CodecParameters, CodecDescriptor, Decoder, DecoderOptions};
use symphonia_core::codecs::{CODEC_TYPE_PCM_S8, CODEC_TYPE_PCM_S16LE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_S24LE, CODEC_TYPE_PCM_S32LE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_S16BE, CODEC_TYPE_PCM_S24BE, CODEC_TYPE_PCM_S32BE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_U8, CODEC_TYPE_PCM_U16LE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_U24LE, CODEC_TYPE_PCM_U32LE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_U16BE, CODEC_TYPE_PCM_U24BE, CODEC_TYPE_PCM_U32BE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_F32LE, CODEC_TYPE_PCM_F32BE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_F64LE, CODEC_TYPE_PCM_F64BE};
use symphonia_core::codecs::{CODEC_TYPE_PCM_ALAW, CODEC_TYPE_PCM_MULAW};
use symphonia_core::conv::FromSample;
use symphonia_core::errors::{Result, unsupported_error};
use symphonia_core::formats::Packet;
use symphonia_core::io::ByteStream;
macro_rules! read_pcm_signed {
($buf:expr, $read:expr, $shift:expr) => {
$buf.fill(| audio_planes, idx | -> Result<()> {
for plane in audio_planes.planes() {
plane[idx] = (($read as u32) << $shift) as i32;
}
Ok(())
})
};
}
macro_rules! read_pcm_unsigned {
($buf:expr, $read:expr, $shift:expr) => {
$buf.fill(| audio_planes, idx | -> Result<()> {
for plane in audio_planes.planes() {
plane[idx] = (($read as u32) << $shift).wrapping_add(0x80000000) as i32
}
Ok(())
})
};
}
macro_rules! read_pcm_floating {
($buf:expr, $read:expr) => {
$buf.fill(| audio_planes, idx | -> Result<()> {
for plane in audio_planes.planes() {
plane[idx] = i32::from_sample($read);
}
Ok(())
})
};
}
macro_rules! read_pcm_transfer_func {
($buf:expr, $func:expr) => {
$buf.fill(| audio_planes, idx | -> Result<()> {
for plane in audio_planes.planes() {
plane[idx] = i32::from_sample($func);
}
Ok(())
})
};
}
const XLAW_QUANT_MASK: u8 = 0x0f;
const XLAW_SEG_MASK: u8 = 0x70;
const XLAW_SEG_SHIFT: u32 = 4;
fn alaw_to_linear(mut a_val: u8) -> i16 {
a_val ^= 0x55;
let mut t = i16::from((a_val & XLAW_QUANT_MASK) << 4);
let seg = (a_val & XLAW_SEG_MASK) >> XLAW_SEG_SHIFT;
match seg {
0 => t += 0x8,
1 => t += 0x108,
_ => t = (t + 0x108) << (seg - 1),
}
if a_val & 0x80 == 0x80 { t } else { -t }
}
fn mulaw_to_linear(mut mu_val: u8) -> i16 {
const BIAS: i16 = 0x84;
mu_val = !mu_val;
let mut t = i16::from((mu_val & XLAW_QUANT_MASK) << 3) + BIAS;
t <<= (mu_val & XLAW_SEG_MASK) >> XLAW_SEG_SHIFT;
if mu_val & 0x80 == 0x80 { t - BIAS } else { BIAS - t }
}
pub struct PcmDecoder {
params: CodecParameters,
sample_width: u32,
buf: AudioBuffer<i32>,
}
impl Decoder for PcmDecoder {
fn try_new(params: &CodecParameters, _options: &DecoderOptions) -> Result<Self> {
let frames = match params.max_frames_per_packet {
Some(frames) => frames,
_ => return unsupported_error("pcm: maximum frames per packet is required"),
};
let rate = match params.sample_rate {
Some(rate) => rate,
_ => return unsupported_error("pcm: sample rate is required")
};
let spec = if let Some(channels) = params.channels {
SignalSpec::new(rate, channels)
}
else if let Some(layout) = params.channel_layout {
SignalSpec::new_with_layout(rate, layout)
}
else {
return unsupported_error("pcm: channels or channel_layout is required");
};
let sample_width = params.bits_per_coded_sample.unwrap_or_else(
|| params.bits_per_sample.unwrap_or(0));
if sample_width == 0 {
match params.codec {
CODEC_TYPE_PCM_F32LE | CODEC_TYPE_PCM_F32BE => (),
CODEC_TYPE_PCM_F64LE | CODEC_TYPE_PCM_F64BE => (),
CODEC_TYPE_PCM_ALAW | CODEC_TYPE_PCM_MULAW => (),
_ => return unsupported_error("pcm: unknown bits per (coded) sample."),
}
}
Ok(PcmDecoder {
params: params.clone(),
sample_width,
buf: AudioBuffer::new(frames, spec),
})
}
fn supported_codecs() -> &'static [CodecDescriptor] {
&[
support_codec!(
CODEC_TYPE_PCM_S32LE,
"pcm_s32le",
"PCM Signed 32-bit Little-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_S32BE,
"pcm_s32be",
"PCM Signed 32-bit Big-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_S24LE,
"pcm_s24le",
"PCM Signed 24-bit Little-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_S24BE,
"pcm_s24be",
"PCM Signed 24-bit Big-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_S16LE,
"pcm_s16le",
"PCM Signed 16-bit Little-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_S16BE,
"pcm_s16be",
"PCM Signed 16-bit Big-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_S8,
"pcm_s8",
"PCM Signed 8-bit Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U32LE,
"pcm_u32le",
"PCM Unsigned 32-bit Little-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U32BE,
"pcm_u32be",
"PCM Unsigned 32-bit Big-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U24LE,
"pcm_u24le",
"PCM Unsigned 24-bit Little-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U24BE,
"pcm_u24be",
"PCM Unsigned 24-bit Big-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U16LE,
"pcm_u16le",
"PCM Unsigned 16-bit Little-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U16BE,
"pcm_u16be",
"PCM Unsigned 16-bit Big-Endian Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_U8,
"pcm_u8",
"PCM Unsigned 8-bit Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_F32LE,
"pcm_f32le",
"PCM 32-bit Little-Endian Floating Point Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_F32BE,
"pcm_f32be",
"PCM 32-bit Big-Endian Floating Point Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_F64LE,
"pcm_f64le",
"PCM 64-bit Little-Endian Floating Point Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_F64BE,
"pcm_f64be",
"PCM 64-bit Big-Endian Floating Point Interleaved"
),
support_codec!(
CODEC_TYPE_PCM_ALAW ,
"pcm_alaw" ,
"PCM A-law"
),
support_codec!(
CODEC_TYPE_PCM_MULAW,
"pcm_mulaw",
"PCM Mu-law"
),
]
}
fn codec_params(&self) -> &CodecParameters {
&self.params
}
fn decode(&mut self, packet: &Packet) -> Result<AudioBufferRef<'_>> {
let mut stream = packet.as_buf_stream();
let int_shift = if self.sample_width <= 32 { 32 - self.sample_width } else { 0 };
let _ = match self.params.codec {
CODEC_TYPE_PCM_S32LE => read_pcm_signed!(self.buf, stream.read_u32()?, int_shift),
CODEC_TYPE_PCM_S32BE => read_pcm_signed!(self.buf, stream.read_be_u32()?, int_shift),
CODEC_TYPE_PCM_S24LE => read_pcm_signed!(self.buf, stream.read_u24()?, int_shift),
CODEC_TYPE_PCM_S24BE => read_pcm_signed!(self.buf, stream.read_be_u24()?, int_shift),
CODEC_TYPE_PCM_S16LE => read_pcm_signed!(self.buf, stream.read_u16()?, int_shift),
CODEC_TYPE_PCM_S16BE => read_pcm_signed!(self.buf, stream.read_be_u16()?, int_shift),
CODEC_TYPE_PCM_S8 => read_pcm_signed!(self.buf, stream.read_u8()?, int_shift),
CODEC_TYPE_PCM_U32LE => read_pcm_unsigned!(self.buf, stream.read_u32()?, int_shift),
CODEC_TYPE_PCM_U32BE => read_pcm_unsigned!(self.buf, stream.read_be_u32()?, int_shift),
CODEC_TYPE_PCM_U24LE => read_pcm_unsigned!(self.buf, stream.read_u24()?, int_shift),
CODEC_TYPE_PCM_U24BE => read_pcm_unsigned!(self.buf, stream.read_be_u24()?, int_shift),
CODEC_TYPE_PCM_U16LE => read_pcm_unsigned!(self.buf, stream.read_u16()?, int_shift),
CODEC_TYPE_PCM_U16BE => read_pcm_unsigned!(self.buf, stream.read_be_u16()?, int_shift),
CODEC_TYPE_PCM_U8 => read_pcm_unsigned!(self.buf, stream.read_u8()?, int_shift),
CODEC_TYPE_PCM_F32LE => read_pcm_floating!(self.buf, stream.read_f32()?),
CODEC_TYPE_PCM_F32BE => read_pcm_floating!(self.buf, stream.read_be_f32()?),
CODEC_TYPE_PCM_F64LE => read_pcm_floating!(self.buf, stream.read_f64()?),
CODEC_TYPE_PCM_F64BE => read_pcm_floating!(self.buf, stream.read_be_f64()?),
CODEC_TYPE_PCM_ALAW => {
read_pcm_transfer_func!(self.buf, alaw_to_linear(stream.read_u8()?))
},
CODEC_TYPE_PCM_MULAW => {
read_pcm_transfer_func!(self.buf, mulaw_to_linear(stream.read_u8()?))
},
_ => return unsupported_error("pcm: codec is unsupported.")
};
Ok(self.buf.as_audio_buffer_ref())
}
fn close(&mut self) {
}
}