Skip to content

Commit

Permalink
aac: add more validations in approximate frame count logic
Browse files Browse the repository at this point in the history
  • Loading branch information
sscobici committed Feb 17, 2025
1 parent c92def7 commit 46d263e
Showing 1 changed file with 38 additions and 17 deletions.
55 changes: 38 additions & 17 deletions symphonia-codec-aac/src/adts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ impl FormatReader for AdtsReader<'_> {

fn approximate_frame_count(mut source: &mut MediaSourceStream<'_>) -> Result<Option<u64>> {
let original_pos = source.pos();
let total_len = match source.byte_len() {
let remaining_len = match source.byte_len() {
Some(len) => len - original_pos,
_ => return Ok(None),
};
Expand Down Expand Up @@ -428,34 +428,55 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream<'_>) -> Result<Opt
else {
// The number of points to sample within the stream.
const NUM_SAMPLE_POINTS: u64 = 4;
const NUM_FRAMES_PER_SAMPLE_POINT: u32 = 100;

let step = (total_len - original_pos) / NUM_SAMPLE_POINTS;
let step = remaining_len / NUM_SAMPLE_POINTS;

// Skip the first sample point (start of file) since it is an outlier.
for new_pos in (original_pos..total_len - step).step_by(step as usize).skip(1) {
let res = source.seek(SeekFrom::Start(new_pos));
if res.is_err() {
break;
}
// file can be small enough and not have enough NUM_FRAMES_PER_SAMPLE_POINT, but we can still read at least one frame
if step > 0 {
for new_pos in (original_pos..(original_pos + remaining_len)).step_by(step as usize) {
if source.seek(SeekFrom::Start(new_pos)).is_err() {
break;
}

let mut next_frame_pos = new_pos;
for _ in 0..NUM_FRAMES_PER_SAMPLE_POINT {
let header = match AdtsHeader::read(&mut source) {
Ok(header) => header,
_ => break,
};

next_frame_pos = source.pos() + header.payload_len() as u64;

for _ in 0..=100 {
let header = match AdtsHeader::read(&mut source) {
Ok(header) => header,
_ => break,
};
// if reading NUM_FRAMES_PER_SAMPLE_POINT frames overflow the next sample point position then break
if next_frame_pos > new_pos + step {
break;
}

parsed_n_frames += 1;
n_bytes += u64::from(header.frame_len);
parsed_n_frames += 1;
n_bytes += u64::from(header.frame_len);

// skip frame payload to avoid seaching the sync word in the audio data
if source.ignore_bytes(next_frame_pos - source.pos()).is_err() {
break;
}
}

// Reading frames from the next sample point could lead to reprocessing already calculated frames.
// Also, if no sync word was found, better to avoid redundant searches.
if next_frame_pos > new_pos + step {
break;
}
}
}

let _ = source.seek(SeekFrom::Start(original_pos))?;
}

debug!("adts: parsed {} of {} bytes to approximate duration", n_bytes, total_len);
debug!("adts: parsed {} of {} bytes to approximate duration", n_bytes, remaining_len);

match parsed_n_frames {
0 => Ok(None),
_ => Ok(Some(total_len / (n_bytes / parsed_n_frames) * SAMPLES_PER_AAC_PACKET)),
_ => Ok(Some(remaining_len / (n_bytes / parsed_n_frames) * SAMPLES_PER_AAC_PACKET)),
}
}

0 comments on commit 46d263e

Please sign in to comment.