no Bytes in AudioParameters interface either

For #47.

Along the way, I simplified `aac::Depacketizer` impl a bit, eliminating
a clone and some redundancy.
This commit is contained in:
Scott Lamb 2022-05-11 11:56:42 -07:00
parent b1e1fa9031
commit a33ba9b8af
4 changed files with 32 additions and 48 deletions

View File

@ -30,13 +30,9 @@ use super::{AudioParameters, CodecItem};
/// Currently stores the raw form and a few fields of interest. /// Currently stores the raw form and a few fields of interest.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct AudioSpecificConfig { struct AudioSpecificConfig {
raw: Bytes, parameters: AudioParameters,
sample_entry: Bytes,
/// See ISO/IEC 14496-3 Table 1.3.
audio_object_type: u8,
frame_length: NonZeroU16, frame_length: NonZeroU16,
sampling_frequency: u32,
channels: &'static ChannelConfig, channels: &'static ChannelConfig,
} }
@ -159,28 +155,22 @@ impl AudioSpecificConfig {
(_, true) => NonZeroU16::new(960).expect("non-zero"), (_, true) => NonZeroU16::new(960).expect("non-zero"),
}; };
// https://datatracker.ietf.org/doc/html/rfc6381#section-3.3
let rfc6381_codec = Some(format!("mp4a.40.{}", audio_object_type));
Ok(AudioSpecificConfig { Ok(AudioSpecificConfig {
raw: Bytes::copy_from_slice(raw), parameters: AudioParameters {
sample_entry: make_sample_entry(channels, sampling_frequency, raw)?, // See also TODO asking if clock_rate and sampling_frequency must match.
audio_object_type, clock_rate: sampling_frequency,
rfc6381_codec,
frame_length: Some(NonZeroU32::from(frame_length)),
extra_data: raw.to_owned(),
sample_entry: Some(make_sample_entry(channels, sampling_frequency, raw)?),
},
frame_length, frame_length,
sampling_frequency,
channels, channels,
}) })
} }
fn to_parameters(&self) -> super::AudioParameters {
// https://datatracker.ietf.org/doc/html/rfc6381#section-3.3
let rfc6381_codec = Some(format!("mp4a.40.{}", self.audio_object_type));
super::AudioParameters {
// See also TODO asking if clock_rate and sampling_frequency must match.
clock_rate: self.sampling_frequency,
rfc6381_codec,
frame_length: Some(NonZeroU32::from(self.frame_length)),
extra_data: self.raw.clone(),
sample_entry: Some(self.sample_entry.clone()),
}
}
} }
/// Overwrites a buffer with a varint length, returning the length of the length. /// Overwrites a buffer with a varint length, returning the length of the length.
@ -220,7 +210,7 @@ macro_rules! write_box {
// is expected to reference `$buf` via the original name. // is expected to reference `$buf` via the original name.
#[allow(clippy::unnecessary_mut_passed)] #[allow(clippy::unnecessary_mut_passed)]
{ {
let _: &mut BytesMut = $buf; // type-check. let _: &mut Vec<u8> = $buf; // type-check.
let pos_start = $buf.len(); let pos_start = $buf.len();
let fourcc: &[u8; 4] = $fourcc; let fourcc: &[u8; 4] = $fourcc;
@ -244,7 +234,7 @@ macro_rules! write_box {
/// scope. See ISO/IEC 14496-1 Table 1 for the `tag`. /// scope. See ISO/IEC 14496-1 Table 1 for the `tag`.
macro_rules! write_descriptor { macro_rules! write_descriptor {
($buf:expr, $tag:expr, $b:block) => {{ ($buf:expr, $tag:expr, $b:block) => {{
let _: &mut BytesMut = $buf; // type-check. let _: &mut Vec<u8> = $buf; // type-check.
let _: u8 = $tag; let _: u8 = $tag;
let pos_start = $buf.len(); let pos_start = $buf.len();
@ -274,8 +264,8 @@ fn make_sample_entry(
channels: &ChannelConfig, channels: &ChannelConfig,
sampling_frequency: u32, sampling_frequency: u32,
config: &[u8], config: &[u8],
) -> Result<Bytes, String> { ) -> Result<Vec<u8>, String> {
let mut buf = BytesMut::new(); let mut buf = Vec::new();
// Write an MP4AudioSampleEntry (`mp4a`), as in ISO/IEC 14496-14 section 5.6.1. // Write an MP4AudioSampleEntry (`mp4a`), as in ISO/IEC 14496-14 section 5.6.1.
// It's based on AudioSampleEntry, ISO/IEC 14496-12 section 12.2.3.2, // It's based on AudioSampleEntry, ISO/IEC 14496-12 section 12.2.3.2,
@ -354,7 +344,7 @@ fn make_sample_entry(
}); });
}); });
}); });
Ok(buf.freeze()) Ok(buf)
} }
/// Parses metadata from the `format-specific-params` of a SDP `fmtp` media attribute. /// Parses metadata from the `format-specific-params` of a SDP `fmtp` media attribute.
@ -418,11 +408,12 @@ fn parse_format_specific_params(
let config = AudioSpecificConfig::parse(&config[..])?; let config = AudioSpecificConfig::parse(&config[..])?;
// TODO: is this a requirement? I might have read somewhere one can be a multiple of the other. // TODO: is this a requirement? I might have read somewhere that the RTP clock rate can be
if clock_rate != config.sampling_frequency { // a multiple of the AudioSpecificConfig sampling_frequency or vice versa.
if clock_rate != config.parameters.clock_rate {
return Err(format!( return Err(format!(
"Expected RTP clock rate {} and AAC sampling frequency {} to match", "Expected RTP clock rate {} and AAC sampling frequency {} to match",
clock_rate, config.sampling_frequency clock_rate, config.parameters.clock_rate,
)); ));
} }
@ -432,7 +423,6 @@ fn parse_format_specific_params(
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Depacketizer { pub(crate) struct Depacketizer {
config: AudioSpecificConfig, config: AudioSpecificConfig,
parameters: AudioParameters,
state: DepacketizerState, state: DepacketizerState,
} }
@ -528,16 +518,14 @@ impl Depacketizer {
channels, config.channels channels, config.channels
)); ));
} }
let parameters = config.to_parameters();
Ok(Self { Ok(Self {
config, config,
parameters,
state: DepacketizerState::default(), state: DepacketizerState::default(),
}) })
} }
pub(super) fn parameters(&self) -> Option<super::ParametersRef> { pub(super) fn parameters(&self) -> Option<super::ParametersRef> {
Some(super::ParametersRef::Audio(&self.parameters)) Some(super::ParametersRef::Audio(&self.config.parameters))
} }
pub(super) fn push(&mut self, pkt: ReceivedPacket) -> Result<(), String> { pub(super) fn push(&mut self, pkt: ReceivedPacket) -> Result<(), String> {
@ -797,15 +785,15 @@ mod tests {
#[test] #[test]
fn parse_audio_specific_config() { fn parse_audio_specific_config() {
let dahua = AudioSpecificConfig::parse(&[0x11, 0x88]).unwrap(); let dahua = AudioSpecificConfig::parse(&[0x11, 0x88]).unwrap();
assert_eq!(dahua.sampling_frequency, 48_000); assert_eq!(dahua.parameters.clock_rate, 48_000);
assert_eq!(dahua.channels.name, "mono"); assert_eq!(dahua.channels.name, "mono");
let bunny = AudioSpecificConfig::parse(&[0x14, 0x90]).unwrap(); let bunny = AudioSpecificConfig::parse(&[0x14, 0x90]).unwrap();
assert_eq!(bunny.sampling_frequency, 12_000); assert_eq!(bunny.parameters.clock_rate, 12_000);
assert_eq!(bunny.channels.name, "stereo"); assert_eq!(bunny.channels.name, "stereo");
let rfc3640 = AudioSpecificConfig::parse(&[0x11, 0xB0]).unwrap(); let rfc3640 = AudioSpecificConfig::parse(&[0x11, 0xB0]).unwrap();
assert_eq!(rfc3640.sampling_frequency, 48_000); assert_eq!(rfc3640.parameters.clock_rate, 48_000);
assert_eq!(rfc3640.channels.name, "5.1"); assert_eq!(rfc3640.channels.name, "5.1");
} }

View File

@ -5,8 +5,6 @@
use std::num::NonZeroU32; use std::num::NonZeroU32;
use bytes::Bytes;
use super::AudioParameters; use super::AudioParameters;
const FIXED_CLOCK_RATE: u32 = 8_000; const FIXED_CLOCK_RATE: u32 = 8_000;
@ -32,7 +30,7 @@ impl Depacketizer {
rfc6381_codec: None, rfc6381_codec: None,
frame_length: NonZeroU32::new(240), frame_length: NonZeroU32::new(240),
clock_rate: FIXED_CLOCK_RATE, clock_rate: FIXED_CLOCK_RATE,
extra_data: Bytes::new(), extra_data: Vec::new(),
sample_entry: None, sample_entry: None,
}, },
}) })

