OPtimized case of seeking within a single link; reset decode state
authorMonty <xiphmont@xiph.org>
Tue, 4 Mar 2003 21:22:11 +0000 (21:22 +0000)
committerMonty <xiphmont@xiph.org>
Tue, 4 Mar 2003 21:22:11 +0000 (21:22 +0000)
without dumping decode setup.  Roughly 5-10x faster this way.

Raft of small vorbisfile seek fixes (nearly all to do with exact
positioning around stream boundaries).

svn path=/trunk/vorbis/; revision=4404

lib/block.c
lib/psytune.c
lib/vorbisfile.c
lib/window.c
lib/window.h

index e239e2d..3b1b162 100644 (file)
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: PCM data vector blocking, windowing and dis/reassembly
- last mod: $Id: block.c,v 1.70 2003/03/02 21:32:00 xiphmont Exp $
+ last mod: $Id: block.c,v 1.71 2003/03/04 21:22:11 xiphmont Exp $
 
  Handle windowing, overlap-add, etc of the PCM vectors.  This is made
  more amusing by Vorbis' current two allowed block sizes.
@@ -186,8 +186,8 @@ static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){
   mdct_init(b->transform[1][0],ci->blocksizes[1]);
 
   /* Vorbis I uses only window type 0 */
-  b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
-  b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
+  b->window[0]=_vorbis_window_create(0,ci->blocksizes[0]/2);
+  b->window[1]=_vorbis_window_create(0,ci->blocksizes[1]/2);
 
   if(encp){ /* encode/decode differ here */
 
@@ -637,17 +637,34 @@ int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){
   return(1);
 }
 
-int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
-  _vds_shared_init(v,vi,0);
+int vorbis_synthesis_restart(vorbis_dsp_state *v){
+  vorbis_info *vi=v->vi;
+  codec_setup_info *ci;
+
+  if(!v->backend_state)return -1;
+  if(!vi)return -1;
+  ci=vi->codec_setup;
+  if(!ci)return -1;
 
+  v->centerW=ci->blocksizes[1]/2;
+  v->pcm_current=v->centerW;
+  
   v->pcm_returned=-1;
   v->granulepos=-1;
   v->sequence=-1;
+  v->eofflag=0;
   ((private_state *)(v->backend_state))->sample_count=-1;
 
   return(0);
 }
 
+int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+  _vds_shared_init(v,vi,0);
+  vorbis_synthesis_restart(v);
+
+  return(0);
+}
+
 /* Unlike in analysis, the window is only partially applied for each
    block.  The time domain envelope is not yet handled at the point of
    calling (as it relies on the previous block). */
index 6e5584f..7f2b553 100644 (file)
@@ -12,7 +12,7 @@
 
  function: simple utility that runs audio through the psychoacoustics
            without encoding
- last mod: $Id: psytune.c,v 1.19 2002/01/22 08:06:07 xiphmont Exp $
+ last mod: $Id: psytune.c,v 1.20 2003/03/04 21:22:11 xiphmont Exp $
 
  ********************************************************************/
 
