Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ogg: Decode opus packet durations #231

Merged
merged 2 commits into from
Feb 22, 2024
Merged
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
62 changes: 58 additions & 4 deletions symphonia-format-ogg/src/mappings/opus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,63 @@ pub fn detect(buf: &[u8]) -> Result<Option<Box<dyn Mapper>>> {
pub struct OpusPacketParser {}

impl PacketParser for OpusPacketParser {
fn parse_next_packet_dur(&mut self, _packet: &[u8]) -> u64 {
// TODO: Implement.
0
fn parse_next_packet_dur(&mut self, packet: &[u8]) -> u64 {
// See https://www.rfc-editor.org/rfc/rfc6716
// Read TOC (Table Of Contents) byte which is the first byte in the opus data.
let toc_byte = match packet.get(0) {
Some(b) => b,
None => {
warn!("opus packet empty");
return 0;
}
};
// The configuration number is the 5 most significant bits. Shift out 3 least significant
// bits.
let configuration_number = toc_byte >> 3; // max 2^5-1 = 31

// The configuration number maps to packet length according to this lookup table.
// See https://www.rfc-editor.org/rfc/rfc6716 top half of page 14.
// Numbers are in milliseconds in the rfc. Down below they are in TimeBase units, so
// 10ms = 10*48.
#[rustfmt::skip]
const CONFIGURATION_NUMBER_TO_FRAME_DURATION: [u32; 32] = [
10*48, 20*48, 40*48, 60*48,
10*48, 20*48, 40*48, 60*48,
10*48, 20*48, 40*48, 60*48,
10*48, 20*48,
10*48, 20*48,
(2.5*48.0) as u32, 5*48, 10*48, 20*48,
(2.5*48.0) as u32, 5*48, 10*48, 20*48,
(2.5*48.0) as u32, 5*48, 10*48, 20*48,
(2.5*48.0) as u32, 5*48, 10*48, 20*48,
];
// Look up the frame length.
let frame_duration =
CONFIGURATION_NUMBER_TO_FRAME_DURATION[configuration_number as usize] as u64;

// Look up the number of frames in the packet.
// See https://www.rfc-editor.org/rfc/rfc6716 bottom half of page 14.
let c = toc_byte & 0b11; // Note: it's actually called "c" in the rfc.
let num_frames = match c {
0 => 1,
1 | 2 => 2,
3 => match packet.get(1) {
Some(byte) => {
// TOC byte is followed by number of frames. See page 18 section 3.2.5 code 3
let m = byte & 0b11111; // Note: it's actually called "M" in the rfc.
m as u64
}
None => {
// What to do here? I'd like to return an error but this is an infalliable
// trait.
warn!("opus code 3 packet with no following byte containing number of frames");
return 0;
}
},
_ => unreachable!("masked 2 bits"),
};
// Look up the packet length and return it.
frame_duration * num_frames
}
}

Expand Down Expand Up @@ -184,7 +238,7 @@ impl Mapper for OpusMapper {

fn map_packet(&mut self, packet: &[u8]) -> Result<MapResult> {
if !self.need_comment {
Ok(MapResult::StreamData { dur: 0 })
Ok(MapResult::StreamData { dur: OpusPacketParser {}.parse_next_packet_dur(packet) })
}
else {
let mut reader = BufReader::new(packet);
Expand Down
Loading