Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions rtc-rtp/src/codec/h264/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,24 @@ impl H264Payloader {
self.pps_nalu = Some(nalu.clone());
return;
} else if let (Some(sps_nalu), Some(pps_nalu)) = (&self.sps_nalu, &self.pps_nalu) {
// Pack current NALU with SPS and PPS as STAP-A
let sps_len = (sps_nalu.len() as u16).to_be_bytes();
let pps_len = (pps_nalu.len() as u16).to_be_bytes();

let mut stap_a_nalu = Vec::with_capacity(1 + 2 + sps_nalu.len() + 2 + pps_nalu.len());
stap_a_nalu.push(OUTPUT_STAP_AHEADER);
stap_a_nalu.extend(sps_len);
stap_a_nalu.extend_from_slice(sps_nalu);
stap_a_nalu.extend(pps_len);
stap_a_nalu.extend_from_slice(pps_nalu);
if stap_a_nalu.len() <= mtu {
payloads.push(Bytes::from(stap_a_nalu));
// Pack current NALU with SPS and PPS as STAP-A.
// STAP-A length fields are u16; only pack if both NALUs fit within 65535 bytes.
if sps_nalu.len() <= u16::MAX as usize && pps_nalu.len() <= u16::MAX as usize {
let sps_len = (sps_nalu.len() as u16).to_be_bytes();
let pps_len = (pps_nalu.len() as u16).to_be_bytes();

let mut stap_a_nalu =
Vec::with_capacity(1 + 2 + sps_nalu.len() + 2 + pps_nalu.len());
stap_a_nalu.push(OUTPUT_STAP_AHEADER);
stap_a_nalu.extend(sps_len);
stap_a_nalu.extend_from_slice(sps_nalu);
stap_a_nalu.extend(pps_len);
stap_a_nalu.extend_from_slice(pps_nalu);
if stap_a_nalu.len() <= mtu {
payloads.push(Bytes::from(stap_a_nalu));
}
}
}
} // else if let (Some(sps_nalu), Some(pps_nalu))

if self.sps_nalu.is_some() && self.pps_nalu.is_some() {
self.sps_nalu = None;
Expand Down
4 changes: 4 additions & 0 deletions rtc-rtp/src/codec/h265/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ impl HevcPayloader {
);
aggr_nalu.extend_from_slice(&header);
for nalu in nalus.drain(..) {
// Aggregation unit length field is u16; skip oversized NALUs.
if nalu.len() > u16::MAX as usize {
continue;
}
aggr_nalu.extend_from_slice(&(nalu.len() as u16).to_be_bytes());
aggr_nalu.extend_from_slice(&nalu);
}
Expand Down
20 changes: 17 additions & 3 deletions rtc-rtp/src/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ impl Marshal for Header {
return Err(Error::ErrBufferTooSmall);
}

// The first byte contains the version, padding bit, extension bit, and csrc size
// The first byte contains the version, padding bit, extension bit, and csrc size.
// RFC 3550 §5.1: CC is a 4-bit field, so at most 15 contributing sources are allowed.
if self.csrc.len() > 15 {
return Err(Error::TooManyCSRCs(self.csrc.len()));
}
let mut b0 = (self.version << VERSION_SHIFT) | self.csrc.len() as u8;
if self.padding {
b0 |= 1 << PADDING_SHIFT;
Expand Down Expand Up @@ -296,15 +300,25 @@ impl Marshal for Header {
// RFC 8285 RTP One Byte Header Extension
EXTENSION_PROFILE_ONE_BYTE => {
for extension in &self.extensions {
buf.put_u8((extension.id << 4) | (extension.payload.len() as u8 - 1));
// RFC 8285 §4.2: payload must be 1–16 bytes; the length field encodes (len-1).
let len = extension.payload.len();
if len == 0 || len > 16 {
return Err(Error::OneByteHeaderExtensionPayloadTooLarge(len));
}
buf.put_u8((extension.id << 4) | (len as u8 - 1));
buf.put(&*extension.payload);
}
}
// RFC 8285 RTP Two Byte Header Extension
EXTENSION_PROFILE_TWO_BYTE => {
for extension in &self.extensions {
// RFC 8285 §4.3: length field is one byte, so max payload is 255 bytes.
let len = extension.payload.len();
if len > 255 {
return Err(Error::TwoByteHeaderExtensionPayloadTooLarge(len));
}
buf.put_u8(extension.id);
buf.put_u8(extension.payload.len() as u8);
buf.put_u8(len as u8);
buf.put(&*extension.payload);
}
}
Expand Down
8 changes: 8 additions & 0 deletions rtc-shared/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,14 @@ pub enum Error {

#[error("extension_payload must be in 32-bit words")]
HeaderExtensionPayloadNot32BitWords,
#[error("too many CSRCs: {0} exceeds the 4-bit CC field maximum of 15")]
TooManyCSRCs(usize),
#[error("one-byte header extension payload length {0} exceeds RFC 8285 maximum of 16 bytes")]
OneByteHeaderExtensionPayloadTooLarge(usize),
#[error("two-byte header extension payload length {0} exceeds maximum of 255 bytes")]
TwoByteHeaderExtensionPayloadTooLarge(usize),
#[error("NALU length {0} exceeds u16::MAX (65535 bytes)")]
NaluTooLarge(usize),
#[error("audio level overflow")]
AudioLevelOverflow,
#[error("playout delay overflow")]
Expand Down