shithub: opusfile

Download patch

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;