#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, future_incompatible)]
pub use mpeg4_audio_const::{
AudioObjectType, ChannelConfiguration, SamplingFrequencyIndex, SamplingFrequencyIndexError,
};
use std::fmt;
#[derive(Debug)]
pub enum AdtsHeaderError {
BadSyncWord(u16),
NotEnoughData {
expected: usize,
actual: usize,
},
BadFrameLength {
minimum: usize,
actual: usize,
},
BadSamplingFrequency(SamplingFrequencyIndexError),
}
#[derive(Debug, PartialEq)]
pub struct PayloadError {
pub expected: usize,
pub actual: usize,
}
#[derive(Debug, PartialEq)]
pub enum MpegVersion {
Mpeg2,
Mpeg4,
}
#[derive(Debug, PartialEq)]
pub enum ProtectionIndicator {
CrcPresent,
CrcAbsent,
}
#[derive(Debug, PartialEq)]
pub enum Originality {
Original,
Copy,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum BufferFullness {
Vbr,
Cbr(u16),
}
#[derive(Debug, PartialEq)]
pub enum CopyrightIdentificationStart {
Start,
Other,
}
pub struct AdtsHeader<'buf> {
buf: &'buf [u8],
}
impl<'buf> AdtsHeader<'buf> {
pub fn from_bytes(buf: &'buf [u8]) -> Result<AdtsHeader<'buf>, AdtsHeaderError> {
assert!(!buf.is_empty());
let header_len = 7;
Self::check_len(header_len, buf.len())?;
let header = AdtsHeader { buf };
if header.sync_word() != 0xfff {
return Err(AdtsHeaderError::BadSyncWord(header.sync_word()));
}
let crc_len = 2;
if header.protection() == ProtectionIndicator::CrcPresent {
Self::check_len(header_len + crc_len, buf.len())?;
}
SamplingFrequencyIndex::try_from(header.buf[2] >> 2 & 0b1111)
.map_err(AdtsHeaderError::BadSamplingFrequency)?;
if header.frame_length() < header.header_length() {
return Err(AdtsHeaderError::BadFrameLength {
actual: header.frame_length() as usize,
minimum: header.header_length() as usize,
});
}
Ok(header)
}
fn check_len(expected: usize, actual: usize) -> Result<(), AdtsHeaderError> {
if actual < expected {
Err(AdtsHeaderError::NotEnoughData { expected, actual })
} else {
Ok(())
}
}
fn header_length(&self) -> u16 {
let fixed_len = 7;
if self.protection() == ProtectionIndicator::CrcPresent {
fixed_len + 2
} else {
fixed_len
}
}
fn sync_word(&self) -> u16 {
u16::from(self.buf[0]) << 4 | u16::from(self.buf[1] >> 4)
}
pub fn mpeg_version(&self) -> MpegVersion {
if self.buf[1] & 0b0000_1000 != 0 {
MpegVersion::Mpeg2
} else {
MpegVersion::Mpeg4
}
}
pub fn protection(&self) -> ProtectionIndicator {
if self.buf[1] & 0b0000_0001 != 0 {
ProtectionIndicator::CrcAbsent
} else {
ProtectionIndicator::CrcPresent
}
}
pub fn audio_object_type(&self) -> AudioObjectType {
match self.buf[2] & 0b1100_0000 {
0b0000_0000 => AudioObjectType::AAC_MAIN,
0b0100_0000 => AudioObjectType::AAC_LC,
0b1000_0000 => AudioObjectType::AAC_SSR,
0b1100_0000 => AudioObjectType::AAC_LTP,
v => panic!("impossible value {:#b}", v),
}
}
pub fn sampling_frequency(&self) -> SamplingFrequencyIndex {
SamplingFrequencyIndex::new(self.buf[2] >> 2 & 0b1111)
}
pub fn private_bit(&self) -> u8 {
(self.buf[2] >> 1) & 1
}
pub fn channel_configuration(&self) -> ChannelConfiguration {
ChannelConfiguration::new(self.buf[2] << 2 & 0b0100 | self.buf[3] >> 6)
}
pub fn originality(&self) -> Originality {
if self.buf[3] & 0b0010_0000 != 0 {
Originality::Original
} else {
Originality::Copy
}
}
pub fn home(&self) -> u8 {
self.buf[3] >> 4 & 1
}
pub fn copyright_identification_bit(&self) -> u8 {
self.buf[3] >> 3 & 1
}
pub fn copyright_identification_start(&self) -> CopyrightIdentificationStart {
if self.buf[3] & 0b0000_0100 != 0 {
CopyrightIdentificationStart::Start
} else {
CopyrightIdentificationStart::Other
}
}
pub fn frame_length(&self) -> u16 {
u16::from(self.buf[3] & 0b11) << 11
| u16::from(self.buf[4]) << 3
| u16::from(self.buf[5]) >> 5
}
pub fn payload_length(&self) -> Option<u16> {
let diff = self.frame_length() as i16 - self.header_length() as i16;
if diff >= 0 {
Some(diff as u16)
} else {
None
}
}
pub fn adts_buffer_fullness(&self) -> BufferFullness {
let raw = u16::from(self.buf[5] & 0b00011111) << 6 | u16::from(self.buf[6]) >> 2;
if raw == 0x7FF {
BufferFullness::Vbr
} else {
BufferFullness::Cbr(raw)
}
}
pub fn crc(&self) -> Option<u16> {
match self.protection() {
ProtectionIndicator::CrcAbsent => None,
ProtectionIndicator::CrcPresent => {
Some(u16::from(self.buf[7]) << 8 | u16::from(self.buf[8]))
}
}
}
pub fn number_of_raw_data_blocks_in_frame(&self) -> u8 {
(self.buf[6] & 0b11) + 1
}
pub fn payload(&self) -> Result<&'buf [u8], PayloadError> {
let len = self.frame_length() as usize;
if self.buf.len() < len {
Err(PayloadError {
expected: len,
actual: self.buf.len(),
})
} else {
Ok(&self.buf[self.header_length() as usize..len])
}
}
}
impl<'buf> fmt::Debug for AdtsHeader<'buf> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
f.debug_struct("AdtsHeader")
.field("mpeg_version", &self.mpeg_version())
.field("protection", &self.protection())
.field("audio_object_type", &self.audio_object_type())
.field("sampling_frequency", &self.sampling_frequency())
.field("private_bit", &self.private_bit())
.field("channel_configuration", &self.channel_configuration())
.field("originality", &self.originality())
.field("home", &self.home())
.field(
"copyright_identification_bit",
&self.copyright_identification_bit(),
)
.field(
"copyright_identification_start",
&self.copyright_identification_start(),
)
.field("frame_length", &self.frame_length())
.field("adts_buffer_fullness", &self.adts_buffer_fullness())
.field("crc", &self.crc())
.field(
"number_of_raw_data_blocks_in_frame",
&self.number_of_raw_data_blocks_in_frame(),
)
.finish()
}
}
#[derive(Debug, PartialEq)]
pub enum CopyrightIdErr {
TooFewBits,
TooManyBits,
}
#[derive(Debug, PartialEq)]
pub struct CopyrightIdentification {
pub copyright_identifier: u8,
pub copyright_number: u64,
}
#[derive(PartialEq)]
enum AdtsState {
Start,
Incomplete,
Error,
}
#[derive(Debug, PartialEq)]
pub enum AdtsParseError {
BadSyncWord,
BadFrameLength,
BadSamplingFrequency,
}
pub trait AdtsConsumer {
fn new_config(
&mut self,
mpeg_version: MpegVersion,
protection: ProtectionIndicator,
aot: AudioObjectType,
freq: SamplingFrequencyIndex,
private_bit: u8,
channels: ChannelConfiguration,
originality: Originality,
home: u8,
);
fn payload(&mut self, buffer_fullness: BufferFullness, number_of_blocks: u8, buf: &[u8]);
fn error(&mut self, err: AdtsParseError);
}
pub struct AdtsParser<C>
where
C: AdtsConsumer,
{
pub consumer: C,
current_config: [u8; 4],
state: AdtsState,
incomplete_frame: Vec<u8>,
desired_data_len: Option<usize>,
}
impl<C> AdtsParser<C>
where
C: AdtsConsumer,
{
pub fn new(consumer: C) -> AdtsParser<C> {
AdtsParser {
consumer,
current_config: [0; 4],
state: AdtsState::Start,
incomplete_frame: vec![],
desired_data_len: None,
}
}
fn is_new_config(&self, header_data: &[u8]) -> bool {
self.current_config[0..3] != header_data[0..3]
|| self.current_config[3] != header_data[3] & 0b1111_0000
}
fn remember(&mut self, remaining_data: &[u8], desired_data_len: usize) {
self.state = AdtsState::Incomplete;
self.incomplete_frame.clear();
self.incomplete_frame.extend_from_slice(remaining_data);
self.desired_data_len = Some(desired_data_len);
}
pub fn start(&mut self) {
if self.state == AdtsState::Incomplete {
self.incomplete_frame.clear();
self.desired_data_len = None;
eprintln!("ADTS: incomplete data buffer dropped by call to start()");
}
self.state = AdtsState::Start;
}
pub fn push(&mut self, adts_buf: &[u8]) {
let mut buf = adts_buf;
match self.state {
AdtsState::Error => return, AdtsState::Incomplete => {
loop {
let bytes_needed_to_complete_frame =
self.desired_data_len.unwrap() - self.incomplete_frame.len();
if buf.len() < bytes_needed_to_complete_frame {
self.incomplete_frame.extend_from_slice(buf);
return;
}
self.incomplete_frame
.extend_from_slice(&buf[..bytes_needed_to_complete_frame]);
buf = &buf[bytes_needed_to_complete_frame..];
let mut still_more = false; match AdtsHeader::from_bytes(&self.incomplete_frame[..]) {
Ok(header) => {
if (header.frame_length() as usize) > self.incomplete_frame.len() {
self.desired_data_len = Some(header.frame_length() as usize);
still_more = true;
} else {
if self.is_new_config(&self.incomplete_frame[..]) {
Self::push_config(
&mut self.current_config,
&mut self.consumer,
&header,
&self.incomplete_frame[..],
);
}
Self::push_payload(&mut self.consumer, header);
self.state = AdtsState::Start;
}
}
Err(e) => match e {
AdtsHeaderError::BadSyncWord { .. } => {
self.state = AdtsState::Error;
self.consumer.error(AdtsParseError::BadSyncWord);
return;
}
AdtsHeaderError::BadFrameLength { .. } => {
self.state = AdtsState::Error;
self.consumer.error(AdtsParseError::BadFrameLength);
return;
}
AdtsHeaderError::BadSamplingFrequency(_) => {
self.state = AdtsState::Error;
self.consumer.error(AdtsParseError::BadSamplingFrequency);
return;
}
AdtsHeaderError::NotEnoughData { expected, .. } => {
self.desired_data_len = Some(expected);
still_more = true;
}
},
}
if !still_more {
break;
}
}
}
AdtsState::Start => (),
};
let mut pos = 0;
while pos < buf.len() {
let remaining_data = &buf[pos..];
let h = match AdtsHeader::from_bytes(remaining_data) {
Ok(header) => header,
Err(e) => {
self.state = AdtsState::Error;
match e {
AdtsHeaderError::BadSyncWord { .. } => {
self.consumer.error(AdtsParseError::BadSyncWord)
}
AdtsHeaderError::BadFrameLength { .. } => {
self.consumer.error(AdtsParseError::BadFrameLength);
return;
}
AdtsHeaderError::NotEnoughData { expected, .. } => {
self.remember(remaining_data, expected);
return;
}
AdtsHeaderError::BadSamplingFrequency(_) => {
self.consumer.error(AdtsParseError::BadSamplingFrequency);
}
}
return;
}
};
let new_pos = pos + h.frame_length() as usize;
if new_pos > buf.len() {
self.remember(remaining_data, h.frame_length() as usize);
return;
}
if self.is_new_config(remaining_data) {
Self::push_config(
&mut self.current_config,
&mut self.consumer,
&h,
remaining_data,
);
}
Self::push_payload(&mut self.consumer, h);
self.state = AdtsState::Start;
pos = new_pos;
}
}
fn push_config(
current_config: &mut [u8; 4],
consumer: &mut C,
h: &AdtsHeader<'_>,
frame_buffer: &[u8],
) {
current_config[0..3].copy_from_slice(&frame_buffer[0..3]);
current_config[3] = frame_buffer[3] & 0b1111_0000;
consumer.new_config(
h.mpeg_version(),
h.protection(),
h.audio_object_type(),
h.sampling_frequency(),
h.private_bit(),
h.channel_configuration(),
h.originality(),
h.home(),
);
}
fn push_payload(consumer: &mut C, h: AdtsHeader<'_>) {
match h.payload() {
Ok(payload) => {
consumer.payload(
h.adts_buffer_fullness(),
h.number_of_raw_data_blocks_in_frame(),
payload,
);
}
Err(PayloadError { expected, actual }) => {
panic!(
"Unexpected payload size mismatch: expected {}, actual size {}",
expected, actual
);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use bitstream_io::{BigEndian, BitWrite, BitWriter, BE};
use std::io;
fn make_test_data<F>(builder: F) -> Vec<u8>
where
F: Fn(BitWriter<&mut Vec<u8>, BE>) -> Result<(), io::Error>,
{
let mut data: Vec<u8> = Vec::new();
builder(BitWriter::endian(&mut data, BigEndian)).unwrap();
data
}
fn write_frame(w: &mut BitWriter<&mut Vec<u8>, BE>) -> Result<(), io::Error> {
w.write(12, 0xfff)?; w.write(1, 0)?; w.write(2, 0)?; w.write(1, 1)?; w.write(2, 0)?; w.write(4, 0b0011)?; w.write(1, 1)?; w.write(3, 2)?; w.write(1, 1)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 1)?; w.write(13, 8)?; w.write(11, 123)?; w.write(2, 0)?; w.write(8, 0b10000001) }
#[test]
fn no_crc() {
let header_data = make_test_data(|mut w| write_frame(&mut w));
let header = AdtsHeader::from_bytes(&header_data[..]).unwrap();
assert_eq!(header.mpeg_version(), MpegVersion::Mpeg4);
assert_eq!(header.protection(), ProtectionIndicator::CrcAbsent);
assert_eq!(header.audio_object_type(), AudioObjectType::AAC_MAIN);
assert_eq!(
header.sampling_frequency(),
SamplingFrequencyIndex::FREQ_48000
);
assert_eq!(header.sampling_frequency().freq(), Some(48000));
assert_eq!(header.private_bit(), 1);
assert_eq!(header.channel_configuration(), ChannelConfiguration::STEREO);
assert_eq!(header.originality(), Originality::Original);
assert_eq!(header.home(), 0);
assert_eq!(header.copyright_identification_bit(), 0);
assert_eq!(
header.copyright_identification_start(),
CopyrightIdentificationStart::Start
);
assert_eq!(header.frame_length(), 8);
assert_eq!(header.payload_length(), Some(8 - 7));
assert_eq!(header.adts_buffer_fullness(), BufferFullness::Cbr(123));
assert_eq!(header.number_of_raw_data_blocks_in_frame(), 1);
assert_eq!(header.payload(), Ok(&[0b10000001][..]));
}
#[test]
fn large_buffer_fullness() {
let header_data = make_test_data(|mut w| {
w.write(12, 0xfff)?; w.write(1, 0)?; w.write(2, 0)?; w.write(1, 1)?; w.write(2, 0)?; w.write(4, 0b0011)?; w.write(1, 0)?; w.write(3, 1)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 0)?; w.write(13, 8)?; w.write(11, 0x7FF)?; w.write(2, 0)?; w.write(8, 0x00) });
let header = AdtsHeader::from_bytes(&header_data[..]).unwrap();
assert_eq!(header.adts_buffer_fullness(), BufferFullness::Vbr);
}
struct MockConsumer {
seq: usize,
payload_seq: usize,
payload_size: Option<usize>,
}
impl MockConsumer {
pub fn new() -> MockConsumer {
MockConsumer {
seq: 0,
payload_seq: 0,
payload_size: None,
}
}
pub fn assert_seq(&mut self, expected: usize) {
assert_eq!(expected, self.seq);
self.seq += 1;
}
}
impl AdtsConsumer for MockConsumer {
fn new_config(
&mut self,
mpeg_version: MpegVersion,
_protection: ProtectionIndicator,
_aot: AudioObjectType,
_freq: SamplingFrequencyIndex,
_private_bit: u8,
_channels: ChannelConfiguration,
_originality: Originality,
_home: u8,
) {
self.assert_seq(0);
assert_eq!(mpeg_version, MpegVersion::Mpeg4);
}
fn payload(&mut self, _buffer_fullness: BufferFullness, _number_of_blocks: u8, buf: &[u8]) {
self.payload_seq += 1;
let new_payload_seq = self.payload_seq;
self.assert_seq(new_payload_seq);
self.payload_size = Some(buf.len());
}
fn error(&mut self, err: AdtsParseError) {
panic!("no errors expected in bitstream: {:?}", err);
}
}
#[test]
fn parser() {
let header_data = make_test_data(|mut w| {
write_frame(&mut w)?;
write_frame(&mut w)
});
for split in 0..header_data.len() {
let mut parser = AdtsParser::new(MockConsumer::new());
let (head, tail) = header_data.split_at(split);
parser.push(head);
parser.push(tail);
assert_eq!(2, parser.consumer.payload_seq);
assert_eq!(Some(1), parser.consumer.payload_size);
}
}
struct CountingConsumer {
payload_count: usize,
}
impl AdtsConsumer for CountingConsumer {
fn new_config(
&mut self,
_: MpegVersion,
_: ProtectionIndicator,
_: AudioObjectType,
_: SamplingFrequencyIndex,
_: u8,
_: ChannelConfiguration,
_: Originality,
_: u8,
) {
}
fn payload(&mut self, _: BufferFullness, _: u8, _: &[u8]) {
self.payload_count += 1;
}
fn error(&mut self, err: AdtsParseError) {
panic!("no errors expected: {:?}", err);
}
}
#[test]
fn crc_frame_split_across_pushes() {
let frame_data = make_test_data(|mut w| {
w.write(12, 0xfff)?; w.write(1, 0)?; w.write(2, 0)?; w.write(1, 0)?; w.write(2, 0)?; w.write(4, 0b0011)?; w.write(1, 0)?; w.write(3, 2)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 0)?; w.write(13, 10)?; w.write(11, 100)?; w.write(2, 0)?; w.write(16, 0)?; w.write(8, 0xAB) });
let mut parser = AdtsParser::new(CountingConsumer { payload_count: 0 });
parser.push(&frame_data[..5]);
parser.push(&frame_data[5..7]);
assert_eq!(0, parser.consumer.payload_count, "no payload yet");
parser.push(&frame_data[7..]);
assert_eq!(
1, parser.consumer.payload_count,
"payload should have been delivered"
);
}
#[test]
fn too_short() {
let header_data = make_test_data(|mut w| write_frame(&mut w));
let mut parser = AdtsParser::new(MockConsumer::new());
parser.push(&header_data[..5]);
parser.push(&header_data[5..7]);
}
#[test]
fn bad_sampling_frequency() {
let header_data = make_test_data(|mut w| {
w.write(12, 0xfff)?; w.write(1, 0)?; w.write(2, 0)?; w.write(1, 1)?; w.write(2, 0)?; w.write(4, 0b1111)?; w.write(1, 0)?; w.write(3, 1)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 0)?; w.write(1, 0)?; w.write(13, 8)?; w.write(11, 0)?; w.write(2, 0)?; w.write(8, 0x00) });
assert!(matches!(
AdtsHeader::from_bytes(&header_data),
Err(AdtsHeaderError::BadSamplingFrequency(_))
));
}
}