Martijn van Beurden wrote:
As far as I know, please correct if wrong, neither libopusfile nor
libvorbisfile provide this functionality either. In neither I could
find a function to find the total number of samples over all links.
Opus has a fixed samplerate so there is no changing, but libvorbisfile
doesn't provide a way to query it on any data about the links it might
have stored.

For opusfile:

https://opus-codec.org/docs/opusfile_api-0.12/group__stream__info.html#ga8c228c3d95f2c903ad6cfd2b78d8dad6

    ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li)

_li: The index of the link whose PCM length should be computed. Use a negative number to get the PCM length of the entire stream.

"The entire stream" here includes all links in a chained stream.

https://xiph.org/vorbis/doc/vorbisfile/ov_pcm_total.html does the same thing for vorbisfile (the opusfile API is pretty much directly adapted from vorbisfile's). vorbisfile also includes an ov_time_total():

https://xiph.org/vorbis/doc/vorbisfile/ov_time_total.html

As well as an ov_time_seek():

https://xiph.org/vorbis/doc/vorbisfile/ov_time_seek.html

These were redundant and thus not implemented separately in opusfile, because as you point out, the opusfile API decodes at a fixed sample rate, so samples are the same thing as time with a particular choice of unit. However, I think they are frequently used by vorbisfile users.

https://xiph.org/vorbis/doc/vorbisfile/ov_info.html also does let you query the data from the info header of each link, with https://xiph.org/vorbis/doc/vorbisfile/ov_streams.html to tell you how many there are. This includes the sample rate, if you really wanted to do your own time calculations, but also includes important information like the channel count. It is impossible to interpret the decoded audio correctly without these.

op_head() <https://opus-codec.org/docs/opusfile_api-0.12/group__stream__info.html#gabae95dfa8a278a305213332e295443bb> and op_link_count() <https://opus-codec.org/docs/opusfile_api-0.12/group__stream__info.html#gaaf6ff40725a8bc7e73c9d396ab91837d> do the same for opusfile.

I'm not sure what would be most useful, and I am reluctant to
implement them all.

Please let me know what you think.

It is a bit of a challenge because of the need to support unseekable streams (for, e.g., internet radio, your original use-case), but also not make chained streams _too_ much more of a burden to support than a stream with a single link in the seekable case. The vorbisfile API at least has a long history of use in a lot of applications, so it should not be too terrible a guide.

I do not think seeking to a link by serial number is that useful (how does the application know the serial number in advance?). Seeking to a link by "number" is probably not that common, either, and still needs a way to know the total number of links. Being able to seek to specific samples and specific times in the entire stream are both useful, and does need a way to know the total number of samples or total duration. Being able to enumerate the information about all of the links is also quite useful. For example, an application may wish to know if the sample rate and channel count do not change in all of the links of a chained file, for the purpose of generating an RIFF header or similar.

Probably the most difficult piece to implement is doing link enumeration in an efficient way. You want to be doing some sort of bisection search to locate link boundaries, re-using previous results for subsequent links, if possible. Some thought went in to doing this efficiently in opusfile. See op_bisect_forward_serialno() <https://gitlab.xiph.org/xiph/opusfile/-/blob/master/src/opusfile.c?ref_type=heads#L1104> for details of the current approach (or maybe even start at <https://gitlab.xiph.org/xiph/opusfile/-/blob/master/src/opusfile.c?ref_type=heads#L1391> to see how the call to that function is set up).

For testing during development, I often used a file gmaxwell created that is 2.6 GB with 30 links containing over 26 hours of audio, accessed over https. It can still take several seconds to open the file under those conditions, but it is many orders of magnitude faster than trying to scan through the whole thing, and I imagine that is only more true with the high bitrate of FLAC files. Output from opusfile's seeking_example:

    Opened file containing 30 links with 194 seeks (6.467 per link).
    Loaded (240.592 kbps average).
    Testing raw seeking to random places in 2831820229 bytes...
    Total seek operations: 1000 (1.000 per raw seek, 1 maximum).
Testing exact PCM seeking to random places in 4519756545 samples (1d02h09m21.595s)...
    Total seek operations: 1873 (1.873 per exact seek, 4 maximum).
    OK.

A more typical example (~4 hours captured from an actual internet radio stream) looks like:

    Opened file containing 75 links with 425 seeks (5.667 per link).
    Loaded (98.551 kbps average).
    Testing raw seeking to random places in 169127944 bytes...
    Total seek operations: 1000 (1.000 per raw seek, 1 maximum).
Testing exact PCM seeking to random places in 658998312 samples (3h48m49.132s)...
    Total seek operations: 1001 (1.001 per exact seek, 2 maximum).
    OK.
_______________________________________________
flac-dev mailing list
flac-dev@xiph.org
http://lists.xiph.org/mailman/listinfo/flac-dev

Reply via email to