Skip to content

Commit

Permalink
better adts aprox of n_frames
Browse files Browse the repository at this point in the history
  • Loading branch information
dedobbin committed Feb 9, 2024
1 parent d492f7c commit 8ddf94b
Showing 1 changed file with 35 additions and 15 deletions.
50 changes: 35 additions & 15 deletions symphonia-codec-aac/src/adts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,12 @@ struct AdtsHeader {

impl AdtsHeader {
const SIZE: usize = 7;

fn sync<B: ReadBytes>(reader: &mut B) -> Result<()> {
let mut sync = 0u16;

while sync != 0xfff1 {
sync = (sync << 8) | u16::from(reader.read_u8()?);
}

Ok(())
}

Expand Down Expand Up @@ -268,17 +266,18 @@ impl FormatReader for AdtsReader {
}

fn aproximate_frame_count(mut source: &mut MediaSourceStream) -> Option<u64> {
// TODO: make dynamic?
const MAX_FRAMES: u32 = 20;
const MAX_BYTES: usize = 8000;

let original_pos = source.pos();

let total_len = match source.byte_len() {
Some(len) => len - original_pos,
_ => return None,
};

source.ensure_seekback_buffer(MAX_BYTES);
// Ensure can rewind, cap max bytes because we don't want to parse too much data
// TODO: make dynamic?
let max_bytes: u64 = total_len.min(100000);
source.ensure_seekback_buffer(max_bytes as usize);

macro_rules! calculate_n_frames {
($n_bytes:expr, $parsed_n_frames:expr, $total_len:expr) => {{
Expand All @@ -297,32 +296,53 @@ fn aproximate_frame_count(mut source: &mut MediaSourceStream) -> Option<u64> {

let mut parsed_n_frames = 0;
let mut n_bytes = 0;
let step = 2000;
//let step = 200;
let n_frames = loop {
if parsed_n_frames >= MAX_FRAMES || n_bytes + AdtsHeader::SIZE >= MAX_BYTES {
break calculate_n_frames!(n_bytes, parsed_n_frames, total_len);
// Find header without going over max_bytes boundry.
let mut sync = 0u16;
while sync != 0xfff1 {
if source.pos() + 1 >= max_bytes{
break;
}
let val = source.read_u8().unwrap(); //TODO: dont unwrap..
sync = (sync << 8) | u16::from(val);
}
// AdtsHeader::read will also attempt to sync. Go 2 bytes back so this will line up.
source.seek_buffered_rev(2);

// Since we are synced up, AdtsHeader::read will always read exactly AdtsHeader::SIZE bytes.
if source.pos() + AdtsHeader::SIZE as u64 >= max_bytes {
break calculate_n_frames!(n_bytes, parsed_n_frames, total_len);
}

let header = match AdtsHeader::read(&mut source) {
Ok(header) => header,
_ => {
break calculate_n_frames!(n_bytes, parsed_n_frames, total_len);
}
};
n_bytes += AdtsHeader::SIZE;

if n_bytes + header.frame_len >= MAX_BYTES {
if source.pos() + header.frame_len as u64 >= max_bytes {
break calculate_n_frames!(n_bytes, parsed_n_frames, total_len);
}

if source.ignore_bytes(header.frame_len as u64).is_err() {
break None;
break calculate_n_frames!(n_bytes, parsed_n_frames, total_len);
}

parsed_n_frames += 1;
n_bytes += header.frame_len;
};
n_bytes += header.frame_len + AdtsHeader::SIZE;

// seek_buffered_rel can read < step bytes, so even though this is not 100% accurate,
// it will never read > step bytes, so max_bytes boundry will never be crossed
if source.pos() + step >= max_bytes {
break calculate_n_frames!(n_bytes, parsed_n_frames, total_len);
}
source.seek_buffered_rel(step as isize);

};
source.seek_buffered_rev((source.pos() - original_pos) as usize);

return n_frames;
}
}

0 comments on commit 8ddf94b

Please sign in to comment.