Skip to content

Commit

Permalink
fixes seek in m4a files, fixes seeking having 1 second granularity
Browse files Browse the repository at this point in the history
  • Loading branch information
dvdsk committed Oct 11, 2023
1 parent cb5b76a commit 347c482
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 32 deletions.
51 changes: 31 additions & 20 deletions src/decoder/symphonia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,36 +155,47 @@ impl Source for SymphoniaDecoder {
.total_duration()
.is_some_and(|dur| dur.saturating_sub(pos).as_millis() < 1);

if seek_beyond_end {
self.format.seek(
SeekMode::Accurate,
SeekTo::Time {
time: self.total_duration.unwrap(),
track_id: None,
},
)?;
let time = if seek_beyond_end {
let time = self.total_duration.expect("if guarentees this is Some");
adjust_down_a_bit(time) // some decoders can only seek to just before the end
} else {
let frac = if pos.subsec_nanos() == 0 {
0f64
} else {
1f64 / pos.subsec_nanos() as f64
let res = pos.subsec_nanos() as f64 / 1_000_000_000.0;
res
};
self.format.seek(
SeekMode::Accurate,
SeekTo::Time {
time: Time {
seconds: pos.as_secs(),
frac,
},
track_id: None,
},
)?;
}
Time {
seconds: pos.as_secs(),
frac,
}
};

self.format.seek(
SeekMode::Accurate,
SeekTo::Time {
time,
track_id: None,
},
)?;
Ok(())
}
}

fn adjust_down_a_bit(
Time {
mut seconds,
mut frac,
}: Time,
) -> Time {
frac -= 0.0001;
if frac < 0.0 {
seconds = seconds.saturating_sub(1);
frac = 1.0 - frac;
}
Time { seconds, frac }
}

impl Iterator for SymphoniaDecoder {
type Item = i16;

Expand Down
24 changes: 12 additions & 12 deletions tests/seek.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,37 +36,37 @@ fn sink_and_decoder(format: &str) -> (Sink, Decoder<impl Read + Seek>) {
// --features symphonia-flac --features symphonia-isomp4 --features minimp3
fn format_decoder_info() -> &'static [(&'static str, bool, &'static str)] {
&[
#[cfg(feature = "minimp3")]
#[cfg(all(feature = "minimp3", not(feature = "symphonia-mp3")))]
("mp3", false, "minimp3"),
#[cfg(feature = "symphonia-mp3")]
("mp3", true, "symphonia"),
#[cfg(feature = "hound")]
#[cfg(all(feature = "wav", not(feature = "symphonia-wav")))]
("wav", true, "hound"),
#[cfg(feature = "symphonia-wav")]
("wav", true, "symphonia"),
#[cfg(feature = "lewton")]
#[cfg(all(feature = "vorbis", not(feature = "symphonia-vorbis")))]
("ogg", true, "lewton"),
// note: disabled, symphonia returns error unsupported format
// note: disabled, broken decoder see issue: #516
// #[cfg(feature = "symphonia-vorbis")]
// ("ogg", true, "symphonia"),
#[cfg(feature = "claxon")]
#[cfg(all(feature = "flac", not(feature = "symphonia-flac")))]
("flac", false, "claxon"),
#[cfg(feature = "symphonia-flac")]
("flac", true, "symphonia"),
// note: disabled, symphonia returns error unsupported format
// #[cfg(feature = "symphonia-isomp4")]
// ("m4a", true, "symphonia"),
#[cfg(feature = "symphonia-isomp4")]
("m4a", true, "symphonia"),
]
}

#[test]
fn seek_returns_err_if_unsupported() {
for (format, supported, decoder) in format_decoder_info().iter().cloned() {
println!("trying: {format},\t\tby: {decoder},\t\tshould support seek: {supported}");
for (format, supported, decoder_name) in format_decoder_info().iter().cloned() {
println!("trying: {format},\t\tby: {decoder_name},\t\tshould support seek: {supported}");
let (sink, decoder) = sink_and_decoder(format);
sink.append(decoder);
let res = sink.try_seek(Duration::from_secs(2));
assert_eq!(res.is_ok(), supported);
let res = sink.try_seek(Duration::from_millis(2500));
assert_eq!(res.is_ok(), supported, "decoder: {decoder_name}");
}
}

Expand All @@ -83,7 +83,7 @@ fn seek_beyond_end_saturates() {

println!("seeking beyond end for: {format}\t decoded by: {decoder_name}");
let res = sink.try_seek(Duration::from_secs(999));
assert!(res.is_ok());
assert!(dbg!(res).is_ok());

let now = Instant::now();
sink.sleep_until_end();
Expand Down

0 comments on commit 347c482

Please sign in to comment.