concentus.oggfile
concentus.oggfile copied to clipboard
The code does not support seek ?
When using code like:
OpusDecoder decoder = OpusDecoder.Create(48000, 2);
OpusOggReadStream oggIn = new OpusOggReadStream(decoder, fileIn);
while (oggIn.HasNextPacket)
{
short[] packet = oggIn.DecodeNextPacket();
}
it's not possible to just jump or seek to a position in the file?
Yeah the implementation is about as bare-bones as possible. See this TODO where I punted a refactor of this whole interface.
Seeking in Ogg by itself can be a bit complicated when you have to reconcile file, stream, and granule positions, the fact that there is no global index, and the code also has to handle forwards-only streams of indeterminate length for streaming scenarios. But if you have ideas for a better implementation then I am all ears.
Would a simple option be to:
-
Just jump to a location in the (readable) stream, say at 50%.
-
Start decoding from that point on, which will probably fail. However I don't know the Opus Codec at all, but is it possible to find the next valid frame from that point on?
-
If the next valid frame is found, just start decoding as usual?
That would work as a simple option. You could just reset the opus decoder, seek to an arbitrary point, and then start searching for the next ogg page. But of course the reality is more complicated.
Perhaps a quick breakdown of OggOpus would help:
- An Ogg file is a sequence of pages. Each page is associated with an elementary stream ID - generally there's one per audio file, but not always.
- Ogg was designed for streaming so it allows new elementary streams to come and go at any time arbitrarily, or have several streams (e.g. audio and video) playing at once
- You can seek to any point in the stream and start looking for the OggS header to continue decoding from that point. However, there's no guarantee that the elementary stream you expect will still exist at that point, if you seek before or beyond where that elementary stream exists in the file.
- An opus stream is an elementary stream containing opus frames (audio data). Each page might contain 2-15 seconds of audio.
- The first two pages of it are special - OpusHead and OpusTags. These describe the encoding format and metadata of the stream before you can decode it.
- Once you've read those special pages, you can set up your opus decoder and start decoding from any point in the stream
So, there's a few wrenches that this can throw into the design for seeking:
- Someone might want to open a file and then immediately seek to the middle of it. But you can't do this until you've 1) established (or at least made an assumption) about which elementary stream ID the user wants to listen to and 2) read the preliminary OpusHead and OpusTags
- The stream might not allow random access, in which case you can seek forwards in a preestablished stream but not backwards
- The elementary stream might no longer exist at the point where you are seeking to, in which case you'd have to either lookaround for a bit and potentially fail the seek operation, or give the caller the option to switch to a different elementary stream
- Also, if you want to seek according to the playback timestamp rather than just the file position, e.g. "start playing this song from the 3:10 mark" then you'd have to implement a heuristic search to check the granule position of various pages until you've found the one you're looking for.
see https://github.com/lostromb/concentus.oggfile/pull/15