1#![forbid(unsafe_code)]
4
5use bytes::Bytes;
6
7use crate::error::Error;
8use crate::types::{ChannelMode, FrameHeader, MpegVersion, bitrate_table, sample_rate_table};
9
10const HEADER_LEN: usize = 4;
11const CRC_LEN: usize = 2;
12
13const fn version_from_bits(bits: u8) -> Option<MpegVersion> {
14 match bits & 0x03 {
15 0b00 => Some(MpegVersion::Mpeg25),
16 0b10 => Some(MpegVersion::Mpeg2),
17 0b11 => Some(MpegVersion::Mpeg1),
18 _ => None, }
20}
21
22#[derive(Debug, Clone, Default)]
28pub struct Demuxer {
29 buf: Vec<u8>,
30 header: Option<FrameHeader>,
31}
32
33impl Demuxer {
34 #[must_use]
36 pub fn new() -> Self {
37 Self::default()
38 }
39
40 pub fn push_bytes(&mut self, data: &[u8]) {
42 self.buf.extend_from_slice(data);
43 }
44
45 #[must_use]
47 pub const fn header(&self) -> Option<FrameHeader> {
48 self.header
49 }
50
51 pub fn poll_frame(&mut self) -> Result<Option<Bytes>, Error> {
54 if self.buf.len() < HEADER_LEN {
55 return Ok(None);
56 }
57 if self.buf[0] != 0xFF || (self.buf[1] & 0xE0) != 0xE0 {
58 return Err(Error::BadSyncOrReservedField);
59 }
60 let version = version_from_bits(self.buf[1] >> 3).ok_or(Error::BadSyncOrReservedField)?;
61 let layer_bits = (self.buf[1] >> 1) & 0x03;
62 if layer_bits != 0b01 {
63 return Err(Error::UnsupportedLayer);
64 }
65 let protection_absent = (self.buf[1] & 0x01) != 0;
66
67 let bitrate_index = (self.buf[2] >> 4) & 0x0F;
68 if bitrate_index == 0 || bitrate_index == 0x0F {
69 return Err(Error::BadSyncOrReservedField);
70 }
71 let bitrate_kbps = bitrate_table(version)[usize::from(bitrate_index) - 1];
72
73 let sample_rate_index = (self.buf[2] >> 2) & 0x03;
74 if sample_rate_index == 0x03 {
75 return Err(Error::BadSyncOrReservedField);
76 }
77 let sample_rate = sample_rate_table(version)[usize::from(sample_rate_index)];
78
79 let padding = (self.buf[2] >> 1) & 0x01 != 0;
80 let channel_mode = ChannelMode::from_bits(self.buf[3] >> 6);
81
82 let header = FrameHeader {
83 version,
84 bitrate_kbps,
85 sample_rate,
86 channel_mode,
87 };
88 let frame_len = header.frame_len(padding);
89 if self.buf.len() < frame_len {
90 return Ok(None);
91 }
92
93 let payload_start = if protection_absent {
94 HEADER_LEN
95 } else {
96 HEADER_LEN + CRC_LEN
97 };
98 self.header = Some(header);
99 let payload = Bytes::copy_from_slice(&self.buf[payload_start.min(frame_len)..frame_len]);
100 self.buf.drain(0..frame_len);
101 Ok(Some(payload))
102 }
103}
104
105#[cfg(test)]
106#[path = "demux_tests.rs"]
107mod tests;