From 6ca87a9e0ec90ace080f172ecda3e1850c8b4beb Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Tue, 1 Oct 2019 16:36:41 +1000 Subject: [PATCH 1/6] stb_vorbis: fix theoretical seek performance problem --- stb_vorbis.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index fd02caf..75c3de5 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -4707,14 +4707,16 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) } // if we've just found the last page again then we're in a tricky file, - // and we're close enough. - if (mid.page_start == right.page_start) - break; - - if (sample_number < mid.last_decoded_sample) - right = mid; - else - left = mid; + // and we're close enough (if it wasn't an interpolation probe). + if (mid.page_start == right.page_start) { + if (probe >= 2) + break; + } else { + if (last_sample_limit < mid.last_decoded_sample) + right = mid; + else + left = mid; + } ++probe; } From 2abc5c6ced37e2d70a5e7401dbbb9cfc5700995e Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Tue, 1 Oct 2019 16:37:22 +1000 Subject: [PATCH 2/6] stb_vorbis: fix seek_to_sample_coarse failure near page end --- stb_vorbis.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index 75c3de5..57af9e0 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -4625,7 +4625,7 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) { ProbedPage left, right, mid; int i, start_seg_with_known_loc, end_pos, page_start; - uint32 delta, stream_length, padding; + uint32 delta, stream_length, padding, last_sample_limit; double offset, bytes_per_sample; int probe = 0; @@ -4639,9 +4639,9 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) // indicates should be the granule position (give or take one)). padding = ((f->blocksize_1 - f->blocksize_0) >> 2); if (sample_number < padding) - sample_number = 0; + last_sample_limit = 0; else - sample_number -= padding; + last_sample_limit = sample_number - padding; left = f->p_first; while (left.last_decoded_sample == ~0U) { @@ -4654,7 +4654,7 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) assert(right.last_decoded_sample != ~0U); // starting from the start is handled differently - if (sample_number <= left.last_decoded_sample) { + if (last_sample_limit <= left.last_decoded_sample) { if (stb_vorbis_seek_start(f)) return 1; return 0; @@ -4673,10 +4673,10 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) // first probe (interpolate) double data_bytes = right.page_end - left.page_start; bytes_per_sample = data_bytes / right.last_decoded_sample; - offset = left.page_start + bytes_per_sample * (sample_number - left.last_decoded_sample); + offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample); } else { // second probe (try to bound the other side) - double error = ((double) sample_number - mid.last_decoded_sample) * bytes_per_sample; + double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample; if (error >= 0 && error < 8000) error = 8000; if (error < 0 && error > -8000) error = -8000; offset += error * 2; From 7c4eb44a636ab398b1aea872e4f5792ad66d7706 Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Tue, 1 Oct 2019 20:47:29 +1000 Subject: [PATCH 3/6] stb_vorbis: fix seeking in files with audio packets in header pages Fixes #682, #580 --- stb_vorbis.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index 57af9e0..0e7c7fa 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -774,8 +774,11 @@ struct stb_vorbis uint8 push_mode; + // the page to seek to when seeking to start, may be zero uint32 first_audio_page_offset; + // p_first is the page on which the first audio packet ends + // (but not necessarily the page on which it starts) ProbedPage p_first, p_last; // memory management @@ -1404,6 +1407,9 @@ static int capture_pattern(vorb *f) static int start_page_no_capturepattern(vorb *f) { uint32 loc0,loc1,n; + if (f->first_decode && !IS_PUSH_MODE(f)) { + f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4; + } // stream structure version if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); // header flag @@ -1440,15 +1446,12 @@ static int start_page_no_capturepattern(vorb *f) } if (f->first_decode) { int i,len; - ProbedPage p; len = 0; for (i=0; i < f->segment_count; ++i) len += f->segments[i]; len += 27 + f->segment_count; - p.page_start = f->first_audio_page_offset; - p.page_end = p.page_start + len; - p.last_decoded_sample = loc0; - f->p_first = p; + f->p_first.page_end = f->p_first.page_start + len; + f->p_first.last_decoded_sample = loc0; } f->next_seg = 0; return TRUE; @@ -3576,6 +3579,7 @@ static int start_decoder(vorb *f) int longest_floorlist=0; // first page, first packet + f->first_decode = TRUE; if (!start_page(f)) return FALSE; // validate page flag @@ -4132,7 +4136,6 @@ static int start_decoder(vorb *f) f->temp_memory_required = imdct_mem; } - f->first_decode = TRUE; if (f->alloc.alloc_buffer) { assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); @@ -4141,7 +4144,17 @@ static int start_decoder(vorb *f) return error(f, VORBIS_outofmem); } - f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + // @TODO: stb_vorbis_seek_start expects first_audio_page_offset to point to a page + // without PAGEFLAG_continued_packet, so this either points to the first page, or + // the page after the end of the headers. It might be cleaner to point to a page + // in the middle of the headers, when that's the page where the first audio packet + // starts, but we'd have to also correctly skip the end of any continued packet in + // stb_vorbis_seek_start. + if (f->next_seg == -1) { + f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + } else { + f->first_audio_page_offset = 0; + } return TRUE; } From 057914d959243e51b8399155d34968f1bbb151ba Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Sun, 20 Oct 2019 14:42:28 +1100 Subject: [PATCH 4/6] stb_vorbis: fix pushdata for files with audio packets in header pages Fixes #259, #597 --- stb_vorbis.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index 0e7c7fa..ea01d09 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -3507,7 +3507,7 @@ static int vorbis_pump_first_frame(stb_vorbis *f) } #ifndef STB_VORBIS_NO_PUSHDATA_API -static int is_whole_packet_present(stb_vorbis *f, int end_page) +static int is_whole_packet_present(stb_vorbis *f) { // make sure that we have the packet available before continuing... // this requires a full ogg parse, but we know we can fetch from f->stream @@ -3527,8 +3527,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page) break; } // either this continues, or it ends it... - if (end_page) - if (s < f->segment_count-1) return error(f, VORBIS_invalid_stream); if (s == f->segment_count) s = -1; // set 'crosses page' flag if (p > f->stream_end) return error(f, VORBIS_need_more_data); @@ -3561,8 +3559,6 @@ static int is_whole_packet_present(stb_vorbis *f, int end_page) if (q[s] < 255) break; } - if (end_page) - if (s < n-1) return error(f, VORBIS_invalid_stream); if (s == n) s = -1; // set 'crosses page' flag if (p > f->stream_end) return error(f, VORBIS_need_more_data); @@ -3648,7 +3644,7 @@ static int start_decoder(vorb *f) #ifndef STB_VORBIS_NO_PUSHDATA_API if (IS_PUSH_MODE(f)) { - if (!is_whole_packet_present(f, TRUE)) { + if (!is_whole_packet_present(f)) { // convert error in ogg header to write type if (f->error == VORBIS_invalid_stream) f->error = VORBIS_invalid_setup; @@ -4402,7 +4398,7 @@ int stb_vorbis_decode_frame_pushdata( f->error = VORBIS__no_error; // check that we have the entire packet in memory - if (!is_whole_packet_present(f, FALSE)) { + if (!is_whole_packet_present(f)) { *samples = 0; return 0; } From c3298670d028a7f4381ad5f4a9f8d27266a9422b Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Mon, 21 Oct 2019 15:37:04 +1100 Subject: [PATCH 5/6] stb_vorbis: fix a couple asserts that fail on invalid files --- stb_vorbis.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index ea01d09..1c8d2ac 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -4664,8 +4664,11 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) // starting from the start is handled differently if (last_sample_limit <= left.last_decoded_sample) { - if (stb_vorbis_seek_start(f)) + if (stb_vorbis_seek_start(f)) { + if (f->current_loc > sample_number) + return error(f, VORBIS_seek_failed); return 1; + } return 0; } @@ -4841,8 +4844,8 @@ int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) flush_packet(f); } } - // the next frame will start with the sample - assert(f->current_loc == sample_number); + // the next frame should start with the sample + if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed); return 1; } From da79a214efa2a8c94ff76aa60f678be12f9dfa3e Mon Sep 17 00:00:00 2001 From: Dougall Johnson Date: Mon, 21 Oct 2019 20:39:31 +1100 Subject: [PATCH 6/6] stb_vorbis: improve fix for theoretical seek performance problem --- stb_vorbis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_vorbis.c b/stb_vorbis.c index 1c8d2ac..65fc9b7 100644 --- a/stb_vorbis.c +++ b/stb_vorbis.c @@ -4721,7 +4721,7 @@ static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) // if we've just found the last page again then we're in a tricky file, // and we're close enough (if it wasn't an interpolation probe). if (mid.page_start == right.page_start) { - if (probe >= 2) + if (probe >= 2 || delta <= 65536) break; } else { if (last_sample_limit < mid.last_decoded_sample)