ref: 9ed9fa49fb919ce97cc035bffe42290876b3f999
parent: 2592d24f9dc784aa4f47033e066a0554e7cf9d5e
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Sat Sep 22 21:45:33 EDT 2012
Further reduce seeks per bisection search. If we encounter the first page after the target while scanning forward, we no longer seek back and read it again after we exit the bisection search, but just hold on to the copy we already have.
--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -1626,7 +1626,7 @@
0) Need more data (only if _readp==0).
1) Got at least one audio data packet.*/
static int op_fetch_and_process_page(OggOpusFile *_of,
- int _readp,int _spanp,int _ignore_holes){
+ ogg_page *_og,opus_int64 _page_pos,int _readp,int _spanp,int _ignore_holes){
OggOpusLink *links;
ogg_uint32_t cur_serialno;
int seekable;
@@ -1644,8 +1644,7 @@
cur_serialno=links[cur_link].serialno;
/*Handle one page.*/
for(;;){
- ogg_page og;
- opus_int64 page_pos;
+ ogg_page og;
OP_ASSERT(_of->ready_state>=OP_OPENED);
/*This loop is not strictly necessary, but there's no sense in doing the
extra checks of the larger loop for the common case in a multiplexed
@@ -1652,10 +1651,15 @@
bistream where the page is simply part of a different logical
bitstream.*/
do{
+ /*If we were given a page to use, use it.*/
+ if(_og!=NULL){
+ *&og=*_og;
+ _og=NULL;
+ }
/*Keep reading until we get a page with the correct serialno.*/
- page_pos=op_get_next_page(_of,&og,_of->end);
+ else _page_pos=op_get_next_page(_of,&og,_of->end);
/*EOF: Leave uninitialized.*/
- if(page_pos<0)return OP_EOF;
+ if(_page_pos<0)return OP_EOF;
if(OP_LIKELY(_of->ready_state>=OP_STREAMSET)){
if(cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){
/*Two possibilities:
@@ -1700,7 +1704,7 @@
_of->ready_state=OP_STREAMSET;
/*If we're at the start of this link, initialize the granule position
and pre-skip tracking.*/
- if(page_pos<=links[cur_link].data_offset){
+ if(_page_pos<=links[cur_link].data_offset){
_of->prev_packet_gp=links[cur_link].pcm_start;
_of->cur_discard_count=links[cur_link].head.pre_skip;
/*Ignore a hole at the start of a new link (this is common for
@@ -1900,7 +1904,7 @@
_of->samples_tracked=0;
ret=op_seek_helper(_of,_pos);
if(OP_UNLIKELY(ret<0))return OP_EREAD;
- ret=op_fetch_and_process_page(_of,1,1,1);
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,1,1);
/*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized.
Instead, jump to the end.*/
if(ret==OP_EOF){
@@ -1974,7 +1978,7 @@
opus_int64 begin;
opus_int64 end;
opus_int64 best;
- opus_int64 llret;
+ opus_int64 page_offset;
int ret;
_of->bytes_tracked=0;
_of->samples_tracked=0;
@@ -1996,7 +2000,7 @@
ret=op_granpos_add(&pcm_pre_skip,pcm_start,pre_skip);
OP_ASSERT(!ret);
end=op_granpos_cmp(_target_gp,pcm_pre_skip)<0?begin:link->end_offset;
- llret=OP_FALSE;
+ page_offset=-1;
while(begin<end){
opus_int64 bisect;
if(end-begin<OP_CHUNK_SIZE)bisect=begin;
@@ -2010,18 +2014,23 @@
bisect=begin+op_rescale64(diff,diff2,end-begin)-OP_CHUNK_SIZE;
if(bisect-OP_CHUNK_SIZE<begin)bisect=begin;
}
- ret=op_seek_helper(_of,bisect);
- if(OP_UNLIKELY(ret<0))return ret;
+ if(bisect!=_of->offset){
+ page_offset=-1;
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
while(begin<end){
- llret=op_get_next_page(_of,&og,end-_of->offset);
- if(llret==OP_EREAD)return OP_EBADLINK;
- if(llret<0){
+ page_offset=op_get_next_page(_of,&og,end-_of->offset);
+ if(page_offset==OP_EREAD)return OP_EBADLINK;
+ if(page_offset<0){
/*Found it.*/
if(bisect<=begin+1)end=begin;
else{
bisect=OP_MAX(bisect-OP_CHUNK_SIZE,begin+1);
- ret=op_seek_helper(_of,bisect);
- if(OP_UNLIKELY(ret<0))return ret;
+ if(bisect!=_of->offset){
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
}
}
else{
@@ -2054,10 +2063,13 @@
/*We're pretty close.
We'd be stuck in an endless loop otherwise.*/
if(end==_of->offset){
- end=llret;
+ end=page_offset;
bisect=OP_MAX(bisect-OP_CHUNK_SIZE,begin+1);
- ret=op_seek_helper(_of,bisect);
- if(OP_UNLIKELY(ret<0))return ret;
+ if(bisect!=_of->offset){
+ page_offset=-1;
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
}
else{
end=bisect;
@@ -2076,8 +2088,11 @@
This is an easier case than op_raw_seek(), as we don't need to keep any
packets from the page we found.*/
/*Seek, if necessary.*/
- ret=op_seek_helper(_of,best);
- if(OP_UNLIKELY(ret<0))return ret;
+ if(best!=page_offset){
+ page_offset=-1;
+ ret=op_seek_helper(_of,best);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
/*By default, discard 80 ms of data after a seek, unless we seek
into the pre-skip region.*/
cur_discard_count=80*48;
@@ -2095,7 +2110,7 @@
_of->prev_packet_gp=best_gp;
_of->cur_discard_count=cur_discard_count;
ogg_stream_reset_serialno(&_of->os,serialno);
- ret=op_fetch_and_process_page(_of,1,0,1);
+ ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,1,0,1);
if(OP_UNLIKELY(ret<=0))return OP_EBADLINK;
/*Verify result.*/
if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){
@@ -2160,7 +2175,7 @@
if(op_pos<op_count)break;
/*We skipped all the packets on this page.
Fetch another.*/
- ret=op_fetch_and_process_page(_of,1,0,1);
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,0,1);
if(OP_UNLIKELY(ret<=0))return OP_EBADLINK;
}
ret=op_granpos_diff(&diff,prev_packet_gp,pcm_start);
@@ -2373,7 +2388,7 @@
}
}
/*Suck in another page.*/
- ret=op_fetch_and_process_page(_of,1,1,0);
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,1,0);
if(OP_UNLIKELY(ret==OP_EOF)){
if(_li!=NULL)*_li=_of->cur_link;
return 0;