Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

seek(SeekMode::Accurate, x) can jump onto a position that is after the requested seek position #261

Closed
abique opened this issue Feb 9, 2024 · 14 comments
Milestone

Comments

@abique
Copy link
Contributor

abique commented Feb 9, 2024

Hi,

I've written some fuzzing tests with symphonia and the following assertion fails:

let seeked_to = self.reader.seek(
    SeekMode::Accurate,
    SeekTo::TimeStamp {
        ts: frame as u64,
        track_id: self.track_id,
    },
)?;

assert!(seeked_to.actual_ts <= frame);

Here is what the debugger shows:

{track_id:0, required_ts:9535043, actual_ts:9535488}

According to the documentation we could always assert that assert!(actual_ts < required_ts);:

pub enum SeekMode {
    /// Coarse seek mode is a best-effort attempt to seek to the requested position. The actual
    /// position seeked to may be before or after the requested position. Coarse seeking is an
    /// optional performance enhancement. If a `FormatReader` does not support this mode an
    /// accurate seek will be performed instead.
    Coarse,
    /// Accurate (aka sample-accurate) seek mode will be always seek to a position before the
    /// requested position.
    Accurate,
}

This happened on a FLAC file.

Cheers,
Alex

@abique
Copy link
Contributor Author

abique commented Feb 9, 2024

By the way I had gapless = true.
Maybe this could be the reason why?

@abique
Copy link
Contributor Author

abique commented Feb 9, 2024

Actually, even with gapless = false I still get the issue.

@abique
Copy link
Contributor Author

abique commented Feb 9, 2024

After reading the flac demuxer, it turns out that it currently ignores both gapless and the seek mode.

@abique
Copy link
Contributor Author

abique commented Feb 9, 2024

This loop seems suspicious to me, it seems that the loop can only forward. Maybe I don't understand correctly what those function do.

@abique
Copy link
Contributor Author

abique commented Feb 9, 2024

I've opened #262

@abique
Copy link
Contributor Author

abique commented Feb 10, 2024

Maybe this is what happens:

  1. the binary search cuts too close to the desired seek point, yet it cuts before it
  2. the algorithm then switches to the linear search which skips over the desired seek point, there's a comment "overshoot ..."

I believe the linear search doesn't work, maybe when it is at the edge?

@abique
Copy link
Contributor Author

abique commented Feb 10, 2024

By the way I could run flac -a and flac -t on the file in question and it didn't report any problem.
So I think that the issue is in Symphonia.

@pdeljanov
Copy link
Owner

Thanks for this. I think your PR and solution makes sense. I'll give it some testing on my end.

The goal of the binary search is to find the FLAC frame that contains the sample with the desired timestamp. The timestamp of the FLAC frame is the timestamp of the first sample in that frame. So it would make sense to use >= instead of >. That may have been a typo.

After reading the flac demuxer, it turns out that it currently ignores both gapless and the seek mode.

FLAC is naturally gapless and contains enough timing information to implement a cheap accurate seek, so these two options are not relevant to FLAC!

@abique
Copy link
Contributor Author

abique commented Feb 14, 2024

The PR isn't enough to fix the issue.
I've added the following behavior in my reader to workaround this issue and it worked:

  1. seek Accurate to N
  2. if seek didn't work, seek accurate to N - M * K until it seeks before N
  3. read up to N

I'd suggest that symphonia does something similar in order to honnor the interface contract.

seek(pos, is_accurate)
{
   do_seek(pos, is_accurate);
   if (is_accurate)
   {
      assert did_seek_accurately;
      if (!did_seek_accurately)
         seek_accurately_using_workaround(pos);
   }
}

@pdeljanov
Copy link
Owner

Could you provide a test vector that reproduces your problem?

Asserting is not an acceptable solution since that will panic the end-user application. It is very conceivable that a broken (e.g., a file with missing FLAC frames), or malicious file could trigger a failure.

A fix should be implemented for well-formed files, but for other cases I think the behaviour is acceptable.

@pdeljanov pdeljanov added this to the v0.5.4 milestone Feb 16, 2024
@abique
Copy link
Contributor Author

abique commented Feb 16, 2024

@pdeljanov yes, I can share one file with a seek offset, but not publicly as it isn't free music. How to send it to you?

@pdeljanov
Copy link
Owner

@abique Thanks. You can send it to philip (dot) deljanov (at) gmail (dot) com.

@abique
Copy link
Contributor Author

abique commented Feb 17, 2024

@pdeljanov sent.

@pdeljanov
Copy link
Owner

Thanks! Fixed!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy