From 7af45717e5686da7f16ca4289411f7176bd49bd1 Mon Sep 17 00:00:00 2001 From: dedobbin Date: Sun, 27 Aug 2023 21:05:40 +0200 Subject: [PATCH 1/6] adts duration --- symphonia-codec-aac/src/adts.rs | 79 ++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index 596c41dc..ae4e7ea9 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -131,12 +131,20 @@ impl FormatReader for AdtsReader { // Use the header to populate the codec parameters. let mut params = CodecParameters::new(); - params.for_codec(CODEC_TYPE_AAC).with_sample_rate(header.sample_rate); + params + .for_codec(CODEC_TYPE_AAC) + .with_sample_rate(header.sample_rate) + .with_time_base(TimeBase::new(1, header.sample_rate)); if let Some(channels) = header.channels { params.with_channels(channels); } + let n_frames = approximate_frame_count(&mut source)?; + if let Some(n_frames) = n_frames { + params.with_n_frames(n_frames); + } + // Rewind back to the start of the frame. source.seek_buffered_rev(AdtsHeader::SIZE); @@ -258,3 +266,72 @@ impl FormatReader for AdtsReader { self.reader } } + +fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result> { + let original_pos = source.pos(); + let total_len = match source.byte_len() { + Some(len) => len - original_pos, + _ => return Ok(None), + }; + + const ENSURED_SEEK_LEN: u64 = 1000; + source.ensure_seekback_buffer(ENSURED_SEEK_LEN as usize); + let mut scoped_stream = ScopedStream::new(&mut source, ENSURED_SEEK_LEN); + + let mut parsed_n_frames = 0; + let mut n_bytes = 0; + + loop { + let header = match AdtsHeader::read(&mut scoped_stream) { + Ok(header) => header, + _ => break, + }; + + if scoped_stream.ignore_bytes(header.frame_len as u64).is_err() { + break; + } + + parsed_n_frames += 1; + n_bytes += header.frame_len + AdtsHeader::SIZE; + } + source.seek_buffered_rev((source.pos() - original_pos) as usize); + + let step = total_len / 3; + if source.is_seekable() { + let mut new_pos = total_len / 2; + + loop { + if new_pos >= total_len { + break; + } + + let res = source.seek(SeekFrom::Start(new_pos)); + if res.is_err() { + break; + } + + for _ in 0..=500 { + let header = match AdtsHeader::read(&mut source) { + Ok(header) => header, + _ => break, + }; + + if source.ignore_bytes(header.frame_len as u64).is_err() { + break; + } + + parsed_n_frames += 1; + n_bytes += header.frame_len + AdtsHeader::SIZE; + } + new_pos += step; + } + + let _ = source.seek(SeekFrom::Start(original_pos))?; + } + debug!("adts: Parsed {} of {} bytes to approximate duration", n_bytes, total_len); + + match parsed_n_frames { + 0 => Ok(None), + _ => Ok(Some(total_len / (n_bytes as u64 / parsed_n_frames) * SAMPLES_PER_AAC_PACKET)), + } +} From 8f057a8fdab74811f30fc16dec4e3481c690c803 Mon Sep 17 00:00:00 2001 From: dedobbin Date: Sun, 10 Mar 2024 19:00:43 +0100 Subject: [PATCH 2/6] adts: bit cleaner loop for estimating n frames --- symphonia-codec-aac/src/adts.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index ae4e7ea9..fd9545fd 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -298,9 +298,7 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result= total_len { break; } @@ -323,7 +321,6 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result Date: Sun, 10 Mar 2024 19:06:23 +0100 Subject: [PATCH 3/6] adts: only use ensure_seekback_buffer for estimation of duration when source is not seekable --- symphonia-codec-aac/src/adts.rs | 37 +++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index fd9545fd..36ba936a 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -274,30 +274,30 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result return Ok(None), }; - const ENSURED_SEEK_LEN: u64 = 1000; - source.ensure_seekback_buffer(ENSURED_SEEK_LEN as usize); - let mut scoped_stream = ScopedStream::new(&mut source, ENSURED_SEEK_LEN); - let mut parsed_n_frames = 0; let mut n_bytes = 0; - loop { - let header = match AdtsHeader::read(&mut scoped_stream) { - Ok(header) => header, - _ => break, - }; + if !source.is_seekable() { + const ENSURED_SEEK_LEN: u64 = 1000; + source.ensure_seekback_buffer(ENSURED_SEEK_LEN as usize); + let mut scoped_stream = ScopedStream::new(&mut source, ENSURED_SEEK_LEN); - if scoped_stream.ignore_bytes(header.frame_len as u64).is_err() { - break; - } + loop { + let header = match AdtsHeader::read(&mut scoped_stream) { + Ok(header) => header, + _ => break, + }; - parsed_n_frames += 1; - n_bytes += header.frame_len + AdtsHeader::SIZE; - } - source.seek_buffered_rev((source.pos() - original_pos) as usize); + if scoped_stream.ignore_bytes(header.frame_len as u64).is_err() { + break; + } - let step = total_len / 3; - if source.is_seekable() { + parsed_n_frames += 1; + n_bytes += header.frame_len + AdtsHeader::SIZE; + } + source.seek_buffered_rev((source.pos() - original_pos) as usize); + } else { + let step = total_len / 3; for new_pos in (original_pos..total_len).step_by(step as usize).skip(1) { if new_pos >= total_len { break; @@ -325,6 +325,7 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result Date: Sun, 10 Mar 2024 19:08:07 +0100 Subject: [PATCH 4/6] adts: parse less data to estimate duration --- symphonia-codec-aac/src/adts.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index 36ba936a..a8e716be 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -296,7 +296,8 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result= total_len { @@ -308,7 +309,7 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result header, _ => break, @@ -325,7 +326,7 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result Date: Sun, 10 Mar 2024 19:35:32 +0100 Subject: [PATCH 5/6] adts: moved call of approximate_frame_count --- symphonia-codec-aac/src/adts.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index a8e716be..d684d696 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -140,16 +140,16 @@ impl FormatReader for AdtsReader { params.with_channels(channels); } - let n_frames = approximate_frame_count(&mut source)?; - if let Some(n_frames) = n_frames { - params.with_n_frames(n_frames); - } - // Rewind back to the start of the frame. source.seek_buffered_rev(AdtsHeader::SIZE); let first_frame_pos = source.pos(); + let n_frames = approximate_frame_count(&mut source)?; + if let Some(n_frames) = n_frames { + params.with_n_frames(n_frames); + } + Ok(AdtsReader { reader: source, tracks: vec![Track::new(0, params)], From 367c964a537825b0b05aae3f9565e4001bed656e Mon Sep 17 00:00:00 2001 From: Philip Deljanov Date: Sun, 10 Mar 2024 19:30:13 -0400 Subject: [PATCH 6/6] adts: minor fixes --- symphonia-codec-aac/src/adts.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/symphonia-codec-aac/src/adts.rs b/symphonia-codec-aac/src/adts.rs index d684d696..c14c94bc 100644 --- a/symphonia-codec-aac/src/adts.rs +++ b/symphonia-codec-aac/src/adts.rs @@ -20,7 +20,7 @@ use std::io::{Seek, SeekFrom}; use super::common::{map_channels, M4AType, AAC_SAMPLE_RATES, M4A_TYPES}; -use log::debug; +use log::{debug, info}; const SAMPLES_PER_AAC_PACKET: u64 = 1024; @@ -147,6 +147,7 @@ impl FormatReader for AdtsReader { let n_frames = approximate_frame_count(&mut source)?; if let Some(n_frames) = n_frames { + info!("estimating duration from bitrate, may be inaccurate for vbr files"); params.with_n_frames(n_frames); } @@ -278,9 +279,11 @@ fn approximate_frame_count(mut source: &mut MediaSourceStream) -> Result Result= total_len { - break; - } + // The number of points to sample within the stream. + const NUM_SAMPLE_POINTS: u64 = 4; + + let step = (total_len - original_pos) / 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;