Skip to content

Commit 2c2a8e4

Browse files
committed
aac: add more validations in approximate frame count logic
1 parent 92944b1 commit 2c2a8e4

File tree

1 file changed

+31
-17
lines changed

1 file changed

+31
-17
lines changed

symphonia-codec-aac/src/adts.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ impl FormatReader for AdtsReader<'_> {
394394

395395
fn approximate_frame_count(mut source: &mut MediaSourceStream<'_>) -> Result<Option<u64>> {
396396
let original_pos = source.pos();
397-
let total_len = match source.byte_len() {
397+
let remaining_len = match source.byte_len() {
398398
Some(len) => len - original_pos,
399399
_ => return Ok(None),
400400
};
@@ -428,34 +428,48 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream<'_>) -> Result<Opt
428428
else {
429429
// The number of points to sample within the stream.
430430
const NUM_SAMPLE_POINTS: u64 = 4;
431+
const NUM_FRAMES: u32 = 100;
431432

432-
let step = (total_len - original_pos) / NUM_SAMPLE_POINTS;
433+
let step = remaining_len / NUM_SAMPLE_POINTS;
433434

434-
// Skip the first sample point (start of file) since it is an outlier.
435-
for new_pos in (original_pos..total_len - step).step_by(step as usize).skip(1) {
436-
let res = source.seek(SeekFrom::Start(new_pos));
437-
if res.is_err() {
438-
break;
439-
}
435+
// file can be small enough and not have enough NUM_FRAMES, but we can still read at least one header
436+
if step > 0 {
437+
for new_pos in (original_pos..(original_pos + remaining_len)).step_by(step as usize) {
438+
let mut cur_pos = new_pos;
439+
if source.seek(SeekFrom::Start(cur_pos)).is_err() {
440+
break;
441+
}
442+
443+
for _ in 0..NUM_FRAMES {
444+
let header = match AdtsHeader::read(&mut source) {
445+
Ok(header) => header,
446+
_ => break,
447+
};
440448

441-
for _ in 0..=100 {
442-
let header = match AdtsHeader::read(&mut source) {
443-
Ok(header) => header,
444-
_ => break,
445-
};
449+
parsed_n_frames += 1;
450+
n_bytes += u64::from(header.frame_len);
446451

447-
parsed_n_frames += 1;
448-
n_bytes += u64::from(header.frame_len);
452+
// skip frame to avoid meeting sync word in the audio data and for quick sync()
453+
cur_pos += u64::from(header.frame_len);
454+
if source.seek(SeekFrom::Start(cur_pos)).is_err() {
455+
break;
456+
}
457+
}
458+
459+
// if reading NUM_FRAMES frames overflow the next step position then break
460+
if cur_pos > new_pos + step {
461+
break;
462+
}
449463
}
450464
}
451465

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

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

457471
match parsed_n_frames {
458472
0 => Ok(None),
459-
_ => Ok(Some(total_len / (n_bytes / parsed_n_frames) * SAMPLES_PER_AAC_PACKET)),
473+
_ => Ok(Some(remaining_len / (n_bytes / parsed_n_frames) * SAMPLES_PER_AAC_PACKET)),
460474
}
461475
}

0 commit comments

Comments
 (0)