update seek routine to use info from seek table

This commit is contained in:
Josh Coalson 2001-04-13 18:42:12 +00:00
parent 167658a907
commit ce025f577d

View File

@ -378,6 +378,7 @@ void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMe
else if(metadata->type == FLAC__METADATA_TYPE_SEEKTABLE) {
file_decoder->guts->seek_table = &metadata->data.seek_table;
}
if(file_decoder->state != FLAC__FILE_DECODER_SEEKING)
file_decoder->guts->metadata_callback(file_decoder, metadata, file_decoder->guts->client_data);
}
@ -393,7 +394,8 @@ void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErro
bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64 target_sample)
{
long lower_bound, upper_bound, pos, last_pos = -1;
long first_frame_offset, lower_bound, upper_bound, pos = -1, last_pos = -1;
int i, lower_seek_point = -1;
unsigned approx_bytes_per_frame;
uint64 last_frame_sample = 0xffffffffffffffff;
bool needs_seek;
@ -410,17 +412,26 @@ bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64
else
approx_bytes_per_frame = 1152 * decoder->guts->stream_info.channels * decoder->guts->stream_info.bits_per_sample/8 + 64;
/* The file pointer is currently at the first frame plus any read
ahead data, so first we get the file pointer, then subtract
uncomsumed bytes to get the position (lower_bound) of the first frame
in the file */
if(-1 == (lower_bound = ftell(decoder->guts->file))) {
/*
* The file pointer is currently at the first frame plus any read
* ahead data, so first we get the file pointer, then subtract
* uncomsumed bytes to get the position of the first frame in the
* file.
*/
if(-1 == (first_frame_offset = ftell(decoder->guts->file))) {
decoder->state = FLAC__FILE_DECODER_SEEK_ERROR;
return false;
}
lower_bound -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream);
if(lower_bound < 0)
lower_bound = 0;
first_frame_offset -= FLAC__stream_decoder_input_bytes_unconsumed(decoder->guts->stream);
assert(first_frame_offset >= 0);
/*
* First, we set an upper and lower bound on where in the
* file we will search. For now we assume the worst case
* scenario, which is our best guess at the beginning of
* the first and last frames.
*/
lower_bound = first_frame_offset;
/* calc the upper_bound, beyond which we never want to seek */
if(decoder->guts->stream_info.max_framesize > 0)
@ -428,13 +439,63 @@ bool seek_to_absolute_sample_(FLAC__FileDecoder *decoder, long filesize, uint64
else
upper_bound = filesize - ((decoder->guts->stream_info.channels * decoder->guts->stream_info.bits_per_sample * FLAC__MAX_BLOCK_SIZE) / 8 + 128 + 2);
/* Now we need to use the metadata and the filelength to search to the frame with the correct sample */
/*
* Now we refine the bounds if we have a seektable with
* suitable points. Note that according to the spec they
* must be ordered by ascending sample number.
*/
if(0 != decoder->guts->seek_table) {
/* find the closest seek point <= target_sample, if it exists */
for(i = (int)decoder->guts->seek_table->num_points - 1; i >= 0; i--) {
if(decoder->guts->seek_table->points[i].sample_number <= target_sample)
break;
}
if(i >= 0) { /* i.e. we found a suitable seek point... */
lower_bound = first_frame_offset + decoder->guts->seek_table->points[i].stream_offset;
lower_seek_point = i;
}
/* find the closest seek point > target_sample, if it exists */
for(i = 0; i < (int)decoder->guts->seek_table->num_points; i++) {
if(decoder->guts->seek_table->points[i].sample_number > target_sample)
break;
}
if(i < (int)decoder->guts->seek_table->num_points) { /* i.e. we found a suitable seek point... */
upper_bound = first_frame_offset + decoder->guts->seek_table->points[i].stream_offset;
upper_seek_point = i;
}
}
/*
* Now guess at where within those bounds our target
* sample will be.
*/
if(lower_seek_point >= 0) {
/* first see if our sample is within a few frames of the lower seekpoint */
if(decoder->guts->seek_table->points[lower_seek_point].sample_number <= target_sample && target_sample < decoder->guts->seek_table->points[lower_seek_point].sample_number + (decoder->guts->seek_table->points[lower_seek_point].frame_samples * 4)) {
pos = lower_bound;
}
else if(upper_seek_point >= 0) {
const uint64 target_offset = target_sample - decoder->guts->seek_table->points[lower_seek_point].sample_number;
const uint64 range_samples = decoder->guts->seek_table->points[upper_seek_point].sample_number - decoder->guts->seek_table->points[lower_seek_point].sample_number;
const long range_bytes = upper_bound - lower_bound;
#ifdef _MSC_VER
/* with VC++ you have to spoon feed it the casting */
pos = lower_bound + (long)((double)(int64)target_sample / (double)(int64)decoder->guts->stream_info.total_samples * (double)(filesize-lower_bound-1)) - approx_bytes_per_frame;
/* with VC++ you have to spoon feed it the casting */
pos = lower_bound + (long)((double)(int64)target_offset / (double)(int64)range_samples * (double)(range_bytes-1)) - approx_bytes_per_frame;
#else
pos = lower_bound + (long)((double)target_sample / (double)decoder->guts->stream_info.total_samples * (double)(filesize-lower_bound-1)) - approx_bytes_per_frame;
pos = lower_bound + (long)((double)target_offset / (double)range_samples * (double)(range_bytes-1)) - approx_bytes_per_frame;
#endif
}
}
if(pos < 0) {
/* We need to use the metadata and the filelength to estimate the position of the frame with the correct sample */
#ifdef _MSC_VER
/* with VC++ you have to spoon feed it the casting */
pos = first_frame_offset + (long)((double)(int64)target_sample / (double)(int64)decoder->guts->stream_info.total_samples * (double)(filesize-first_frame_offset-1)) - approx_bytes_per_frame;
#else
pos = first_frame_offset + (long)((double)target_sample / (double)decoder->guts->stream_info.total_samples * (double)(filesize-first_frame_offset-1)) - approx_bytes_per_frame;
#endif
}
/* clip the position to the bounds, lower bound takes precedence */
if(pos >= upper_bound)