[flac-dev] Low-level seek routines in libFLAC
Simon Zolin
stsaz at yandex.ru
Tue Jun 16 03:42:20 PDT 2015
Hello everyone!
Can we add low-level seek functions into libFLAC?
I'm using libFLAC in a program where file operations can't be completed synchronously from those user callback procedures that libFLAC calls when it needs to perform read, seek, etc. So I had to modify libFLAC in a way that it doesn't call any user callbacks while performing seeking. Although I added a dirty hack for asynchronous read() to work, my first goal here is to discuss with you a low-level seek() interface.
It's quite clear what we need to do here: just split the function seek_to_absolute_sample_() into 2 public functions (they are shown below). seek_to_absolute_sample_() can be easily modified to use those functions, and we won't change its behaviour.
The user code that uses those functions might look like this:
void foo()
{
FLAC__uint64 offset;
FLAC__stream_decoder_seek_prepare(decoder, target_sample, stream_length);
for (;;) {
FLAC__stream_decoder_seek(decoder, &offset);
my_seek(file, offset);
FLAC__stream_decoder_process_single(decoder);
if /* write() callback was called - seek has been completed */ {
puts("seek OK");
break;
}
}
}
I always like to control the full workflow of my program, and by having those seek functions I'm sure no file I/O is performed via callbacks. Ultimately, I want to have low level read/write/meta routines with no user callbacks at all, something like what libvorbis and libmad provide, though, I sense that asynchronous read() will be very hard to implement in a right way, without any hacks. But anyway, that's another topic.
If you feel that this idea is right, I'll prepare a full patch that has:
. declarations and definitions of new seek functions (mostly copy-paste from seek_to_absolute_sample_())
. modification of seek_to_absolute_sample_() to use those low-level functions inside. seek_to_absolute_sample_() will retain its current behavior.
This is a short description of the proposed API:
/*
An object of this structure lives within FLAC__StreamDecoderPrivate.
It saves the local variables needed for seek functions.
*/
typedef struct seek_t {
int state;
FLAC__uint64 lower_bound;
FLAC__uint64 upper_bound;
FLAC__uint64 lower_bound_sample;
FLAC__uint64 upper_bound_sample;
FLAC__uint64 this_frame_sample;
unsigned approx_bytes_per_frame;
FLAC__bool first_seek;
} seek_t;
/*
This function initializes an object of type "struct seek_t" and sets initial lower/upper bounds.
*/
FLAC_API int FLAC__stream_decoder_seek_prepare(FLAC__StreamDecoder *decoder, FLAC__uint64 target_sample, FLAC__uint64 stream_length);
/*
This function is called in a loop until we reach the target sample.
@abs_file_off
On input, it's the current absolute file offset.
Upon return, it contains the absolute file offset that user needs to seek to.
return 0, if target sample isn't yet reached: user needs to seek to @abs_file_off then call the function again.
return -1, if an error occurred.
*/
FLAC_API int FLAC__stream_decoder_seek(FLAC__StreamDecoder *decoder, FLAC__uint64 *abs_file_off);
Best regards,
Simon.
More information about the flac-dev
mailing list