shithub: opusfile

Download patch

ref: 007ec4e4611e7636a72830b8e927c8d803d69ece
parent: 9ed9fa49fb919ce97cc035bffe42290876b3f999
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Sun Sep 23 04:42:58 EDT 2012

More link enumeration improvements.

1) Remember the granule position of the last page we've seen from
    the current link and save the first page of the next link as
    long as we're scanning forward.
   This knocks almost 10% off the number of seeks for large links.
   For smaller links the improvement is much larger.
2) Only use pairs of close-by serial numbers to estimate link
    start locations (assuming they're above our start threshold).
   This gives a minor (<2%) improvement, which might be in the
    noise, but as it doesn't appear to hurt and is faster, might as
    well.
3) Eliminate a redundant check in op_pcm_seek_page_impl().

--- a/src/opusfile.c
+++ b/src/opusfile.c
@@ -934,7 +934,7 @@
     }
     offset1=_sr[sri].offset;
     serialno1=_sr[sri].serialno;
-    for(srj=0;srj<sri;srj++){
+    for(srj=sri;srj-->0;){
       ogg_int64_t  gp2;
       opus_int64   offset2;
       opus_int64   num;
@@ -956,6 +956,7 @@
       offset2-=op_rescale64(gp2,den,num);
       if(offset2<_searched)continue;
       bisect=OP_MIN(bisect,offset2);
+      break;
     }
   }
   return bisect>=_end_searched?-1:bisect;
@@ -989,12 +990,13 @@
      improve the lower bound on the location where the next link starts.*/
   nsr=1;
   for(;;){
-    opus_int64 data_offset;
-    opus_int64 end_searched;
-    opus_int64 bisect;
-    opus_int64 next;
-    opus_int64 last;
-    int        sri;
+    opus_int64  data_offset;
+    opus_int64  end_searched;
+    opus_int64  bisect;
+    opus_int64  next;
+    opus_int64  last;
+    ogg_int64_t end_gp;
+    int         sri;
     serialnos=*_serialnos;
     nserialnos=*_nserialnos;
     if(OP_UNLIKELY(nlinks>=clinks)){
@@ -1018,8 +1020,13 @@
     if(sri<=0)break;
     /*Last page wasn't found.
       We have at least one more link.*/
+    last=-1;
     end_searched=next=_sr[sri-1].search_start;
-    if(sri<nsr)_searched=_sr[sri].offset+_sr[sri].size;
+    end_gp=-1;
+    if(sri<nsr){
+      _searched=_sr[sri].offset+_sr[sri].size;
+      if(_sr[sri].serialno==links[nlinks-1].serialno)end_gp=_sr[sri].gp;
+    }
     nsr=sri;
     bisect=-1;
     /*If we've already found the end of at least one link, try to pick the
@@ -1044,6 +1051,7 @@
     while(_searched<end_searched){
       if(bisect==-1)bisect=_searched+(end_searched-_searched>>1);
       if(OP_UNLIKELY(bisect-_searched<OP_CHUNK_SIZE))bisect=_searched;
+      else end_gp=-1;
       ret=op_seek_helper(_of,bisect);
       if(OP_UNLIKELY(ret<0))return ret;
       last=op_get_next_page(_of,&og,_of->end);
@@ -1051,6 +1059,7 @@
       if(OP_UNLIKELY(last<0))return OP_EBADLINK;
       OP_ASSERT(nsr<_csr);
       _sr[nsr].serialno=ogg_page_serialno(&og);
+      _sr[nsr].gp=ogg_page_granulepos(&og);
       if(!op_lookup_serialno(_sr[nsr].serialno,serialnos,nserialnos)){
         end_searched=bisect;
         next=last;
@@ -1061,11 +1070,13 @@
           OP_ASSERT(_of->offset-last>=0);
           OP_ASSERT(_of->offset-last<=OP_PAGE_SIZE);
           _sr[nsr].size=(opus_int32)(_of->offset-last);
-          _sr[nsr].gp=ogg_page_granulepos(&og);
           nsr++;
         }
       }
-      else _searched=_of->offset;
+      else{
+        _searched=_of->offset;
+        if(_sr[nsr].serialno==links[nlinks-1].serialno)end_gp=_sr[nsr].gp;
+      }
       bisect=op_predict_link_start(_sr,nsr,_searched,end_searched);
     }
     /*Bisection point found.
@@ -1074,17 +1085,20 @@
        empty.*/
     if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){
       ret=op_find_final_pcm_offset(_of,serialnos,nserialnos,
-       links+nlinks-1,next,0,-1,&total_duration);
+       links+nlinks-1,next,links[nlinks-1].serialno,end_gp,&total_duration);
       if(OP_UNLIKELY(ret<0))return ret;
+      if(end_gp==-1)last=-1;
     }
     /*Restore the cursor position after the seek.
       This only performs an actual seek if the last page in the link did not
        belong to our Opus stream.
       TODO: Read forward instead, or let seek implementations do that?*/
-    ret=op_seek_helper(_of,next);
-    if(OP_UNLIKELY(ret<0))return ret;
+    if(last!=next){
+      ret=op_seek_helper(_of,next);
+      if(OP_UNLIKELY(ret<0))return ret;
+    }
     ret=op_fetch_headers(_of,&links[nlinks].head,&links[nlinks].tags,
-     _serialnos,_nserialnos,_cserialnos,NULL);
+     _serialnos,_nserialnos,_cserialnos,last!=next?NULL:&og);
     if(OP_UNLIKELY(ret<0))return ret;
     links[nlinks].offset=next;
     links[nlinks].data_offset=_of->offset;
@@ -2027,10 +2041,8 @@
         if(bisect<=begin+1)end=begin;
         else{
           bisect=OP_MAX(bisect-OP_CHUNK_SIZE,begin+1);
-          if(bisect!=_of->offset){
-            ret=op_seek_helper(_of,bisect);
-            if(OP_UNLIKELY(ret<0))return ret;
-          }
+          ret=op_seek_helper(_of,bisect);
+          if(OP_UNLIKELY(ret<0))return ret;
         }
       }
       else{