shrink several large datastructures
* Box the remaining Depacketizer variants. I already boxed the largest ones, which are also the most common. Might as well box the others and not have so much dead space in the common case... * Don't keep around a full codec::Parameters on all codecs. This shrinks several depacketizers. I also avoid some awkward destructuring. * Box VideoFrame::new_parameters, which is populated rarely. ``` sizes changes on 64-bit platforms: type before after client::Stream 512 312 codec::Depacketizer 224 16 codec::aac::Depacketizer 232 208 codec::g723::Depacketizer 200 104 codec::h264::Depacketizer 560 552 codec::onvif::Depacketizer 216 128 codec::simple_audio::Depacketizer 208 112 codec::CodecItem 240 160 codec::VideoFrame 232 152 codec::AudioFrame 104 104 codec::MessageFrame 104 104 client::rtp::SenderReport 72 72 ```
This commit is contained in:
parent
f5b4c5a9b6
commit
de6658961b
@ -1,7 +1,12 @@
|
||||
## unreleased
|
||||
|
||||
* New opaque error type with more uniform, richer error messages. No more
|
||||
`failure` dependency.
|
||||
* BREAKING CHANGE: New opaque error type with more uniform, richer error
|
||||
messages. No more `failure` dependency.
|
||||
* BREAKING CHANGE: `retina::client::Stream::parameters` now returns parameters
|
||||
by value. This allows shrinking depacketizer types.
|
||||
* BREAKING CHANGE: `retina::codec::VideoFrame::new_parameters` is now boxed.
|
||||
This allows shrinking `VideoFrame` and `CodecItem` by 80 bytes each (on
|
||||
64-bit platforms). The box is only rarely populated.
|
||||
|
||||
## v0.0.4 (2021-06-28)
|
||||
|
||||
|
@ -191,7 +191,7 @@ impl Stream {
|
||||
///
|
||||
/// Returns `None` on unknown codecs, bad parameters, or if parameters aren't specified
|
||||
/// via SDP. Some codecs allow parameters to be specified in-band instead.
|
||||
pub fn parameters(&self) -> Option<&crate::codec::Parameters> {
|
||||
pub fn parameters(&self) -> Option<crate::codec::Parameters> {
|
||||
self.depacketizer.as_ref().ok().and_then(|d| d.parameters())
|
||||
}
|
||||
}
|
||||
@ -1071,3 +1071,31 @@ impl futures::Stream for Demuxed {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// See with: cargo test -- --nocapture client::tests::print_sizes
|
||||
#[test]
|
||||
fn print_sizes() {
|
||||
for (name, size) in [
|
||||
("RtspConnection", std::mem::size_of::<RtspConnection>()),
|
||||
(
|
||||
"Session<Described>",
|
||||
std::mem::size_of::<Session<Described>>(),
|
||||
),
|
||||
("Session<Playing>", std::mem::size_of::<Session<Playing>>()),
|
||||
("Demuxed", std::mem::size_of::<Demuxed>()),
|
||||
("Stream", std::mem::size_of::<Stream>()),
|
||||
("PacketItem", std::mem::size_of::<PacketItem>()),
|
||||
("rtp::Packet", std::mem::size_of::<rtp::Packet>()),
|
||||
(
|
||||
"rtp::SenderReport",
|
||||
std::mem::size_of::<rtp::SenderReport>(),
|
||||
),
|
||||
] {
|
||||
println!("{:-40} {:4}", name, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
105
src/codec/aac.rs
105
src/codec/aac.rs
@ -26,9 +26,13 @@ use crate::{client::rtp::Packet, error::ErrorInt, ConnectionContext, Error};
|
||||
use super::CodecItem;
|
||||
|
||||
/// An AudioSpecificConfig as in ISO/IEC 14496-3 section 1.6.2.1.
|
||||
/// Currently just a few fields of interest.
|
||||
///
|
||||
/// Currently stores the raw form and a few fields of interest.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) struct AudioSpecificConfig {
|
||||
struct AudioSpecificConfig {
|
||||
raw: Bytes,
|
||||
sample_entry: Bytes,
|
||||
|
||||
/// See ISO/IEC 14496-3 Table 1.3.
|
||||
audio_object_type: u8,
|
||||
frame_length: NonZeroU16,
|
||||
@ -63,8 +67,8 @@ const CHANNEL_CONFIGS: [Option<ChannelConfig>; 8] = [
|
||||
|
||||
impl AudioSpecificConfig {
|
||||
/// Parses from raw bytes.
|
||||
fn parse(config: &[u8]) -> Result<Self, String> {
|
||||
let mut r = bitreader::BitReader::new(config);
|
||||
fn parse(raw: &[u8]) -> Result<Self, String> {
|
||||
let mut r = bitreader::BitReader::new(&raw[..]);
|
||||
let audio_object_type = match r
|
||||
.read_u8(5)
|
||||
.map_err(|e| format!("unable to read audio_object_type: {}", e))?
|
||||
@ -153,12 +157,27 @@ impl AudioSpecificConfig {
|
||||
};
|
||||
|
||||
Ok(AudioSpecificConfig {
|
||||
raw: Bytes::copy_from_slice(raw),
|
||||
sample_entry: make_sample_entry(channels, sampling_frequency, raw)?,
|
||||
audio_object_type,
|
||||
frame_length,
|
||||
sampling_frequency,
|
||||
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.
|
||||
@ -239,13 +258,12 @@ macro_rules! write_descriptor {
|
||||
}
|
||||
|
||||
/// Returns an MP4AudioSampleEntry (`mp4a`) box as in ISO/IEC 14496-14 section 5.6.1.
|
||||
/// `config` should be a raw AudioSpecificConfig (matching `parsed`).
|
||||
pub(super) fn get_mp4a_box(parameters: &super::AudioParameters) -> Result<Bytes, String> {
|
||||
let parsed = match parameters.config {
|
||||
super::AudioCodecConfig::Aac(ref c) => c,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let config = ¶meters.extra_data[..];
|
||||
/// `config` should be a raw AudioSpecificConfig.
|
||||
fn make_sample_entry(
|
||||
channels: &ChannelConfig,
|
||||
sampling_frequency: u32,
|
||||
config: &[u8],
|
||||
) -> Result<Bytes, String> {
|
||||
let mut buf = BytesMut::new();
|
||||
|
||||
// Write an MP4AudioSampleEntry (`mp4a`), as in ISO/IEC 14496-14 section 5.6.1.
|
||||
@ -258,7 +276,7 @@ pub(super) fn get_mp4a_box(parameters: &super::AudioParameters) -> Result<Bytes,
|
||||
0, 0, 0, 0, // AudioSampleEntry.reserved
|
||||
0, 0, 0, 0, // AudioSampleEntry.reserved
|
||||
]);
|
||||
buf.put_u16(parsed.channels.channels);
|
||||
buf.put_u16(channels.channels);
|
||||
buf.extend_from_slice(&[
|
||||
0x00, 0x10, // AudioSampleEntry.samplesize
|
||||
0x00, 0x00, 0x00, 0x00, // AudioSampleEntry.pre_defined, AudioSampleEntry.reserved
|
||||
@ -269,12 +287,8 @@ pub(super) fn get_mp4a_box(parameters: &super::AudioParameters) -> Result<Bytes,
|
||||
// use a SamplingRateBox. The latter also requires changing the
|
||||
// version/structure of the AudioSampleEntryBox and the version of the
|
||||
// stsd box. Just support the former for now.
|
||||
let sampling_frequency = u16::try_from(parsed.sampling_frequency).map_err(|_| {
|
||||
format!(
|
||||
"aac sampling_frequency={} unsupported",
|
||||
parsed.sampling_frequency
|
||||
)
|
||||
})?;
|
||||
let sampling_frequency = u16::try_from(sampling_frequency)
|
||||
.map_err(|_| format!("aac sampling_frequency={} unsupported", sampling_frequency))?;
|
||||
buf.put_u32(u32::from(sampling_frequency) << 16);
|
||||
|
||||
// Write the embedded ESDBox (`esds`), as in ISO/IEC 14496-14 section 5.6.1.
|
||||
@ -301,16 +315,15 @@ pub(super) fn get_mp4a_box(parameters: &super::AudioParameters) -> Result<Bytes,
|
||||
// elementary stream in byte". ISO/IEC 13818-7 section
|
||||
// 8.2.2.1 defines the total decoder input buffer size as
|
||||
// 6144 bits per NCC.
|
||||
let buffer_size_bytes = (6144 / 8) * u32::from(parsed.channels.ncc);
|
||||
let buffer_size_bytes = (6144 / 8) * u32::from(channels.ncc);
|
||||
debug_assert!(buffer_size_bytes <= 0xFF_FFFF);
|
||||
|
||||
// buffer_size_bytes as a 24-bit number
|
||||
buf.put_u8((buffer_size_bytes >> 16) as u8);
|
||||
buf.put_u16(buffer_size_bytes as u16);
|
||||
|
||||
let max_bitrate = (6144 / 1024)
|
||||
* u32::from(parsed.channels.ncc)
|
||||
* u32::from(sampling_frequency);
|
||||
let max_bitrate =
|
||||
(6144 / 1024) * u32::from(channels.ncc) * u32::from(sampling_frequency);
|
||||
buf.put_u32(max_bitrate);
|
||||
|
||||
// avg_bitrate. ISO/IEC 14496-1 section 7.2.6.6 says "for streams with
|
||||
@ -339,7 +352,7 @@ pub(super) fn get_mp4a_box(parameters: &super::AudioParameters) -> Result<Bytes,
|
||||
fn parse_format_specific_params(
|
||||
clock_rate: u32,
|
||||
format_specific_params: &str,
|
||||
) -> Result<super::AudioParameters, String> {
|
||||
) -> Result<AudioSpecificConfig, String> {
|
||||
let mut mode = None;
|
||||
let mut config = None;
|
||||
let mut size_length = None;
|
||||
@ -392,34 +405,22 @@ fn parse_format_specific_params(
|
||||
));
|
||||
}
|
||||
|
||||
let parsed = 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.
|
||||
if clock_rate != parsed.sampling_frequency {
|
||||
if clock_rate != config.sampling_frequency {
|
||||
return Err(format!(
|
||||
"Expected RTP clock rate {} and AAC sampling frequency {} to match",
|
||||
clock_rate, parsed.sampling_frequency
|
||||
clock_rate, config.sampling_frequency
|
||||
));
|
||||
}
|
||||
|
||||
// https://datatracker.ietf.org/doc/html/rfc6381#section-3.3
|
||||
let rfc6381_codec = Some(format!("mp4a.40.{}", parsed.audio_object_type));
|
||||
let frame_length = Some(parsed.frame_length);
|
||||
Ok(super::AudioParameters {
|
||||
config: super::AudioCodecConfig::Aac(parsed),
|
||||
clock_rate,
|
||||
rfc6381_codec,
|
||||
frame_length: frame_length.map(NonZeroU32::from),
|
||||
extra_data: Bytes::from(config),
|
||||
})
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Depacketizer {
|
||||
parameters: super::Parameters,
|
||||
|
||||
/// This is in parameters but duplicated here to avoid destructuring.
|
||||
frame_length: NonZeroU16,
|
||||
config: AudioSpecificConfig,
|
||||
state: DepacketizerState,
|
||||
}
|
||||
|
||||
@ -497,27 +498,21 @@ impl Depacketizer {
|
||||
) -> Result<Self, String> {
|
||||
let format_specific_params = format_specific_params
|
||||
.ok_or_else(|| "AAC requires format specific params".to_string())?;
|
||||
let parameters = parse_format_specific_params(clock_rate, format_specific_params)?;
|
||||
let parsed = match parameters.config {
|
||||
super::AudioCodecConfig::Aac(ref c) => c,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if matches!(channels, Some(c) if c.get() != parsed.channels.channels) {
|
||||
let config = parse_format_specific_params(clock_rate, format_specific_params)?;
|
||||
if matches!(channels, Some(c) if c.get() != config.channels.channels) {
|
||||
return Err(format!(
|
||||
"Expected RTP channels {:?} and AAC channels {:?} to match",
|
||||
channels, parsed.channels
|
||||
channels, config.channels
|
||||
));
|
||||
}
|
||||
let frame_length = parsed.frame_length;
|
||||
Ok(Self {
|
||||
parameters: super::Parameters::Audio(parameters),
|
||||
frame_length,
|
||||
config,
|
||||
state: DepacketizerState::Idle { prev_loss: 0 },
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn parameters(&self) -> Option<&super::Parameters> {
|
||||
Some(&self.parameters)
|
||||
pub(super) fn parameters(&self) -> Option<super::Parameters> {
|
||||
Some(super::Parameters::Audio(self.config.to_parameters()))
|
||||
}
|
||||
|
||||
pub(super) fn push(&mut self, mut pkt: Packet) -> Result<(), String> {
|
||||
@ -592,7 +587,7 @@ impl Depacketizer {
|
||||
self.state = DepacketizerState::Ready(super::AudioFrame {
|
||||
ctx: pkt.ctx,
|
||||
loss: frag.loss,
|
||||
frame_length: NonZeroU32::from(self.frame_length),
|
||||
frame_length: NonZeroU32::from(self.config.frame_length),
|
||||
stream_id: pkt.stream_id,
|
||||
timestamp: pkt.timestamp,
|
||||
data: std::mem::take(&mut frag.buf).freeze(),
|
||||
@ -691,13 +686,13 @@ impl Depacketizer {
|
||||
));
|
||||
}
|
||||
|
||||
let delta = u32::from(agg.frame_i) * u32::from(self.frame_length.get());
|
||||
let delta = u32::from(agg.frame_i) * u32::from(self.config.frame_length.get());
|
||||
let agg_timestamp = agg.timestamp;
|
||||
let frame = super::AudioFrame {
|
||||
ctx: agg.ctx,
|
||||
loss: agg.loss,
|
||||
stream_id: agg.stream_id,
|
||||
frame_length: NonZeroU32::from(self.frame_length),
|
||||
frame_length: NonZeroU32::from(self.config.frame_length),
|
||||
|
||||
// u16 * u16 can't overflow u32, but i64 + u32 can overflow i64.
|
||||
timestamp: match agg_timestamp.try_add(delta) {
|
||||
|
@ -8,35 +8,33 @@ use std::num::NonZeroU32;
|
||||
use bytes::Bytes;
|
||||
use pretty_hex::PrettyHex;
|
||||
|
||||
const FIXED_CLOCK_RATE: u32 = 8_000;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Depacketizer {
|
||||
parameters: super::Parameters,
|
||||
pending: Option<super::AudioFrame>,
|
||||
}
|
||||
|
||||
impl Depacketizer {
|
||||
/// Creates a new Depacketizer.
|
||||
pub(super) fn new(clock_rate: u32) -> Result<Self, String> {
|
||||
if clock_rate != 8_000 {
|
||||
if clock_rate != FIXED_CLOCK_RATE {
|
||||
return Err(format!(
|
||||
"Expected clock rate of 8000 for G.723, got {}",
|
||||
clock_rate
|
||||
"Expected clock rate of {} for G.723, got {}",
|
||||
FIXED_CLOCK_RATE, clock_rate
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
parameters: super::Parameters::Audio(super::AudioParameters {
|
||||
rfc6381_codec: None,
|
||||
frame_length: NonZeroU32::new(240),
|
||||
clock_rate,
|
||||
extra_data: Bytes::new(),
|
||||
config: super::AudioCodecConfig::Other,
|
||||
}),
|
||||
pending: None,
|
||||
})
|
||||
Ok(Self { pending: None })
|
||||
}
|
||||
|
||||
pub(super) fn parameters(&self) -> Option<&super::Parameters> {
|
||||
Some(&self.parameters)
|
||||
pub(super) fn parameters(&self) -> Option<super::Parameters> {
|
||||
Some(super::Parameters::Audio(super::AudioParameters {
|
||||
rfc6381_codec: None,
|
||||
frame_length: NonZeroU32::new(240),
|
||||
clock_rate: FIXED_CLOCK_RATE,
|
||||
extra_data: Bytes::new(),
|
||||
sample_entry: None,
|
||||
}))
|
||||
}
|
||||
|
||||
fn validate(pkt: &crate::client::rtp::Packet) -> bool {
|
||||
|
@ -114,8 +114,10 @@ impl Depacketizer {
|
||||
})
|
||||
}
|
||||
|
||||
pub(super) fn parameters(&self) -> Option<&super::Parameters> {
|
||||
Some(&self.parameters.generic_parameters)
|
||||
pub(super) fn parameters(&self) -> Option<super::Parameters> {
|
||||
Some(super::Parameters::Video(
|
||||
self.parameters.generic_parameters.clone(),
|
||||
))
|
||||
}
|
||||
|
||||
pub(super) fn push(&mut self, pkt: Packet) -> Result<(), String> {
|
||||
@ -419,10 +421,7 @@ impl Depacketizer {
|
||||
let pps_nal = new_pps.as_deref().unwrap_or(&self.parameters.pps_nal);
|
||||
// TODO: could map this to a RtpPacketError more accurately.
|
||||
self.parameters = InternalParameters::parse_sps_and_pps(sps_nal, pps_nal)?;
|
||||
match self.parameters.generic_parameters {
|
||||
super::Parameters::Video(ref p) => Some(p.clone()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
Some(Box::new(self.parameters.generic_parameters.clone()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -457,7 +456,7 @@ impl AccessUnit {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct InternalParameters {
|
||||
generic_parameters: super::Parameters,
|
||||
generic_parameters: super::VideoParameters,
|
||||
|
||||
/// The (single) SPS NAL.
|
||||
sps_nal: Bytes,
|
||||
@ -599,13 +598,13 @@ impl InternalParameters {
|
||||
let sps_nal = avc_decoder_config.slice(sps_nal_start..sps_nal_end);
|
||||
let pps_nal = avc_decoder_config.slice(pps_nal_start..pps_nal_end);
|
||||
Ok(InternalParameters {
|
||||
generic_parameters: super::Parameters::Video(super::VideoParameters {
|
||||
generic_parameters: super::VideoParameters {
|
||||
rfc6381_codec,
|
||||
pixel_dimensions,
|
||||
pixel_aspect_ratio,
|
||||
frame_rate,
|
||||
extra_data: avc_decoder_config,
|
||||
}),
|
||||
},
|
||||
sps_nal,
|
||||
pps_nal,
|
||||
})
|
||||
|
139
src/codec/mod.rs
139
src/codec/mod.rs
@ -10,7 +10,6 @@
|
||||
use std::num::{NonZeroU16, NonZeroU32};
|
||||
|
||||
use crate::client::rtp;
|
||||
use crate::error::ErrorInt;
|
||||
use crate::ConnectionContext;
|
||||
use crate::Error;
|
||||
use bytes::{Buf, Bytes};
|
||||
@ -114,13 +113,7 @@ pub struct AudioParameters {
|
||||
frame_length: Option<NonZeroU32>,
|
||||
clock_rate: u32,
|
||||
extra_data: Bytes,
|
||||
config: AudioCodecConfig,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum AudioCodecConfig {
|
||||
Aac(aac::AudioSpecificConfig),
|
||||
Other,
|
||||
sample_entry: Option<Bytes>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AudioParameters {
|
||||
@ -153,13 +146,12 @@ impl AudioParameters {
|
||||
&self.extra_data
|
||||
}
|
||||
|
||||
/// Builds an `.mp4` `SimpleAudioEntry` box (as defined in ISO/IEC 14496-12) if possible.
|
||||
/// An `.mp4` `SimpleAudioEntry` box (as defined in ISO/IEC 14496-12), if possible.
|
||||
///
|
||||
/// Not all codecs can be placed into a `.mp4` file, and even for supported codecs there
|
||||
/// may be unsupported edge cases.
|
||||
pub fn sample_entry(&self) -> Result<Bytes, Error> {
|
||||
// TODO: InvalidArgument doesn't seem quite right. We probably should
|
||||
// produce the mp4a eagerly anyway.
|
||||
aac::get_mp4a_box(self).map_err(|description| wrap!(ErrorInt::InvalidArgument(description)))
|
||||
pub fn sample_entry(&self) -> Option<&Bytes> {
|
||||
self.sample_entry.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,7 +232,8 @@ impl std::fmt::Debug for MessageFrame {
|
||||
/// specified here; they can be calculated from the timestamp of a following
|
||||
/// picture, or approximated via the frame rate.
|
||||
pub struct VideoFrame {
|
||||
pub new_parameters: Option<VideoParameters>,
|
||||
// New video parameters. Rarely populated and large, so boxed to reduce bloat.
|
||||
pub new_parameters: Option<Box<VideoParameters>>,
|
||||
|
||||
/// Number of lost RTP packets before this video frame. See [crate::client::rtp::Packet::loss].
|
||||
/// Note that if loss occurs during a fragmented frame, more than this number of packets' worth
|
||||
@ -318,10 +311,10 @@ pub struct Depacketizer(DepacketizerInner);
|
||||
#[derive(Debug)]
|
||||
enum DepacketizerInner {
|
||||
Aac(Box<aac::Depacketizer>),
|
||||
SimpleAudio(simple_audio::Depacketizer),
|
||||
G723(g723::Depacketizer),
|
||||
SimpleAudio(Box<simple_audio::Depacketizer>),
|
||||
G723(Box<g723::Depacketizer>),
|
||||
H264(Box<h264::Depacketizer>),
|
||||
Onvif(onvif::Depacketizer),
|
||||
Onvif(Box<onvif::Depacketizer>),
|
||||
}
|
||||
|
||||
impl Depacketizer {
|
||||
@ -346,40 +339,44 @@ impl Depacketizer {
|
||||
channels,
|
||||
format_specific_params,
|
||||
)?)),
|
||||
("audio", "g726-16") => {
|
||||
DepacketizerInner::SimpleAudio(simple_audio::Depacketizer::new(clock_rate, 2))
|
||||
}
|
||||
("audio", "g726-24") => {
|
||||
DepacketizerInner::SimpleAudio(simple_audio::Depacketizer::new(clock_rate, 3))
|
||||
}
|
||||
("audio", "dvi4") | ("audio", "g726-32") => {
|
||||
DepacketizerInner::SimpleAudio(simple_audio::Depacketizer::new(clock_rate, 4))
|
||||
}
|
||||
("audio", "g726-40") => {
|
||||
DepacketizerInner::SimpleAudio(simple_audio::Depacketizer::new(clock_rate, 5))
|
||||
}
|
||||
("audio", "g726-16") => DepacketizerInner::SimpleAudio(Box::new(
|
||||
simple_audio::Depacketizer::new(clock_rate, 2),
|
||||
)),
|
||||
("audio", "g726-24") => DepacketizerInner::SimpleAudio(Box::new(
|
||||
simple_audio::Depacketizer::new(clock_rate, 3),
|
||||
)),
|
||||
("audio", "dvi4") | ("audio", "g726-32") => DepacketizerInner::SimpleAudio(Box::new(
|
||||
simple_audio::Depacketizer::new(clock_rate, 4),
|
||||
)),
|
||||
("audio", "g726-40") => DepacketizerInner::SimpleAudio(Box::new(
|
||||
simple_audio::Depacketizer::new(clock_rate, 5),
|
||||
)),
|
||||
("audio", "pcma") | ("audio", "pcmu") | ("audio", "u8") | ("audio", "g722") => {
|
||||
DepacketizerInner::SimpleAudio(simple_audio::Depacketizer::new(clock_rate, 8))
|
||||
}
|
||||
("audio", "l16") => {
|
||||
DepacketizerInner::SimpleAudio(simple_audio::Depacketizer::new(clock_rate, 16))
|
||||
DepacketizerInner::SimpleAudio(Box::new(simple_audio::Depacketizer::new(
|
||||
clock_rate, 8,
|
||||
)))
|
||||
}
|
||||
("audio", "l16") => DepacketizerInner::SimpleAudio(Box::new(
|
||||
simple_audio::Depacketizer::new(clock_rate, 16),
|
||||
)),
|
||||
// Dahua cameras when configured with G723 send packets with a
|
||||
// non-standard encoding-name "G723.1" and length 40, which doesn't
|
||||
// make sense. Don't try to depacketize these.
|
||||
("audio", "g723") => DepacketizerInner::G723(g723::Depacketizer::new(clock_rate)?),
|
||||
("application", "vnd.onvif.metadata") => {
|
||||
DepacketizerInner::Onvif(onvif::Depacketizer::new(CompressionType::Uncompressed))
|
||||
}
|
||||
("application", "vnd.onvif.metadata.gzip") => {
|
||||
DepacketizerInner::Onvif(onvif::Depacketizer::new(CompressionType::GzipCompressed))
|
||||
}
|
||||
("application", "vnd.onvif.metadata.exi.onvif") => {
|
||||
DepacketizerInner::Onvif(onvif::Depacketizer::new(CompressionType::ExiDefault))
|
||||
}
|
||||
("application", "vnd.onvif.metadata.exi.ext") => {
|
||||
DepacketizerInner::Onvif(onvif::Depacketizer::new(CompressionType::ExiInBand))
|
||||
("audio", "g723") => {
|
||||
DepacketizerInner::G723(Box::new(g723::Depacketizer::new(clock_rate)?))
|
||||
}
|
||||
("application", "vnd.onvif.metadata") => DepacketizerInner::Onvif(Box::new(
|
||||
onvif::Depacketizer::new(CompressionType::Uncompressed),
|
||||
)),
|
||||
("application", "vnd.onvif.metadata.gzip") => DepacketizerInner::Onvif(Box::new(
|
||||
onvif::Depacketizer::new(CompressionType::GzipCompressed),
|
||||
)),
|
||||
("application", "vnd.onvif.metadata.exi.onvif") => DepacketizerInner::Onvif(Box::new(
|
||||
onvif::Depacketizer::new(CompressionType::ExiDefault),
|
||||
)),
|
||||
("application", "vnd.onvif.metadata.exi.ext") => DepacketizerInner::Onvif(Box::new(
|
||||
onvif::Depacketizer::new(CompressionType::ExiInBand),
|
||||
)),
|
||||
(_, _) => {
|
||||
log::info!(
|
||||
"no depacketizer for media/encoding_name {}/{}",
|
||||
@ -394,7 +391,7 @@ impl Depacketizer {
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn parameters(&self) -> Option<&Parameters> {
|
||||
pub fn parameters(&self) -> Option<Parameters> {
|
||||
match &self.0 {
|
||||
DepacketizerInner::Aac(d) => d.parameters(),
|
||||
DepacketizerInner::G723(d) => d.parameters(),
|
||||
@ -424,3 +421,53 @@ impl Depacketizer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// See with: cargo test -- --nocapture codec::tests::print_sizes
|
||||
#[test]
|
||||
fn print_sizes() {
|
||||
for (name, size) in [
|
||||
("Depacketizer", std::mem::size_of::<Depacketizer>()),
|
||||
(
|
||||
"aac::Depacketizer",
|
||||
std::mem::size_of::<aac::Depacketizer>(),
|
||||
),
|
||||
(
|
||||
"g723::Depacketizer",
|
||||
std::mem::size_of::<g723::Depacketizer>(),
|
||||
),
|
||||
(
|
||||
"h264::Depacketizer",
|
||||
std::mem::size_of::<h264::Depacketizer>(),
|
||||
),
|
||||
(
|
||||
"onvif::Depacketizer",
|
||||
std::mem::size_of::<onvif::Depacketizer>(),
|
||||
),
|
||||
(
|
||||
"simple_audio::Depacketizer",
|
||||
std::mem::size_of::<simple_audio::Depacketizer>(),
|
||||
),
|
||||
("CodecItem", std::mem::size_of::<CodecItem>()),
|
||||
("VideoFrame", std::mem::size_of::<VideoFrame>()),
|
||||
("AudioFrame", std::mem::size_of::<AudioFrame>()),
|
||||
("MessageFrame", std::mem::size_of::<MessageFrame>()),
|
||||
(
|
||||
"SenderReport",
|
||||
std::mem::size_of::<crate::client::rtp::SenderReport>(),
|
||||
),
|
||||
("Parameters", std::mem::size_of::<Parameters>()),
|
||||
("VideoParameters", std::mem::size_of::<VideoParameters>()),
|
||||
("AudioParameters", std::mem::size_of::<AudioParameters>()),
|
||||
(
|
||||
"MessageParameters",
|
||||
std::mem::size_of::<MessageParameters>(),
|
||||
),
|
||||
] {
|
||||
println!("{:-40} {:4}", name, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use bytes::{Buf, BufMut, BytesMut};
|
||||
|
||||
use super::CodecItem;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum CompressionType {
|
||||
Uncompressed,
|
||||
GzipCompressed,
|
||||
@ -22,7 +22,7 @@ pub enum CompressionType {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Depacketizer {
|
||||
parameters: super::Parameters,
|
||||
compression_type: CompressionType,
|
||||
state: State,
|
||||
high_water_size: usize,
|
||||
}
|
||||
@ -45,14 +45,16 @@ struct InProgress {
|
||||
impl Depacketizer {
|
||||
pub(super) fn new(compression_type: CompressionType) -> Self {
|
||||
Depacketizer {
|
||||
parameters: super::Parameters::Message(super::MessageParameters(compression_type)),
|
||||
compression_type,
|
||||
state: State::Idle,
|
||||
high_water_size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parameters(&self) -> Option<&super::Parameters> {
|
||||
Some(&self.parameters)
|
||||
pub(super) fn parameters(&self) -> Option<super::Parameters> {
|
||||
Some(super::Parameters::Message(super::MessageParameters(
|
||||
self.compression_type,
|
||||
)))
|
||||
}
|
||||
|
||||
pub(super) fn push(&mut self, pkt: crate::client::rtp::Packet) -> Result<(), String> {
|
||||
|
@ -12,7 +12,7 @@ use super::CodecItem;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Depacketizer {
|
||||
parameters: super::Parameters,
|
||||
clock_rate: u32,
|
||||
pending: Option<super::AudioFrame>,
|
||||
bits_per_sample: u32,
|
||||
}
|
||||
@ -21,20 +21,20 @@ impl Depacketizer {
|
||||
/// Creates a new Depacketizer.
|
||||
pub(super) fn new(clock_rate: u32, bits_per_sample: u32) -> Self {
|
||||
Self {
|
||||
parameters: super::Parameters::Audio(super::AudioParameters {
|
||||
rfc6381_codec: None,
|
||||
frame_length: None, // variable
|
||||
clock_rate,
|
||||
extra_data: Bytes::new(),
|
||||
config: super::AudioCodecConfig::Other,
|
||||
}),
|
||||
bits_per_sample,
|
||||
pending: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parameters(&self) -> Option<&super::Parameters> {
|
||||
Some(&self.parameters)
|
||||
pub(super) fn parameters(&self) -> Option<super::Parameters> {
|
||||
Some(super::Parameters::Audio(super::AudioParameters {
|
||||
rfc6381_codec: None,
|
||||
frame_length: None, // variable
|
||||
clock_rate: self.clock_rate,
|
||||
extra_data: Bytes::new(),
|
||||
sample_entry: None,
|
||||
}))
|
||||
}
|
||||
|
||||
fn frame_length(&self, payload_len: usize) -> Option<NonZeroU32> {
|
||||
|
Loading…
Reference in New Issue
Block a user