#![forbid(unsafe_code)]
#![allow(
clippy::redundant_pub_crate,
reason = "crate-private helpers used by mux.rs/demux.rs; module itself is private"
)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum MpegVersion {
Mpeg1,
Mpeg2,
Mpeg25,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ChannelMode {
Stereo,
JointStereo,
DualChannel,
Mono,
}
impl ChannelMode {
pub(crate) const fn bits(self) -> u8 {
match self {
Self::Stereo => 0,
Self::JointStereo => 1,
Self::DualChannel => 2,
Self::Mono => 3,
}
}
pub(crate) const fn from_bits(bits: u8) -> Self {
match bits & 0x03 {
0 => Self::Stereo,
1 => Self::JointStereo,
2 => Self::DualChannel,
_ => Self::Mono,
}
}
}
const MPEG1_SAMPLE_RATES: [u32; 3] = [44_100, 48_000, 32_000];
const MPEG2_SAMPLE_RATES: [u32; 3] = [22_050, 24_000, 16_000];
const MPEG25_SAMPLE_RATES: [u32; 3] = [11_025, 12_000, 8_000];
const MPEG1_LAYER3_BITRATES_KBPS: [u16; 14] = [
32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320,
];
const MPEG2_LAYER3_BITRATES_KBPS: [u16; 14] =
[8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160];
pub(crate) const fn sample_rate_table(version: MpegVersion) -> [u32; 3] {
match version {
MpegVersion::Mpeg1 => MPEG1_SAMPLE_RATES,
MpegVersion::Mpeg2 => MPEG2_SAMPLE_RATES,
MpegVersion::Mpeg25 => MPEG25_SAMPLE_RATES,
}
}
pub(crate) const fn bitrate_table(version: MpegVersion) -> [u16; 14] {
match version {
MpegVersion::Mpeg1 => MPEG1_LAYER3_BITRATES_KBPS,
MpegVersion::Mpeg2 | MpegVersion::Mpeg25 => MPEG2_LAYER3_BITRATES_KBPS,
}
}
pub(crate) const fn frame_len_coefficient(version: MpegVersion) -> u32 {
match version {
MpegVersion::Mpeg1 => 144_000,
MpegVersion::Mpeg2 | MpegVersion::Mpeg25 => 72_000,
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FrameHeader {
pub version: MpegVersion,
pub bitrate_kbps: u16,
pub sample_rate: u32,
pub channel_mode: ChannelMode,
}
impl FrameHeader {
#[must_use]
pub const fn frame_len(self, padding: bool) -> usize {
let coeff = frame_len_coefficient(self.version) * self.bitrate_kbps as u32;
let base = coeff / self.sample_rate;
base as usize + if padding { 1 } else { 0 }
}
}