View File

@ -139,8 +139,8 @@ pub struct AudioParameters {
rfc6381_codec: Option<String>, rfc6381_codec: Option<String>,
frame_length: Option<NonZeroU32>, frame_length: Option<NonZeroU32>,
clock_rate: u32, clock_rate: u32,
extra_data: Bytes, extra_data: Vec<u8>,
sample_entry: Option<Bytes>, sample_entry: Option<Vec<u8>>,
} }
impl std::fmt::Debug for AudioParameters { impl std::fmt::Debug for AudioParameters {
@ -172,7 +172,7 @@ impl AudioParameters {
/// The codec-specific "extra data" to feed to eg ffmpeg to decode the audio. /// The codec-specific "extra data" to feed to eg ffmpeg to decode the audio.
/// * AAC: a serialized `AudioSpecificConfig`. /// * AAC: a serialized `AudioSpecificConfig`.
pub fn extra_data(&self) -> &Bytes { pub fn extra_data(&self) -> &[u8] {
&self.extra_data &self.extra_data
} }
@ -180,8 +180,8 @@ impl AudioParameters {
/// ///
/// Not all codecs can be placed into a `.mp4` file, and even for supported codecs there /// Not all codecs can be placed into a `.mp4` file, and even for supported codecs there
/// may be unsupported edge cases. /// may be unsupported edge cases.
pub fn sample_entry(&self) -> Option<&Bytes> { pub fn sample_entry(&self) -> Option<&[u8]> {
self.sample_entry.as_ref() self.sample_entry.as_deref()
} }
} }

View File

@ -6,8 +6,6 @@
use std::num::NonZeroU32; use std::num::NonZeroU32;
use bytes::Bytes;
use super::{AudioParameters, CodecItem}; use super::{AudioParameters, CodecItem};
#[derive(Debug)] #[derive(Debug)]
@ -25,7 +23,7 @@ impl Depacketizer {
rfc6381_codec: None, rfc6381_codec: None,
frame_length: None, // variable frame_length: None, // variable
clock_rate, clock_rate,
extra_data: Bytes::new(), extra_data: Vec::new(),
sample_entry: None, sample_entry: None,
}, },
bits_per_sample, bits_per_sample,