[xiph-commits] r15926 - trunk/vorbis/lib

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Thu Apr 9 00:23:29 PDT 2009


Author: xiphmont
Date: 2009-04-09 00:23:28 -0700 (Thu, 09 Apr 2009)
New Revision: 15926

Modified:
   trunk/vorbis/lib/vorbisfile.c
Log:
Ongoing open refactoring to eliminate superfluous seeks and reads
during stream open

Move initial serial number cataloguing in each link to be part of the
inline header fetch process.



Modified: trunk/vorbis/lib/vorbisfile.c
===================================================================
--- trunk/vorbis/lib/vorbisfile.c	2009-04-09 05:52:38 UTC (rev 15925)
+++ trunk/vorbis/lib/vorbisfile.c	2009-04-09 07:23:28 UTC (rev 15926)
@@ -301,7 +301,8 @@
 /* uses the local ogg_stream storage in vf; this is important for
    non-streaming input sources */
 static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
-			  long *serialno,ogg_page *og_ptr){
+			  long *serialno, long **serialno_list, int *serialno_n,
+                          ogg_page *og_ptr){
   ogg_page og;
   ogg_packet op;
   int i,ret;
@@ -317,87 +318,116 @@
   vorbis_info_init(vi);
   vorbis_comment_init(vc);
 
-  /* extract the first set of vorbis headers we see in the headerset */
+  /* extract the serialnos of all BOS pages + the first set of vorbis
+     headers we see in the link */
 
-  while(1){
-  
-    /* if we're past the ID headers, we won't be finding a Vorbis
-       stream in this link */
-    if(!ogg_page_bos(og_ptr)){
-      ret = OV_ENOTVORBIS;
-      goto bail_header;
+  while(ogg_page_bos(og_ptr)){
+    if(serialno_list){
+      if(_lookup_serialno(og_ptr,*serialno_list,*serialno_n)){
+        /* a dupe serialnumber in an initial header packet set == invalid stream */
+        if(*serialno_list)_ogg_free(*serialno_list);
+        *serialno_list=0;
+        *serialno_n=0;
+        ret=OV_EBADHEADER;
+        goto bail_header;
+      }
+      
+      _add_serialno(og_ptr,serialno_list,serialno_n);
     }
 
-    /* prospective stream setup; we need a stream to get packets */
-    ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
-    ogg_stream_pagein(&vf->os,og_ptr);
+    if(vf->ready_state<STREAMSET){
+      /* we don't have a vorbis stream in this link yet, so begin
+         prospective stream setup. We need a stream to get packets */
+      ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
+      ogg_stream_pagein(&vf->os,og_ptr);
 
-    if(ogg_stream_packetout(&vf->os,&op) > 0 &&
-       vorbis_synthesis_idheader(&op)){
-
-      /* continue Vorbis header load; past this point, any error will
-	 render this link useless (we won't continue looking for more
-	 Vorbis streams */
-      if(serialno)*serialno=vf->os.serialno;
-      vf->ready_state=STREAMSET;
-      if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
-	goto bail_header;
-
-      i=0;
-      while(i<2){ /* get a page loop */
-	
-	while(i<2){ /* get a packet loop */
-
-	  int result=ogg_stream_packetout(&vf->os,&op);
-	  if(result==0)break;
-	  if(result==-1){
-	    ret=OV_EBADHEADER;
-	    goto bail_header;
-	  }
-	
-	  if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
-	    goto bail_header;
-
-	  i++;
-	}
-
-	while(i<2){
-	  if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
-	    ret=OV_EBADHEADER;
-	    goto bail_header;
-	  }
-
-	  /* if this page belongs to the correct stream, go parse it */
-	  if(vf->os.serialno == ogg_page_serialno(og_ptr)){
-	    ogg_stream_pagein(&vf->os,og_ptr);
-	    break;
-	  }
-
-	  /* if we never see the final vorbis headers before the link
-	     ends, abort */
-	  if(ogg_page_bos(og_ptr)){
-	    if(allbos){
-	      ret = OV_EBADHEADER;
-	      goto bail_header;
-	    }else
-	      allbos=1;
-	  }
-
-	  /* otherwise, keep looking */
-	}
+      if(ogg_stream_packetout(&vf->os,&op) > 0 &&
+         vorbis_synthesis_idheader(&op)){
+        /* vorbis header; continue setup */
+        if(serialno)*serialno=vf->os.serialno;
+        vf->ready_state=STREAMSET;
+        if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
+          ret=OV_EBADHEADER;
+          goto bail_header;
+        }
       }
-
-      return 0; 
     }
 
-    /* this wasn't vorbis, get next page, try again */
+    /* get next page */
     {
       ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
-      if(llret==OV_EREAD)return(OV_EREAD);
-      if(llret<0)return(OV_ENOTVORBIS);
+      if(llret==OV_EREAD){
+        ret=OV_EREAD;
+        goto bail_header;
+      }
+      if(llret<0){
+        ret=OV_ENOTVORBIS;
+        goto bail_header;
+      }
+
+      /* if this page also belongs to our vorbis stream, submit it and break */
+      if(vf->ready_state==STREAMSET && 
+         vf->os.serialno == ogg_page_serialno(og_ptr)){
+        ogg_stream_pagein(&vf->os,og_ptr);
+        break;
+      } 
     } 
   }
 
+  if(vf->ready_state!=STREAMSET){
+    ret = OV_ENOTVORBIS;
+    goto bail_header;
+  }
+
+  while(1){
+  
+    i=0;
+    while(i<2){ /* get a page loop */
+      
+      while(i<2){ /* get a packet loop */
+        
+        int result=ogg_stream_packetout(&vf->os,&op);
+        if(result==0)break;
+        if(result==-1){
+          ret=OV_EBADHEADER;
+          goto bail_header;
+        }
+	
+        if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
+          goto bail_header;
+        
+        i++;
+      }
+      
+      while(i<2){
+        if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
+          ret=OV_EBADHEADER;
+          goto bail_header;
+        }
+        
+        /* if this page belongs to the correct stream, go parse it */
+        if(vf->os.serialno == ogg_page_serialno(og_ptr)){
+          ogg_stream_pagein(&vf->os,og_ptr);
+          break;
+        }
+        
+        /* if we never see the final vorbis headers before the link
+           ends, abort */
+        if(ogg_page_bos(og_ptr)){
+          if(allbos){
+            ret = OV_EBADHEADER;
+            goto bail_header;
+          }else
+            allbos=1;
+        }
+        
+        /* otherwise, keep looking */
+      }
+    }
+    
+    return 0; 
+  }
+
  bail_header:
   vorbis_info_clear(vi);
   vorbis_comment_clear(vc);
@@ -420,6 +450,9 @@
   int i;
   ogg_int64_t ret;
 
+  /* release any overloaded vf->serialnos state */
+  if(vf->serialnos)_ogg_free(vf->serialnos);
+
   vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
   vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
   vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
@@ -443,7 +476,7 @@
       if(ret){
 	vf->dataoffsets[i]=-1;
       }else{
-	if(_fetch_headers(vf,vf->vi+i,vf->vc+i,vf->serialnos+i,NULL)<0){
+	if(_fetch_headers(vf,vf->vi+i,vf->vc+i,vf->serialnos+i,NULL,NULL,NULL)<0){
 	  vf->dataoffsets[i]=-1;
 	}else{
 	  vf->dataoffsets[i]=vf->offset;
@@ -550,9 +583,6 @@
 
 static int _open_seekable2(OggVorbis_File *vf){
   ogg_int64_t dataoffset=vf->offset,end;
-  long *serialno_list=NULL;
-  int serialnos=0;
-  int ret;
   ogg_page og;
 
   /* we're partially open and have a first link header state in
@@ -573,15 +603,8 @@
   end=_get_prev_page(vf,&og);
   if(end<0)return(end);
 
-  /* back to beginning, learn all serialnos of first link */
-  ret=_seek_helper(vf,0);
-  if(ret)return(ret);
-  ret=_get_serialnos(vf,&serialno_list,&serialnos);
-  if(ret)return(ret);
-
   /* now determine bitstream structure recursively */
-  if(_bisect_forward_serialno(vf,0,0,end+1,serialno_list,serialnos,0)<0)return(OV_EREAD);  
-  if(serialno_list)_ogg_free(serialno_list);
+  if(_bisect_forward_serialno(vf,0,0,end+1,vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);  
 
   /* the initial header memory is referenced by vf after; don't free it */
   _prefetch_all_headers(vf,dataoffset);
@@ -778,7 +801,7 @@
 	  /* we're streaming */
 	  /* fetch the three header packets, build the info struct */
 	  
-	  int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
+	  int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL,NULL,&og);
 	  if(ret)return(ret);
 	  vf->current_link++;
 	  link=0;
@@ -808,6 +831,8 @@
 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
 		     long ibytes, ov_callbacks callbacks){
   int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
+  long *serialno_list=NULL;
+  int serialno_list_size=0;
   int ret;
   
   memset(vf,0,sizeof(*vf));
@@ -819,8 +844,8 @@
 
   /* perhaps some data was previously read into a buffer for testing
      against other stream types.  Allow initialization from this
-     previously read data (as we may be reading from a non-seekable
-     stream) */
+     previously read data (especially as we may be reading from a
+     non-seekable stream) */
   if(initial){
     char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
     memcpy(buffer,initial,ibytes);
@@ -837,12 +862,25 @@
   vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
   ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
 
-  /* Try to fetch the headers, maintaining all the storage */
-  if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
+  /* Fetch all BOS pages, store the vorbis header and all seen serial
+     numbers, load subsequent vorbis setup headers */
+  if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,
+                         &serialno_list,&serialno_list_size,
+                         NULL))<0){
     vf->datasource=NULL;
     ov_clear(vf);
-  }else 
+  }else{
+    /* serial number list for first link needs to be held somewhere
+       for second stage of seekable stream open; this saves having to
+       seek/reread first link's serialnumber data then. */
+    vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
+    vf->serialnos[0]=vf->current_serialno;
+    vf->serialnos[1]=serialno_list_size;
+    memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
+
     vf->ready_state=PARTOPEN;
+  }
+  if(serialno_list)_ogg_free(serialno_list);
   return(ret);
 }
 



More information about the commits mailing list