@@ -280,7 +280,7 @@ int main(int argc,char *argv[]){
   flr[1]=_ogg_calloc(framesize/2,sizeof(float));
   buffer=_ogg_malloc(framesize*4);
   buffer2=buffer+framesize*2;
-  window=_vorbis_window(0,framesize,framesize/2,framesize/2);
+  window=_vorbis_window_create(0,framesize,framesize/2,framesize/2);
   mdct_init(&m_look,framesize);
   drft_init(&f_look,framesize);
   _vp_psy_init(&p_look,&_psy_set0,&_psy_set0G,framesize/2,44100);
index 846c4d4..0eacd83 100644 (file)
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id: vorbisfile.c,v 1.66 2003/03/02 21:32:00 xiphmont Exp $
+ last mod: $Id: vorbisfile.c,v 1.67 2003/03/04 21:22:11 xiphmont Exp $
 
  ********************************************************************/
 
@@ -444,6 +444,14 @@ static void _decode_clear(OggVorbis_File *vf){
   vf->samptrack=0.f;
 }
 
+/* restart the decoder, but don't clear out machine init */
+static void _decode_restart(OggVorbis_File *vf){
+  vorbis_synthesis_restart(&vf->vd);
+  vf->bittrack=0.f;
+  vf->samptrack=0.f;
+}
+
+
 /* fetch and process a packet.  Handles the case where we're at a
    bitstream boundary and dumps the decoding machine.  If the decoding
    machine is unloaded, it loads it.  It also keeps pcm_offset up to
@@ -540,17 +548,22 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
     }
 
     if(vf->ready_state>=OPENED){
+      int ret;
       if(!readp)return(0);
-      if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* eof. 
-                                                       leave unitialized */
-      /* bitrate tracking; add the header's bytes here, the body bytes
-        are done by packet above */
+      if((ret=_get_next_page(vf,&og,-1))<0){
+       return(OV_EOF); /* eof. 
+                          leave unitialized */
+      }
+
+       /* bitrate tracking; add the header's bytes here, the body bytes
+          are done by packet above */
       vf->bittrack+=og.header_len*8;
       
       /* has our decoding just traversed a bitstream boundary? */
       if(vf->ready_state==INITSET){
        if(vf->current_serialno!=ogg_page_serialno(&og)){
-         if(!spanp)return(OV_EOF);
+         if(!spanp)
+           return(OV_EOF);
 
          _decode_clear(vf);
          
@@ -908,6 +921,8 @@ double ov_time_total(OggVorbis_File *vf,int i){
 
 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
   ogg_stream_state work_os;
+  int i;
+  ogg_int64_t count=0;
 
   if(vf->ready_state<OPENED)return(OV_EINVAL);
   if(!vf->seekable)
@@ -915,9 +930,15 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
 
   if(pos<0 || pos>vf->end)return(OV_EINVAL);
 
-  /* clear out decoding machine state */
+  /* don't yet clear out decoding machine (if it's initialized), in
+     the case we're in the same link.  Restart the decode lapping, and
+     let _fetch_and_process_packet deal with a potential bitstream
+     boundary */
   vf->pcm_offset=-1;
-  _decode_clear(vf);
+  ogg_stream_reset_serialno(&vf->os,
+                           vf->current_serialno); /* must set serialno */
+  _decode_restart(vf);
+  //_decode_clear(vf);
   
   _seek_helper(vf,pos);
 
@@ -944,17 +965,25 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
     int thisblock;
     int eosflag;
 
-    ogg_stream_init(&work_os,-1); /* get the memory ready */
+    ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
+    ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
+                                   return from not necessarily
+                                   starting from the beginning */
 
     while(1){
-      if(vf->ready_state==STREAMSET){
+      if(vf->ready_state>=STREAMSET){
        /* snarf/scan a packet if we can */
        int result=ogg_stream_packetout(&work_os,&op);
       
        if(result>0){
 
-         if(vf->vi[vf->current_link].codec_setup)
+         if(vf->vi[vf->current_link].codec_setup){
            thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
+           if(thisblock<0){
+             ogg_stream_packetout(&vf->os,NULL);
+             continue;
+           }
+         }
          if(eosflag)
            ogg_stream_packetout(&vf->os,NULL);
          else
@@ -987,11 +1016,11 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
       }
       
       /* has our decoding just traversed a bitstream boundary? */
-      if(vf->ready_state==STREAMSET)
+      if(vf->ready_state>=STREAMSET)
        if(vf->current_serialno!=ogg_page_serialno(&og)){
-       _decode_clear(vf); /* clear out stream state */
-       ogg_stream_clear(&work_os);
-      }
+         _decode_clear(vf); /* clear out stream state */
+         ogg_stream_clear(&work_os);
+       }
 
       if(vf->ready_state<STREAMSET){
        int link;
@@ -1127,17 +1156,26 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
     {
       ogg_page og;
       ogg_packet op;
-      /* clear out decoding machine state */
-      _decode_clear(vf);  
+      
       /* seek */
       _seek_helper(vf,best);
+      vf->pcm_offset=-1;
       
       if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* shouldn't happen */
-      vf->current_serialno=ogg_page_serialno(&og);
-      vf->current_link=link;
       
+      if(link!=vf->current_link){
+       /* Different link; dump entire decode machine */
+       _decode_clear(vf);  
+       
+       vf->current_link=link;
+       vf->current_serialno=ogg_page_serialno(&og);
+       vf->ready_state=STREAMSET;
+       
+      }else{
+       _decode_restart(vf);  
+      }
+
       ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
-      vf->ready_state=STREAMSET;
       ogg_stream_pagein(&vf->os,&og);
 
       /* pull out all but last packet; the one with granulepos */
@@ -1148,10 +1186,10 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
              preceeding page. Keep fetching previous pages until we
              get one with a granulepos or without the 'continued' flag
              set.  Then just use raw_seek for simplicity. */
-
-         _decode_clear(vf);  
+         
+         //_decode_restart(vf);  
          _seek_helper(vf,best);
-
+         
          while(1){
            result=_get_prev_page(vf,&og);
            if(result<0) goto seek_error;
@@ -1163,9 +1201,9 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
          }
        }
        if(result<0){
-      result = OV_EBADPACKET; 
-      goto seek_error;
-    }
+         result = OV_EBADPACKET; 
+         goto seek_error;
+       }
        if(op.granulepos!=-1){
          vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
          if(vf->pcm_offset<0)vf->pcm_offset=0;
@@ -1210,7 +1248,10 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
     int ret=ogg_stream_packetpeek(&vf->os,&op);
     if(ret>0){
       thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
-      if(thisblock<0)thisblock=0; /* non audio packet */
+      if(thisblock<0){
+       ogg_stream_packetout(&vf->os,NULL);
+       continue; /* non audio packet */
+      }
       if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
       
       if(vf->pcm_offset+((thisblock+
@@ -1469,8 +1510,10 @@ long ov_read(OggVorbis_File *vf,char *buffer,int length,
     /* suck in another packet */
     {
       int ret=_fetch_and_process_packet(vf,NULL,1,1);
-      if(ret==OV_EOF)return(0);
-      if(ret<=0)return(ret);
+      if(ret==OV_EOF)
+       return(0);
+      if(ret<=0)
+       return(ret);
     }
 
   }
index e952d9a..cdb359a 100644 (file)
@@ -11,7 +11,7 @@
  ********************************************************************
 
  function: window functions
- last mod: $Id: window.c,v 1.19 2003/03/02 11:45:17 xiphmont Exp $
+ last mod: $Id: window.c,v 1.20 2003/03/04 21:22:11 xiphmont Exp $
 
  ********************************************************************/
 
@@ -20,7 +20,7 @@
 #include "os.h"
 #include "misc.h"
 
-float *_vorbis_window(int type, int left){
+float *_vorbis_window_create(int type, int left){
   float *ret=_ogg_calloc(left,sizeof(*ret));
   int i;
 
index 98ebdf4..b6e75eb 100644 (file)
  ********************************************************************
 
  function: window functions
- last mod: $Id: window.h,v 1.10 2002/01/22 11:59:00 xiphmont Exp $
+ last mod: $Id: window.h,v 1.11 2003/03/04 21:22:11 xiphmont Exp $
 
  ********************************************************************/
 
 #ifndef _V_WINDOW_
 #define _V_WINDOW_
 
-extern float *_vorbis_window(int type,int left);
+extern float *_vorbis_window_create(int type,int left);
 extern void _vorbis_apply_window(float *d,float *window[2],long *blocksizes,
                                 int lW,int W,int nW);