[xiph-cvs] cvs commit: Tremor Makefile.am bitwise.c block.c framing.c info.c ivorbiscodec.h ivorbisfile.h misc.h ogg.h synthesis.c vorbisfile.c

Monty xiphmont at xiph.org
Fri Mar 28 19:07:21 PST 2003



xiphmont    03/03/28 22:07:21

  Modified:    .        Makefile.am bitwise.c block.c framing.c info.c
                        ivorbiscodec.h ivorbisfile.h misc.h ogg.h
                        synthesis.c vorbisfile.c
  Log:
  Roll all recent optimizations and fixes to mainline vorbisfile into Tremor
  
  First mainline deployment of libogg 2 (embedded into Tremor)

Revision  Changes    Path
1.7       +1 -1      Tremor/Makefile.am

Index: Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/Tremor/Makefile.am,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Makefile.am	16 Oct 2002 09:07:00 -0000	1.6
+++ Makefile.am	29 Mar 2003 03:07:21 -0000	1.7
@@ -4,7 +4,7 @@
 
 lib_LTLIBRARIES = libvorbisidec.la
 
-libvorbisidec_la_SOURCES = mdct.c block.c window.c \
+libvorbisidec_la_SOURCES = mdct.c block.c window.c misc.c\
                         synthesis.c info.c \
                         floor1.c floor0.c vorbisfile.c \
                         res012.c mapping0.c registry.c codebook.c \

<p><p>1.4       +203 -50   Tremor/bitwise.c

Index: bitwise.c
===================================================================
RCS file: /usr/local/cvsroot/Tremor/bitwise.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- bitwise.c	20 Sep 2002 01:31:39 -0000	1.3
+++ bitwise.c	29 Mar 2003 03:07:21 -0000	1.4
@@ -22,8 +22,6 @@
 #include <stdlib.h>
 #include "ogg.h"
 
-#define BUFFER_INCREMENT 256
-
 static unsigned long mask[]=
 {0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
  0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
@@ -33,80 +31,235 @@
  0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
  0x3fffffff,0x7fffffff,0xffffffff };
 
-void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+/* mark read process as having run off the end */
+static void _adv_halt(oggpack_buffer *b){
+  b->headptr=b->head->buffer->data+b->head->begin+b->head->length;
+  b->headend=-1;
+  b->headbit=0;
+}
+
+/* spans forward, skipping as many bytes as headend is negative; if
+   headend is zero, simply finds next byte.  If we're up to the end
+   of the buffer, leaves headend at zero.  If we've read past the end,
+   halt the decode process. */
+static void _span(oggpack_buffer *b){
+  while(b->headend<1){
+    if(b->head->next){
+      b->count+=b->head->length;
+      b->head=b->head->next;
+      b->headptr=b->head->buffer->data+b->head->begin-b->headend; 
+      b->headend+=b->head->length;      
+    }else{
+      /* we've either met the end of decode, or gone past it. halt
+         only if we're past */
+      if(b->headend<0 || b->headbit)
+        /* read has fallen off the end */
+        _adv_halt(b);
+
+      break;
+    }
+  }
+}
+
+void oggpack_readinit(oggpack_buffer *b,ogg_reference *r){
   memset(b,0,sizeof(*b));
-  b->buffer=b->ptr=buf;
-  b->storage=bytes;
+
+  b->tail=b->head=r;
+  b->count=0;
+  b->headptr=b->head->buffer->data+b->head->begin;
+  b->headend=b->head->length;
+  _span(b);
 }
 
+#define _lookspan()   while(!end){\
+                        head=head->next;\
+                        if(!head) return -1;\
+                        ptr=head->buffer->data + head->begin;\
+                        end=head->length;\
+                      }
+
 /* Read in bits without advancing the bitptr; bits <= 32 */
 long oggpack_look(oggpack_buffer *b,int bits){
-  unsigned long ret;
   unsigned long m=mask[bits];
+  unsigned long ret;
 
-  bits+=b->endbit;
+  bits+=b->headbit;
 
-  if(b->endbyte+4>=b->storage){
-    /* not the main path */
-    if(b->endbyte*8+bits>b->storage*8)return(-1);
-  }
-  
-  ret=b->ptr[0]>>b->endbit;
-  if(bits>8){
-    ret|=b->ptr[1]<<(8-b->endbit);  
-    if(bits>16){
-      ret|=b->ptr[2]<<(16-b->endbit);  
-      if(bits>24){
-	ret|=b->ptr[3]<<(24-b->endbit);  
-	if(bits>32 && b->endbit)
-	  ret|=b->ptr[4]<<(32-b->endbit);
+  if(bits >= b->headend<<3){
+    int            end=b->headend;
+    unsigned char *ptr=b->headptr;
+    ogg_reference *head=b->head;
+
+    if(end<0)return -1;
+    
+    if(bits){
+      _lookspan();
+      ret=*ptr++>>b->headbit;
+      if(bits>8){
+        --end;
+        _lookspan();
+        ret|=*ptr++<<(8-b->headbit);  
+        if(bits>16){
+          --end;
+          _lookspan();
+          ret|=*ptr++<<(16-b->headbit);  
+          if(bits>24){
+            --end;
+            _lookspan();
+            ret|=*ptr++<<(24-b->headbit);  
+            if(bits>32 && b->headbit){
+              --end;
+              _lookspan();
+              ret|=*ptr<<(32-b->headbit);
+            }
+          }
+        }
+      }
+    }
+
+  }else{
+
+    /* make this a switch jump-table */
+    ret=b->headptr[0]>>b->headbit;
+    if(bits>8){
+      ret|=b->headptr[1]<<(8-b->headbit);  
+      if(bits>16){
+        ret|=b->headptr[2]<<(16-b->headbit);  
+        if(bits>24){
+          ret|=b->headptr[3]<<(24-b->headbit);  
+          if(bits>32 && b->headbit)
+            ret|=b->headptr[4]<<(32-b->headbit);
+        }
       }
     }
   }
-  return(m&ret);
+
+  ret&=m;
+  return ret;
 }
 
+/* limited to 32 at a time */
 void oggpack_adv(oggpack_buffer *b,int bits){
-  bits+=b->endbit;
-  b->ptr+=bits/8;
-  b->endbyte+=bits/8;
-  b->endbit=bits&7;
+  bits+=b->headbit;
+  b->headbit=bits&7;
+  b->headptr+=bits/8;
+  if((b->headend-=bits/8)<1)_span(b);
+}
+
+/* spans forward and finds next byte.  Never halts */
+static void _span_one(oggpack_buffer *b){
+  while(b->headend<1){
+    if(b->head->next){
+      b->count+=b->head->length;
+      b->head=b->head->next;
+      b->headptr=b->head->buffer->data+b->head->begin; 
+      b->headend=b->head->length;      
+    }else
+      break;
+  }
+}
+
+static int _halt_one(oggpack_buffer *b){
+  if(b->headend<1){
+    _adv_halt(b);
+    return -1;
+  }
+  return 0;
+}
+
+int oggpack_eop(oggpack_buffer *b){
+  if(b->headend<0)return -1;
+  return 0;
 }
 
 /* bits <= 32 */
 long oggpack_read(oggpack_buffer *b,int bits){
-  unsigned long ret;
   unsigned long m=mask[bits];
+  ogg_uint32_t ret;
 
-  bits+=b->endbit;
+  bits+=b->headbit;
 
-  if(b->endbyte+4>=b->storage){
-    /* not the main path */
-    ret=-1UL;
-    if(b->endbyte*8+bits>b->storage*8)goto overflow;
-  }
+  if(bits >= b->headend<<3){
+
+    if(b->headend<0)return -1;
+    
+    if(bits){
+      if (_halt_one(b)) return -1;
+      ret=*b->headptr>>b->headbit;
+      
+      if(bits>=8){
+        ++b->headptr;
+        --b->headend;
+        _span_one(b);
+        if(bits>8){
+          if (_halt_one(b)) return -1;
+          ret|=*b->headptr<<(8-b->headbit);   
+          
+          if(bits>=16){
+            ++b->headptr;
+            --b->headend;
+            _span_one(b);
+            if(bits>16){
+              if (_halt_one(b)) return -1;
+              ret|=*b->headptr<<(16-b->headbit);  
+              
+              if(bits>=24){
+                ++b->headptr;
+                --b->headend;
+                _span_one(b);
+                if(bits>24){
+                  if (_halt_one(b)) return -1;
+                  ret|=*b->headptr<<(24-b->headbit);
+                  
+                  if(bits>=32){
+                    ++b->headptr;
+                    --b->headend;
+                    _span_one(b);
+                    if(bits>32){
+                      if (_halt_one(b)) return -1;
+                      if(b->headbit)ret|=*b->headptr<<(32-b->headbit);
+                      
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }else{
   
-  ret=b->ptr[0]>>b->endbit;
-  if(bits>8){
-    ret|=b->ptr[1]<<(8-b->endbit);  
-    if(bits>16){
-      ret|=b->ptr[2]<<(16-b->endbit);  
-      if(bits>24){
-	ret|=b->ptr[3]<<(24-b->endbit);  
-	if(bits>32 && b->endbit){
-	  ret|=b->ptr[4]<<(32-b->endbit);
-	}
+    ret=b->headptr[0]>>b->headbit;
+    if(bits>8){
+      ret|=b->headptr[1]<<(8-b->headbit);  
+      if(bits>16){
+        ret|=b->headptr[2]<<(16-b->headbit);  
+        if(bits>24){
+          ret|=b->headptr[3]<<(24-b->headbit);  
+          if(bits>32 && b->headbit){
+            ret|=b->headptr[4]<<(32-b->headbit);
+          }
+        }
       }
     }
+    
+    b->headptr+=bits/8;
+    b->headend-=bits/8;
   }
+
   ret&=m;
-  
- overflow:
+  b->headbit=bits&7;   
+  return ret;
+}
+
+long oggpack_bytes(oggpack_buffer *b){
+  return(b->count+b->headptr-b->head->buffer->data-b->head->begin+
+         (b->headbit+7)/8);
+}
 
-  b->ptr+=bits/8;
-  b->endbyte+=bits/8;
-  b->endbit=bits&7;
-  return(ret);
+long oggpack_bits(oggpack_buffer *b){
+  return((b->count+b->headptr-b->head->buffer->data-b->head->begin)*8+
+         b->headbit);
 }
 
-#undef BUFFER_INCREMENT

<p><p>1.4       +83 -66    Tremor/block.c

Index: block.c
===================================================================
RCS file: /usr/local/cvsroot/Tremor/block.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- block.c	16 Oct 2002 07:39:56 -0000	1.3
+++ block.c	29 Mar 2003 03:07:21 -0000	1.4
@@ -143,7 +143,7 @@
   return(0);
 }
 
-int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
   int i;
   codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
   private_state *b=NULL;
@@ -180,11 +180,6 @@
   v->lW=0; /* previous window size */
   v->W=0;  /* current window size */
 
-  /* all vector indexes */
-  v->centerW=ci->blocksizes[1]/2;
-
-  v->pcm_current=v->centerW;
-
   /* initialize all the mapping/backend lookups */
   b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
   for(i=0;i<ci->modes;i++){
@@ -193,7 +188,21 @@
     b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
                                          ci->map_param[mapnum]);
   }
+  return(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;
@@ -202,6 +211,13 @@
   return(0);
 }
 
+int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
+  _vds_init(v,vi);
+  vorbis_synthesis_restart(v);
+
+  return(0);
+}
+
 void vorbis_dsp_clear(vorbis_dsp_state *v){
   int i;
   if(v){
@@ -258,7 +274,8 @@
 
   v->sequence=vb->sequence;
   
-  {
+  if(vb->pcm){  /* no pcm to process if vorbis_synthesis_trackonly 
+                   was called on block */
     int n=ci->blocksizes[v->W]/2;
     int n0=ci->blocksizes[0]/2;
     int n1=ci->blocksizes[1]/2;
@@ -341,75 +358,75 @@
         ci->blocksizes[v->lW]/4+
         ci->blocksizes[v->W]/4;
     }
+
+  }
     
-    /* track the frame number... This is for convenience, but also
-       making sure our last packet doesn't end with added padding.  If
-       the last packet is partial, the number of samples we'll have to
-       return will be past the vb->granulepos.
-       
-       This is not foolproof!  It will be confused if we begin
-       decoding at the last page after a seek or hole.  In that case,
-       we don't have a starting point to judge where the last frame
-       is.  For this reason, vorbisfile will always try to make sure
-       it reads the last two marked pages in proper sequence */
-    
-    if(b->sample_count==-1){
-      b->sample_count=0;
-    }else{
-      b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
-    }
+  /* track the frame number... This is for convenience, but also
+     making sure our last packet doesn't end with added padding.  If
+     the last packet is partial, the number of samples we'll have to
+     return will be past the vb->granulepos.
+     
+     This is not foolproof!  It will be confused if we begin
+     decoding at the last page after a seek or hole.  In that case,
+     we don't have a starting point to judge where the last frame
+     is.  For this reason, vorbisfile will always try to make sure
+     it reads the last two marked pages in proper sequence */
+  
+  if(b->sample_count==-1){
+    b->sample_count=0;
+  }else{
+    b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+  }
     
-    if(v->granulepos==-1){
-      if(vb->granulepos!=-1){ /* only set if we have a position to set to */
-	
-	v->granulepos=vb->granulepos;
-	
-	/* is this a short page? */
-	if(b->sample_count>v->granulepos){
-	  /* corner case; if this is both the first and last audio page,
-	     then spec says the end is cut, not beginning */
-	  if(vb->eofflag){
-	    /* trim the end */
-	    /* no preceeding granulepos; assume we started at zero (we'd
-	       have to in a short single-page stream) */
-	    /* granulepos could be -1 due to a seek, but that would result
-	       in a long coun`t, not short count */
-	    
-	    v->pcm_current-=(b->sample_count-v->granulepos);
-	  }else{
-	    /* trim the beginning */
-	    v->pcm_returned+=(b->sample_count-v->granulepos);
-	    if(v->pcm_returned>v->pcm_current)
-	      v->pcm_returned=v->pcm_current;
-	  }
+  if(v->granulepos==-1){
+    if(vb->granulepos!=-1){ /* only set if we have a position to set to */
+      
+      v->granulepos=vb->granulepos;
+      
+      /* is this a short page? */
+      if(b->sample_count>v->granulepos){
+	/* corner case; if this is both the first and last audio page,
+	   then spec says the end is cut, not beginning */
+	if(vb->eofflag){
+	  /* trim the end */
+	  /* no preceeding granulepos; assume we started at zero (we'd
+	     have to in a short single-page stream) */
+	  /* granulepos could be -1 due to a seek, but that would result
+	     in a long coun`t, not short count */
           
+	  v->pcm_current-=(b->sample_count-v->granulepos);
+	}else{
+	  /* trim the beginning */
+	  v->pcm_returned+=(b->sample_count-v->granulepos);
+	  if(v->pcm_returned>v->pcm_current)
+	    v->pcm_returned=v->pcm_current;
         }
         
       }
-    }else{
-      v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
-      if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
+      
+    }
+  }else{
+    v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
+    if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
+      
+      if(v->granulepos>vb->granulepos){
+	long extra=v->granulepos-vb->granulepos;
         
-	if(v->granulepos>vb->granulepos){
-	  long extra=v->granulepos-vb->granulepos;
-	  
-	  if(extra)
-	    if(vb->eofflag){
-	      /* partial last frame.  Strip the extra samples off */
-	      v->pcm_current-=extra;
-	    } /* else {Shouldn't happen *unless* the bitstream is out of
-		 spec.  Either way, believe the bitstream } */
-	} /* else {Shouldn't happen *unless* the bitstream is out of
-	     spec.  Either way, believe the bitstream } */
-	v->granulepos=vb->granulepos;
-      }
+	if(extra)
+	  if(vb->eofflag){
+	    /* partial last frame.  Strip the extra samples off */
+	    v->pcm_current-=extra;
+	  } /* else {Shouldn't happen *unless* the bitstream is out of
+	       spec.  Either way, believe the bitstream } */
+      } /* else {Shouldn't happen *unless* the bitstream is out of
+	   spec.  Either way, believe the bitstream } */
+      v->granulepos=vb->granulepos;
     }
-    
-    /* Update, cleanup */
-    
-    if(vb->eofflag)v->eofflag=1;
   }
   
+  /* Update, cleanup */
+  
+  if(vb->eofflag)v->eofflag=1;
   return(0);
 }
 

<p><p>1.5       +856 -407  Tremor/framing.c

Index: framing.c
===================================================================
RCS file: /usr/local/cvsroot/Tremor/framing.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- framing.c	25 Nov 2002 20:20:21 -0000	1.4
+++ framing.c	29 Mar 2003 03:07:21 -0000	1.5
@@ -6,13 +6,12 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
- function: code raw [Vorbis] packets into framed OggSquish stream and
-           decode Ogg streams back into raw packets
+ function: decode Ogg streams back into raw packets
 
  note: The CRC code is directly derived from public domain code by
  Ross Williams (ross at guest.adelaide.edu.au).  See docs/framing.html
@@ -23,54 +22,452 @@
 #include <stdlib.h>
 #include <string.h>
 #include "ogg.h"
+#include "misc.h"
+
 
 /* A complete description of Ogg framing exists in docs/framing.html */
 
+/* basic, centralized Ogg memory management based on linked lists of
+   references to refcounted memory buffers.  References and buffers
+   are both recycled.  Buffers are passed around and consumed in
+   reference form. */
+
+static ogg_buffer_state *ogg_buffer_create(void){
+  ogg_buffer_state *bs=_ogg_calloc(1,sizeof(*bs));
+  return bs;
+}
+
+/* destruction is 'lazy'; there may be memory references outstanding,
+   and yanking the buffer state out from underneath would be
+   antisocial.  Dealloc what is currently unused and have
+   _release_one watch for the stragglers to come in.  When they do,
+   finish destruction. */
+
+/* call the helper while holding lock */
+static void _ogg_buffer_destroy(ogg_buffer_state *bs){
+  ogg_buffer *bt;
+  ogg_reference *rt;
+
+  if(bs->shutdown){
+
+    bt=bs->unused_buffers;
+    rt=bs->unused_references;
+
+    if(!bs->outstanding){
+      _ogg_free(bs);
+      return;
+    }
+
+    while(bt){
+      ogg_buffer *b=bt;
+      bt=b->ptr.next;
+      if(b->data)_ogg_free(b->data);
+      _ogg_free(b);
+    }
+    bs->unused_buffers=0;
+    while(rt){
+      ogg_reference *r=rt;
+      rt=r->next;
+      _ogg_free(r);
+    }
+    bs->unused_references=0;
+  }
+}
+
+static void ogg_buffer_destroy(ogg_buffer_state *bs){
+  bs->shutdown=1;
+  _ogg_buffer_destroy(bs);
+}
+
+static ogg_buffer *_fetch_buffer(ogg_buffer_state *bs,long bytes){
+  ogg_buffer    *ob;
+  bs->outstanding++;
+
+  /* do we have an unused buffer sitting in the pool? */
+  if(bs->unused_buffers){
+    ob=bs->unused_buffers;
+    bs->unused_buffers=ob->ptr.next;
+
+    /* if the unused buffer is too small, grow it */
+    if(ob->size<bytes){
+      ob->data=_ogg_realloc(ob->data,bytes);
+      ob->size=bytes;
+    }
+  }else{
+    /* allocate a new buffer */
+    ob=_ogg_malloc(sizeof(*ob));
+    ob->data=_ogg_malloc(bytes<16?16:bytes);
+    ob->size=bytes;
+  }
+
+  ob->refcount=1;
+  ob->ptr.owner=bs;
+  return ob;
+}
+
+static ogg_reference *_fetch_ref(ogg_buffer_state *bs){
+  ogg_reference *or;
+  bs->outstanding++;
+
+  /* do we have an unused reference sitting in the pool? */
+  if(bs->unused_references){
+    or=bs->unused_references;
+    bs->unused_references=or->next;
+  }else{
+    /* allocate a new reference */
+    or=_ogg_malloc(sizeof(*or));
+  }
+
+  or->begin=0;
+  or->length=0;
+  or->next=0;
+  return or;
+}
+
+/* fetch a reference pointing to a fresh, initially continguous buffer
+   of at least [bytes] length */
+static ogg_reference *ogg_buffer_alloc(ogg_buffer_state *bs,long bytes){
+  ogg_buffer    *ob=_fetch_buffer(bs,bytes);
+  ogg_reference *or=_fetch_ref(bs);
+  or->buffer=ob;
+  return or;
+}
+
+/* enlarge the data buffer in the current link */
+static void ogg_buffer_realloc(ogg_reference *or,long bytes){
+  ogg_buffer    *ob=or->buffer;
+  
+  /* if the unused buffer is too small, grow it */
+  if(ob->size<bytes){
+    ob->data=_ogg_realloc(ob->data,bytes);
+    ob->size=bytes;
+  }
+}
+
+static void _ogg_buffer_mark_one(ogg_reference *or){
+  or->buffer->refcount++;
+}
+
+/* increase the refcount of the buffers to which the reference points */
+static void ogg_buffer_mark(ogg_reference *or){
+  while(or){
+    _ogg_buffer_mark_one(or);
+    or=or->next;
+  }
+}
+
+/* duplicate a reference (pointing to the same actual buffer memory)
+   and increment buffer refcount.  If the desired segment begins out
+   of range, NULL is returned; if the desired segment is simply zero
+   length, a zero length ref is returned.  Partial range overlap
+   returns the overlap of the ranges */
+static ogg_reference *ogg_buffer_sub(ogg_reference *or,long begin,long length){
+  ogg_reference *ret=0,*head=0;
+
+  /* walk past any preceeding fragments we don't want */
+  while(or && begin>=or->length){
+    begin-=or->length;
+    or=or->next;
+  }
+
+  /* duplicate the reference chain; increment refcounts */
+  while(or && length){
+    ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner);
+    if(head)
+      head->next=temp;
+    else
+      ret=temp;
+    head=temp;
+    head->buffer=or->buffer;    
+    head->begin=or->begin+begin;
+    head->length=length;
+    if(head->length>or->length-begin)
+      head->length=or->length-begin;
+    
+    begin=0;
+    length-=head->length;
+    or=or->next;
+  }
+
+  ogg_buffer_mark(ret);
+  return ret;
+}
+
+ogg_reference *ogg_buffer_dup(ogg_reference *or){
+  ogg_reference *ret=0,*head=0;
+  /* duplicate the reference chain; increment refcounts */
+  while(or){
+    ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner);
+    if(head)
+      head->next=temp;
+    else
+      ret=temp;
+    head=temp;
+    head->buffer=or->buffer;    
+    head->begin=or->begin;
+    head->length=or->length;
+    or=or->next;
+  }
+
+  ogg_buffer_mark(ret);
+  return ret;
+}
+
+/* split a reference into two references; 'return' is a reference to
+   the buffer preceeding pos and 'head'/'tail' are the buffer past the
+   split.  If pos is at or past the end of the passed in segment,
+   'head/tail' are NULL */
+static ogg_reference *ogg_buffer_split(ogg_reference **tail,
+                                ogg_reference **head,long pos){
+
+  /* walk past any preceeding fragments to one of:
+     a) the exact boundary that seps two fragments
+     b) the fragment that needs split somewhere in the middle */
+  ogg_reference *ret=*tail;
+  ogg_reference *or=*tail;
+
+  while(or && pos>or->length){
+    pos-=or->length;
+    or=or->next;
+  }
+
+  if(!or || pos==0){
+
+    return 0;
+    
+  }else{
+    
+    if(pos>=or->length){
+      /* exact split, or off the end? */
+      if(or->next){
+        
+        /* a split */
+        *tail=or->next;
+        or->next=0;
+        
+      }else{
+        
+        /* off or at the end */
+        *tail=*head=0;
+        
+      }
+    }else{
+      
+      /* split within a fragment */
+      long lengthA=pos;
+      long beginB=or->begin+pos;
+      long lengthB=or->length-pos;
+      
+      /* make a new reference to tail the second piece */
+      *tail=_fetch_ref(or->buffer->ptr.owner);
+      
+      (*tail)->buffer=or->buffer;
+      (*tail)->begin=beginB;
+      (*tail)->length=lengthB;
+      (*tail)->next=or->next;
+      _ogg_buffer_mark_one(*tail);
+      if(head && or==*head)*head=*tail;    
+      
+      /* update the first piece */
+      or->next=0;
+      or->length=lengthA;
+      
+    }
+  }
+  return ret;
+}
+
+static void ogg_buffer_release_one(ogg_reference *or){
+  ogg_buffer *ob=or->buffer;
+  ogg_buffer_state *bs=ob->ptr.owner;
+
+  ob->refcount--;
+  if(ob->refcount==0){
+    bs->outstanding--; /* for the returned buffer */
+    ob->ptr.next=bs->unused_buffers;
+    bs->unused_buffers=ob;
+  }
+  
+  bs->outstanding--; /* for the returned reference */
+  or->next=bs->unused_references;
+  bs->unused_references=or;
+
+  _ogg_buffer_destroy(bs); /* lazy cleanup (if needed) */
+
+}
+
+/* release the references, decrease the refcounts of buffers to which
+   they point, release any buffers with a refcount that drops to zero */
+static void ogg_buffer_release(ogg_reference *or){
+  while(or){
+    ogg_reference *next=or->next;
+    ogg_buffer_release_one(or);
+    or=next;
+  }
+}
+
+static ogg_reference *ogg_buffer_pretruncate(ogg_reference *or,long pos){
+  /* release preceeding fragments we don't want */
+  while(or && pos>=or->length){
+    ogg_reference *next=or->next;
+    pos-=or->length;
+    ogg_buffer_release_one(or);
+    or=next;
+  }
+  if (or) {
+    or->begin+=pos;
+    or->length-=pos;
+  }
+  return or;
+}
+
+static ogg_reference *ogg_buffer_walk(ogg_reference *or){
+  if(!or)return NULL;
+  while(or->next){
+    or=or->next;
+  }
+  return(or);
+}
+
+/* *head is appended to the front end (head) of *tail; both continue to
+   be valid pointers, with *tail at the tail and *head at the head */
+static ogg_reference *ogg_buffer_cat(ogg_reference *tail, ogg_reference *head){
+  if(!tail)return head;
+
+  while(tail->next){
+    tail=tail->next;
+  }
+  tail->next=head;
+  return ogg_buffer_walk(head);
+}
+
+static void _positionB(oggbyte_buffer *b,int pos){
+  if(pos<b->pos){
+    /* start at beginning, scan forward */
+    b->ref=b->baseref;
+    b->pos=0;
+    b->end=b->pos+b->ref->length;
+    b->ptr=b->ref->buffer->data+b->ref->begin;
+  }
+}
+
+static void _positionF(oggbyte_buffer *b,int pos){
+  /* scan forward for position */
+  while(pos>=b->end){
+    /* just seek forward */
+    b->pos+=b->ref->length;
+    b->ref=b->ref->next;
+    b->end=b->ref->length+b->pos;
+    b->ptr=b->ref->buffer->data+b->ref->begin;
+  }
+}
+
+static int oggbyte_init(oggbyte_buffer *b,ogg_reference *or){
+  memset(b,0,sizeof(*b));
+  if(or){
+    b->ref=b->baseref=or;
+    b->pos=0;
+    b->end=b->ref->length;
+    b->ptr=b->ref->buffer->data+b->ref->begin;  
+    return 0;
+  }else
+    return -1;
+}
+
+static void oggbyte_set4(oggbyte_buffer *b,ogg_uint32_t val,int pos){
+  int i;
+  _positionB(b,pos);
+  for(i=0;i<4;i++){
+    _positionF(b,pos);
+    b->ptr[pos-b->pos]=val;
+    val>>=8;
+    ++pos;
+  }
+}
+ 
+static unsigned char oggbyte_read1(oggbyte_buffer *b,int pos){
+  _positionB(b,pos);
+  _positionF(b,pos);
+  return b->ptr[pos-b->pos];
+}
+
+static ogg_uint32_t oggbyte_read4(oggbyte_buffer *b,int pos){
+  ogg_uint32_t ret;
+  _positionB(b,pos);
+  _positionF(b,pos);
+  ret=b->ptr[pos-b->pos];
+  _positionF(b,++pos);
+  ret|=b->ptr[pos-b->pos]<<8;
+  _positionF(b,++pos);
+  ret|=b->ptr[pos-b->pos]<<16;
+  _positionF(b,++pos);
+  ret|=b->ptr[pos-b->pos]<<24;
+  return ret;
+}
+
+static ogg_int64_t oggbyte_read8(oggbyte_buffer *b,int pos){
+  ogg_int64_t ret;
+  unsigned char t[7];
+  int i;
+  _positionB(b,pos);
+  for(i=0;i<7;i++){
+    _positionF(b,pos);
+    t[i]=b->ptr[pos++ -b->pos];
+  }
+
+  _positionF(b,pos);
+  ret=b->ptr[pos-b->pos];
+
+  for(i=6;i>=0;--i)
+    ret= ret<<8 | t[i];
+
+  return ret;
+}
+
+/* Now we get to the actual framing code */
+
 int ogg_page_version(ogg_page *og){
-  return((int)(og->header[4]));
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read1(&ob,4);
 }
 
 int ogg_page_continued(ogg_page *og){
-  return((int)(og->header[5]&0x01));
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read1(&ob,5)&0x01;
 }
 
 int ogg_page_bos(ogg_page *og){
-  return((int)(og->header[5]&0x02));
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read1(&ob,5)&0x02;
 }
 
 int ogg_page_eos(ogg_page *og){
-  return((int)(og->header[5]&0x04));
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read1(&ob,5)&0x04;
 }
 
 ogg_int64_t ogg_page_granulepos(ogg_page *og){
-  unsigned char *page=og->header;
-  ogg_int64_t granulepos=page[13]&(0xff);
-  granulepos= (granulepos<<8)|(page[12]&0xff);
-  granulepos= (granulepos<<8)|(page[11]&0xff);
-  granulepos= (granulepos<<8)|(page[10]&0xff);
-  granulepos= (granulepos<<8)|(page[9]&0xff);
-  granulepos= (granulepos<<8)|(page[8]&0xff);
-  granulepos= (granulepos<<8)|(page[7]&0xff);
-  granulepos= (granulepos<<8)|(page[6]&0xff);
-  return(granulepos);
-}
-
-int ogg_page_serialno(ogg_page *og){
-  return(og->header[14] |
-	 (og->header[15]<<8) |
-	 (og->header[16]<<16) |
-	 (og->header[17]<<24));
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read8(&ob,6);
+}
+
+ogg_uint32_t ogg_page_serialno(ogg_page *og){
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read4(&ob,14);
 }
  
-long ogg_page_pageno(ogg_page *og){
-  return(og->header[18] |
-	 (og->header[19]<<8) |
-	 (og->header[20]<<16) |
-	 (og->header[21]<<24));
+ogg_uint32_t ogg_page_pageno(ogg_page *og){
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+  return oggbyte_read4(&ob,18);
 }
 
-
-
 /* returns the number of packets that are completed on this page (if
    the leading packet is begun on a previous page, but ends on this
    page, it's counted */
@@ -89,13 +486,22 @@
 */
 
 int ogg_page_packets(ogg_page *og){
-  int i,n=og->header[26],count=0;
+  int i;
+  int n;
+  int count=0;
+  oggbyte_buffer ob;
+  oggbyte_init(&ob,og->header);
+
+  n=oggbyte_read1(&ob,26);
   for(i=0;i<n;i++)
-    if(og->header[27+i]<255)count++;
+    if(oggbyte_read1(&ob,27+i)<255)count++;
   return(count);
 }
 
-static const ogg_uint32_t crc_lookup[256]={
+/* Static CRC calculation table.  See older code in CVS for dead
+   run-time initialization code. */
+
+static ogg_uint32_t crc_lookup[256]={
   0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
   0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
   0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
@@ -161,190 +567,92 @@
   0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
   0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
 
-/* init the encode/decode logical stream state */
-
-int ogg_stream_init(ogg_stream_state *os,int serialno){
-  if(os){
-    memset(os,0,sizeof(*os));
-    os->body_storage=6*1024;
-    os->body_data=(unsigned char *)_ogg_malloc(os->body_storage*sizeof(*os->body_data));
-
-    os->lacing_storage=128;
-    os->lacing_vals=(int *)_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
-    os->granule_vals=(ogg_int64_t *)_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
-
-    os->serialno=serialno;
-
-    return(0);
-  }
-  return(-1);
-} 
-
-/* _clear does not free os, only the non-flat storage within */
-int ogg_stream_clear(ogg_stream_state *os){
-  if(os){
-    if(os->body_data)_ogg_free(os->body_data);
-    if(os->lacing_vals)_ogg_free(os->lacing_vals);
-    if(os->granule_vals)_ogg_free(os->granule_vals);
-
-    memset(os,0,sizeof(*os));    
-  }
-  return(0);
-} 
-
-int ogg_stream_destroy(ogg_stream_state *os){
-  if(os){
-    ogg_stream_clear(os);
-    _ogg_free(os);
-  }
-  return(0);
-} 
-
-/* Helpers for ogg_stream_encode; this keeps the structure and
-   what's happening fairly clear */
-
-static void _os_body_expand(ogg_stream_state *os,int needed){
-  /* can we shift first? */
-  if(os->body_storage<=os->body_fill+needed){
-    long br=os->body_returned;
-    
-    os->body_fill-=br;
-    if(os->body_fill)
-      memmove(os->body_data,os->body_data+br,os->body_fill);
-    os->body_returned=0;
-  }
-
-  /* still need more? */
-  if(os->body_storage<=os->body_fill+needed){
-    os->body_storage+=(needed+1024);
-    os->body_data=(unsigned char *)_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
-  }
+ogg_sync_state *ogg_sync_create(void){
+  ogg_sync_state *oy=_ogg_calloc(1,sizeof(*oy));
+  memset(oy,0,sizeof(*oy));
+  oy->bufferpool=ogg_buffer_create();
+  return oy;
 }
 
-static void _os_lacing_expand(ogg_stream_state *os,int needed){
-
-  /* first check for a shift */
-  if(os->lacing_storage<=os->lacing_fill+needed){
-    long lr=os->lacing_returned;
-
-    /* segment table */
-    if(os->lacing_fill-lr){
-      memmove(os->lacing_vals,os->lacing_vals+lr,
-	      (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
-      memmove(os->granule_vals,os->granule_vals+lr,
-	      (os->lacing_fill-lr)*sizeof(*os->granule_vals));
-    }
-    os->lacing_fill-=lr;
-    os->lacing_packet-=lr;
-    os->lacing_returned=0;
-  }
-  
-  /* not enough?  *now* realloc */
-  if(os->lacing_storage<=os->lacing_fill+needed){
-    os->lacing_storage+=(needed+32);
-    os->lacing_vals=(int *)_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
-    os->granule_vals=(ogg_int64_t *)_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
+int ogg_sync_destroy(ogg_sync_state *oy){
+  if(oy){
+    ogg_sync_reset(oy);
+    ogg_buffer_destroy(oy->bufferpool);
+    memset(oy,0,sizeof(*oy));
+    _ogg_free(oy);
   }
+  return OGG_SUCCESS;
 }
 
-/* checksum the page */
-/* Direct table CRC; note that this will be faster in the future if we
-   perform the checksum silmultaneously with other copies */
+unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long bytes){
 
-void ogg_page_checksum_set(ogg_page *og){
-  if(og){
-    ogg_uint32_t crc_reg=0;
-    int i;
+  /* [allocate and] expose a buffer for data submission.
 
-    /* safety; needed for API behavior, but not framing code */
-    og->header[22]=0;
-    og->header[23]=0;
-    og->header[24]=0;
-    og->header[25]=0;
-    
-    for(i=0;i<og->header_len;i++)
-      crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
-    for(i=0;i<og->body_len;i++)
-      crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
-    
-    og->header[22]=crc_reg&0xff;
-    og->header[23]=(crc_reg>>8)&0xff;
-    og->header[24]=(crc_reg>>16)&0xff;
-    og->header[25]=(crc_reg>>24)&0xff;
+     If there is no head fragment
+       allocate one and expose it
+     else
+       if the current head fragment has sufficient unused space
+         expose it
+       else
+         if the current head fragment is unused
+           resize and expose it
+         else
+           allocate new fragment and expose it
+  */
+
+  /* base case; fifo uninitialized */
+  if(!oy->fifo_head){
+    oy->fifo_head=oy->fifo_tail=ogg_buffer_alloc(oy->bufferpool,bytes);
+    return oy->fifo_head->buffer->data;
   }
-}
-
-/* DECODING PRIMITIVES: packet streaming layer **********************/
-
-/* This has two layers to place more of the multi-serialno and paging
-   control in the application's hands.  First, we expose a data buffer
-   using ogg_sync_buffer().  The app either copies into the
-   buffer, or passes it directly to read(), etc.  We then call
-   ogg_sync_wrote() to tell how many bytes we just added.
-
-   Pages are returned (pointers into the buffer in ogg_sync_state)
-   by ogg_sync_pageout().  The page is then submitted to
-   ogg_stream_pagein() along with the appropriate
-   ogg_stream_state* (ie, matching serialno).  We then get raw
-   packets out calling ogg_stream_packetout() with a
-   ogg_stream_state.  See the 'frame-prog.txt' docs for details and
-   example code. */
-
-/* initialize the struct to a known state */
-int ogg_sync_init(ogg_sync_state *oy){
-  if(oy){
-    memset(oy,0,sizeof(*oy));
+  
+  /* space left in current fragment case */
+  if(oy->fifo_head->buffer->size-
+     oy->fifo_head->length-
+     oy->fifo_head->begin >= bytes)
+    return oy->fifo_head->buffer->data+
+      oy->fifo_head->length+oy->fifo_head->begin;
+
+  /* current fragment is unused, but too small */
+  if(!oy->fifo_head->length){
+    ogg_buffer_realloc(oy->fifo_head,bytes);
+    return oy->fifo_head->buffer->data+oy->fifo_head->begin;
   }
-  return(0);
-}
-
-/* clear non-flat storage within */
-int ogg_sync_clear(ogg_sync_state *oy){
-  if(oy){
-    if(oy->data)_ogg_free(oy->data);
-    ogg_sync_init(oy);
+  
+  /* current fragment used/full; get new fragment */
+  {
+    ogg_reference *new=ogg_buffer_alloc(oy->bufferpool,bytes);
+    oy->fifo_head->next=new;
+    oy->fifo_head=new;
   }
-  return(0);
+  return oy->fifo_head->buffer->data;
 }
 
-int ogg_sync_destroy(ogg_sync_state *oy){
-  if(oy){
-    ogg_sync_clear(oy);
-    _ogg_free(oy);
-  }
-  return(0);
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ 
+  if(!oy->fifo_head)return OGG_EINVAL;
+  if(oy->fifo_head->buffer->size-oy->fifo_head->length-oy->fifo_head->begin < 
+     bytes)return OGG_EINVAL;
+  oy->fifo_head->length+=bytes;
+  oy->fifo_fill+=bytes;
+  return OGG_SUCCESS;
 }
 
-char *ogg_sync_buffer(ogg_sync_state *oy, long size){
+static ogg_uint32_t _checksum(ogg_reference *or, int bytes){
+  ogg_uint32_t crc_reg=0;
+  int j,post;
 
-  /* first, clear out any space that has been previously returned */
-  if(oy->returned>8192){
-    oy->fill-=oy->returned;
-    if(oy->fill>0)
-      memmove(oy->data,oy->data+oy->returned,oy->fill);
-    oy->returned=0;
+  while(or){
+    unsigned char *data=or->buffer->data+or->begin;
+    post=(bytes<or->length?bytes:or->length);
+    for(j=0;j<post;++j)
+      crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^data[j]];
+    bytes-=j;
+    or=or->next;
   }
 
-  if(size>oy->storage-oy->fill){
-    /* We need to extend the internal buffer */
-    long newsize=size+oy->fill+4096; /* an extra page to be nice */
-
-    if(oy->data)
-      oy->data=(unsigned char *)_ogg_realloc(oy->data,newsize);
-    else
-      oy->data=(unsigned char *)_ogg_malloc(newsize);
-    oy->storage=newsize;
-  }
-
-  /* expose a segment at least as large as requested at the fill mark */
-  return((char *)oy->data+oy->fill);
+  return crc_reg;
 }
 
-int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
-  if(oy->fill+bytes>oy->storage)return(-1);
-  oy->fill+=bytes;
-  return(0);
-}
 
 /* sync the stream.  This is meant to be useful for finding page
    boundaries.
@@ -357,97 +665,117 @@
 */
 
 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
-  unsigned char *page=oy->data+oy->returned;
-  unsigned char *next;
-  long bytes=oy->fill-oy->returned;
-  
+  oggbyte_buffer page;
+  long           bytes,ret=0;
+
+  ogg_page_release(og);
+
+  bytes=oy->fifo_fill;
+  oggbyte_init(&page,oy->fifo_tail);
+
   if(oy->headerbytes==0){
-    int headerbytes,i;
-    if(bytes<27)return(0); /* not enough for a header */
+    if(bytes<27)goto sync_out; /* not enough for even a minimal header */
     
     /* verify capture pattern */
-    if(memcmp(page,"OggS",4))goto sync_fail;
-    
-    headerbytes=page[26]+27;
-    if(bytes<headerbytes)return(0); /* not enough for header + seg table */
-    
+    if(oggbyte_read1(&page,0)!=(int)'O' ||
+       oggbyte_read1(&page,1)!=(int)'g' ||
+       oggbyte_read1(&page,2)!=(int)'g' ||
+       oggbyte_read1(&page,3)!=(int)'S'    ) goto sync_fail;
+
+    oy->headerbytes=oggbyte_read1(&page,26)+27;
+  }
+  if(bytes<oy->headerbytes)goto sync_out; /* not enough for header +
+                                             seg table */
+  if(oy->bodybytes==0){
+    int i;
     /* count up body length in the segment table */
-    
-    for(i=0;i<page[26];i++)
-      oy->bodybytes+=page[27+i];
-    oy->headerbytes=headerbytes;
+    for(i=0;i<oy->headerbytes-27;i++)
+      oy->bodybytes+=oggbyte_read1(&page,27+i);
   }
   
-  if(oy->bodybytes+oy->headerbytes>bytes)return(0);
-  
-  /* The whole test page is buffered.  Verify the checksum */
+  if(oy->bodybytes+oy->headerbytes>bytes)goto sync_out;
+
+  /* we have what appears to be a complete page; last test: verify
+     checksum */
   {
-    /* Grab the checksum bytes, set the header field to zero */
-    char chksum[4];
-    ogg_page log;
-    
-    memcpy(chksum,page+22,4);
-    memset(page+22,0,4);
-    
-    /* set up a temp page struct and recompute the checksum */
-    log.header=page;
-    log.header_len=oy->headerbytes;
-    log.body=page+oy->headerbytes;
-    log.body_len=oy->bodybytes;
-    ogg_page_checksum_set(&log);
-    
-    /* Compare */
-    if(memcmp(chksum,page+22,4)){
+    ogg_uint32_t chksum=oggbyte_read4(&page,22);
+    oggbyte_set4(&page,0,22);
+
+    /* Compare checksums; memory continues to be common access */
+    if(chksum!=_checksum(oy->fifo_tail,oy->bodybytes+oy->headerbytes)){
+      
       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
-	 at all) */
-      /* replace the computed checksum with the one actually read in */
-      memcpy(page+22,chksum,4);
+         at all). replace the computed checksum with the one actually
+         read in; remember all the memory is common access */
       
-      /* Bad checksum. Lose sync */
+      oggbyte_set4(&page,chksum,22);
       goto sync_fail;
     }
+    oggbyte_set4(&page,chksum,22);
   }
-  
-  /* yes, have a whole page all ready to go */
-  {
-    unsigned char *page=oy->data+oy->returned;
-    long bytes;
-
-    if(og){
-      og->header=page;
-      og->header_len=oy->headerbytes;
-      og->body=page+oy->headerbytes;
-      og->body_len=oy->bodybytes;
-    }
 
-    oy->unsynced=0;
-    oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
-    oy->headerbytes=0;
-    oy->bodybytes=0;
-    return(bytes);
+  /* We have a page.  Set up page return. */
+  if(og){
+    /* set up page output */
+    og->header=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->headerbytes);
+    og->header_len=oy->headerbytes;
+    og->body=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->bodybytes);
+    og->body_len=oy->bodybytes;
+  }else{
+    /* simply advance */
+    oy->fifo_tail=
+      ogg_buffer_pretruncate(oy->fifo_tail,oy->headerbytes+oy->bodybytes);
+    if(!oy->fifo_tail)oy->fifo_head=0;
   }
   
- sync_fail:
+  ret=oy->headerbytes+oy->bodybytes;
+  oy->unsynced=0;
+  oy->headerbytes=0;
+  oy->bodybytes=0;
+  oy->fifo_fill-=ret;
+
+  return ret;
   
+ sync_fail:
+
   oy->headerbytes=0;
   oy->bodybytes=0;
+  oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,1);
+  ret--;
   
-  /* search for possible capture */
-  next=(unsigned char *)memchr(page+1,'O',bytes-1);
-  if(!next)
-    next=oy->data+oy->fill;
+  /* search forward through fragments for possible capture */
+  while(oy->fifo_tail){
+    /* invariant: fifo_cursor points to a position in fifo_tail */
+    unsigned char *now=oy->fifo_tail->buffer->data+oy->fifo_tail->begin;
+    unsigned char *next=memchr(now, 'O', oy->fifo_tail->length);
+      
+    if(next){
+      /* possible capture in this segment */
+      long bytes=next-now;
+      oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
+      ret-=bytes;
+      break;
+    }else{
+      /* no capture.  advance to next segment */
+      long bytes=oy->fifo_tail->length;
+      ret-=bytes;
+      oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
+    }
+  }
+  if(!oy->fifo_tail)oy->fifo_head=0;
+  oy->fifo_fill+=ret;
 
-  oy->returned=next-oy->data;
-  return(-(next-page));
+ sync_out:
+  return ret;
 }
 
 /* sync the stream and get a page.  Keep trying until we find a page.
    Supress 'sync errors' after reporting the first.
 
    return values:
-   -1) recapture (hole in data)
-    0) need more data
-    1) page returned
+   OGG_HOLE) recapture (hole in data)
+          0) need more data
+          1) page returned
 
    Returns pointers into buffered data; invalidated by next call to
    _stream, _clear, _init, or _buffer */
@@ -462,17 +790,17 @@
     long ret=ogg_sync_pageseek(oy,og);
     if(ret>0){
       /* have a page */
-      return(1);
+      return 1;
     }
     if(ret==0){
       /* need more data */
-      return(0);
+      return 0;
     }
     
     /* head did not start a synced page... skipped some bytes */
     if(!oy->unsynced){
       oy->unsynced=1;
-      return(-1);
+      return OGG_HOLE;
     }
 
     /* loop. keep looking */
@@ -480,123 +808,186 @@
   }
 }
 
-/* add the incoming page to the stream state; we decompose the page
-   into packet segments here as well. */
-int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
-  unsigned char *header=og->header;
-  unsigned char *body=og->body;
-  long           bodysize=og->body_len;
-  int            segptr=0;
+/* clear things to an initial state.  Good to call, eg, before seeking */
+int ogg_sync_reset(ogg_sync_state *oy){
 
-  int version=ogg_page_version(og);
-  int continued=ogg_page_continued(og);
-  int bos=ogg_page_bos(og);
-  int eos=ogg_page_eos(og);
-  ogg_int64_t granulepos=ogg_page_granulepos(og);
-  int serialno=ogg_page_serialno(og);
-  long pageno=ogg_page_pageno(og);
-  int segments=header[26];
-  
-  /* check the serial number */
-  if(serialno!=os->serialno)return(-1);
-  if(version>0)return(-1);
+  ogg_buffer_release(oy->fifo_tail);
+  oy->fifo_tail=0;
+  oy->fifo_head=0;
+  oy->fifo_fill=0;
 
-  _os_lacing_expand(os,segments+1);
+  oy->unsynced=0;
+  oy->headerbytes=0;
+  oy->bodybytes=0;
+  return OGG_SUCCESS;
+}
 
-  /* are we in sequence? */
-  if(pageno!=os->pageno){
-    int i;
+ogg_stream_state *ogg_stream_create(int serialno){
+  ogg_stream_state *os=_ogg_calloc(1,sizeof(*os));
+  os->serialno=serialno;
+  os->pageno=-1;
+  return os;
+} 
 
-    /* unroll previous partial packet (if any) */
-    for(i=os->lacing_packet;i<os->lacing_fill;i++)
-      os->body_fill-=os->lacing_vals[i]&0xff;
-    os->lacing_fill=os->lacing_packet;
-
-    /* make a note of dropped data in segment table */
-    if(os->pageno!=-1){
-      os->lacing_vals[os->lacing_fill++]=0x400;
-      os->lacing_packet++;
-    }
-
-    /* are we a 'continued packet' page?  If so, we'll need to skip
-       some segments */
-    if(continued){
-      bos=0;
-      for(;segptr<segments;segptr++){
-	int val=header[27+segptr];
-	body+=val;
-	bodysize-=val;
-	if(val<255){
-	  segptr++;
-	  break;
-	}
-      }
-    }
+int ogg_stream_destroy(ogg_stream_state *os){
+  if(os){
+    ogg_buffer_release(os->header_tail);
+    ogg_buffer_release(os->body_tail);
+    memset(os,0,sizeof(*os));    
   }
-  
-  if(bodysize){
-    _os_body_expand(os,bodysize);
-    memcpy(os->body_data+os->body_fill,body,bodysize);
-    os->body_fill+=bodysize;
+  return OGG_SUCCESS;
+} 
+
+
+#define FINFLAG 0x80000000UL
+#define FINMASK 0x7fffffffUL
+
+static void _next_lace(oggbyte_buffer *ob,ogg_stream_state *os){
+  /* search ahead one lace */
+  os->body_fill_next=0;
+  while(os->laceptr<os->lacing_fill){
+    int val=oggbyte_read1(ob,27+os->laceptr++);
+    os->body_fill_next+=val;
+    if(val<255){
+      os->body_fill_next|=FINFLAG;
+      os->clearflag=1;
+      break;
+    }
   }
+}
 
-  {
-    int saved=-1;
-    while(segptr<segments){
-      int val=header[27+segptr];
-      os->lacing_vals[os->lacing_fill]=val;
-      os->granule_vals[os->lacing_fill]=-1;
-      
-      if(bos){
-	os->lacing_vals[os->lacing_fill]|=0x100;
-	bos=0;
-      }
+static void _span_queued_page(ogg_stream_state *os){ 
+  while( !(os->body_fill&FINFLAG) ){
+    
+    if(!os->header_tail)break;
+
+    /* first flush out preceeding page header (if any).  Body is
+       flushed as it's consumed, so that's not done here. */
+
+    if(os->lacing_fill>=0)
+      os->header_tail=ogg_buffer_pretruncate(os->header_tail,
+                                             os->lacing_fill+27);
+    os->lacing_fill=0;
+    os->laceptr=0;
+    os->clearflag=0;
+
+    if(!os->header_tail){
+      os->header_head=0;
+      break;
+    }else{
       
-      if(val<255)saved=os->lacing_fill;
+      /* process/prepare next page, if any */
+
+      ogg_page og;               /* only for parsing header values */
+      og.header=os->header_tail; /* only for parsing header values */
+      long pageno=ogg_page_pageno(&og);
+      oggbyte_buffer ob;
+
+      oggbyte_init(&ob,os->header_tail);
+      os->lacing_fill=oggbyte_read1(&ob,26);
       
-      os->lacing_fill++;
-      segptr++;
+      /* are we in sequence? */
+      if(pageno!=os->pageno){
+        if(os->pageno==-1) /* indicates seek or reset */
+          os->holeflag=1;  /* set for internal use */
+        else
+          os->holeflag=2;  /* set for external reporting */
+
+        os->body_tail=ogg_buffer_pretruncate(os->body_tail,
+                                             os->body_fill);
+        if(os->body_tail==0)os->body_head=0;
+        os->body_fill=0;
+
+      }
+    
+      if(ogg_page_continued(&og)){
+        if(os->body_fill==0){
+          /* continued packet, but no preceeding data to continue */
+          /* dump the first partial packet on the page */
+          _next_lace(&ob,os);   
+          os->body_tail=
+            ogg_buffer_pretruncate(os->body_tail,os->body_fill_next&FINMASK);
+          if(os->body_tail==0)os->body_head=0;
+          /* set span flag */
+          if(!os->spanflag && !os->holeflag)os->spanflag=2;
+        }
+      }else{
+        if(os->body_fill>0){
+          /* preceeding data to continue, but not a continued page */
+          /* dump body_fill */
+          os->body_tail=ogg_buffer_pretruncate(os->body_tail,
+                                               os->body_fill);
+          if(os->body_tail==0)os->body_head=0;
+          os->body_fill=0;
+
+          /* set espan flag */
+          if(!os->spanflag && !os->holeflag)os->spanflag=2;
+        }
+      }
+
+      if(os->laceptr<os->lacing_fill){
+        os->granulepos=ogg_page_granulepos(&og);
+
+        /* get current packet size & flag */
+        _next_lace(&ob,os);
+        os->body_fill+=os->body_fill_next; /* addition handles the flag fine;
+                                             unsigned on purpose */
+        /* ...and next packet size & flag */
+        _next_lace(&ob,os);
+
+      }
       
-      if(val<255)os->lacing_packet=os->lacing_fill;
-    }
-  
-    /* set the granulepos on the last granuleval of the last full packet */
-    if(saved!=-1){
-      os->granule_vals[saved]=granulepos;
+      os->pageno=pageno+1;
+      os->e_o_s=ogg_page_eos(&og);
+      os->b_o_s=ogg_page_bos(&og);
+    
     }
-
   }
+}
 
-  if(eos){
-    os->e_o_s=1;
-    if(os->lacing_fill>0)
-      os->lacing_vals[os->lacing_fill-1]|=0x200;
-  }
+/* add the incoming page to the stream state; we decompose the page
+   into packet segments here as well. */
 
-  os->pageno=pageno+1;
+int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
 
-  return(0);
-}
+  int serialno=ogg_page_serialno(og);
+  int version=ogg_page_version(og);
 
-/* clear things to an initial state.  Good to call, eg, before seeking */
-int ogg_sync_reset(ogg_sync_state *oy){
-  oy->fill=0;
-  oy->returned=0;
-  oy->unsynced=0;
-  oy->headerbytes=0;
-  oy->bodybytes=0;
-  return(0);
+  /* check the serial number */
+  if(serialno!=os->serialno){
+    ogg_page_release(og);
+    return OGG_ESERIAL;
+  }
+  if(version>0){
+    ogg_page_release(og);
+    return OGG_EVERSION;
+  }
+
+  /* add to fifos */
+  if(!os->body_tail){
+    os->body_tail=og->body;
+    os->body_head=ogg_buffer_walk(og->body);
+  }else{
+    os->body_head=ogg_buffer_cat(os->body_head,og->body);
+  }
+  if(!os->header_tail){
+    os->header_tail=og->header;
+    os->header_head=ogg_buffer_walk(og->header);
+    os->lacing_fill=-27;
+  }else{
+    os->header_head=ogg_buffer_cat(os->header_head,og->header);
+  }
+
+  memset(og,0,sizeof(*og));
+  return OGG_SUCCESS;
 }
 
 int ogg_stream_reset(ogg_stream_state *os){
-  os->body_fill=0;
-  os->body_returned=0;
 
-  os->lacing_fill=0;
-  os->lacing_packet=0;
-  os->lacing_returned=0;
-
-  os->header_fill=0;
+  ogg_buffer_release(os->header_tail);
+  ogg_buffer_release(os->body_tail);
+  os->header_tail=os->header_head=0;
+  os->body_tail=os->body_head=0;
 
   os->e_o_s=0;
   os->b_o_s=0;
@@ -604,61 +995,100 @@
   os->packetno=0;
   os->granulepos=0;
 
-  return(0);
+  os->body_fill=0;
+  os->lacing_fill=0;
+
+  os->holeflag=0;
+  os->spanflag=0;
+  os->clearflag=0;
+  os->laceptr=0;
+  os->body_fill_next=0;
+
+  return OGG_SUCCESS;
+}
+
+int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
+  ogg_stream_reset(os);
+  os->serialno=serialno;
+  return OGG_SUCCESS;
 }
 
 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
 
-  /* The last part of decode. We have the stream broken into packet
-     segments.  Now we need to group them into packets (or return the
-     out of sync markers) */
-
-  int ptr=os->lacing_returned;
-
-  if(os->lacing_packet<=ptr)return(0);
-
-  if(os->lacing_vals[ptr]&0x400){
-    /* we need to tell the codec there's a gap; it might need to
-       handle previous packet dependencies. */
-    os->lacing_returned++;
-    os->packetno++;
-    return(-1);
+  ogg_packet_release(op);
+  _span_queued_page(os);
+
+  if(os->holeflag){
+    int temp=os->holeflag;
+    if(os->clearflag)
+      os->holeflag=0;
+    else
+      os->holeflag=1;
+    if(temp==2){
+      os->packetno++;
+      return OGG_HOLE;
+    }
+  }
+  if(os->spanflag){
+    int temp=os->spanflag;
+    if(os->clearflag)
+      os->spanflag=0;
+    else
+      os->spanflag=1;
+    if(temp==2){
+      os->packetno++;
+      return OGG_SPAN;
+    }
   }
 
-  if(!op && !adv)return(1); /* just using peek as an inexpensive way
+  if(!(os->body_fill&FINFLAG)) return 0;
+  if(!op && !adv)return 1; /* just using peek as an inexpensive way
                                to ask if there's a whole packet
                                waiting */
+  if(op){
+    op->b_o_s=os->b_o_s;
+    if(os->e_o_s && os->body_fill_next==0)
+      op->e_o_s=os->e_o_s;
+    else
+      op->e_o_s=0;
+    if( (os->body_fill&FINFLAG) && !(os->body_fill_next&FINFLAG) )
+      op->granulepos=os->granulepos;
+    else
+      op->granulepos=-1;
+    op->packetno=os->packetno;
+  }
 
-  /* Gather the whole packet. We'll have no holes or a partial packet */
-  {
-    int size=os->lacing_vals[ptr]&0xff;
-    int bytes=size;
-    int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
-    int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
-
-    while(size==255){
-      int val=os->lacing_vals[++ptr];
-      size=val&0xff;
-      if(val&0x200)eos=0x200;
-      bytes+=size;
-    }
+  if(adv){
+    oggbyte_buffer ob;
+    oggbyte_init(&ob,os->header_tail);
 
+    /* split the body contents off */
     if(op){
-      op->e_o_s=eos;
-      op->b_o_s=bos;
-      op->packet=os->body_data+os->body_returned;
-      op->packetno=os->packetno;
-      op->granulepos=os->granule_vals[ptr];
-      op->bytes=bytes;
+      op->packet=ogg_buffer_split(&os->body_tail,&os->body_head,
+				  os->body_fill&FINMASK);
+      op->bytes=os->body_fill&FINMASK;
+    }else{
+      os->body_tail=ogg_buffer_pretruncate(os->body_tail,
+					   os->body_fill&FINMASK);
+      if(os->body_tail==0)os->body_head=0;
     }
 
-    if(adv){
-      os->body_returned+=bytes;
-      os->lacing_returned=ptr+1;
-      os->packetno++;
+    /* update lacing pointers */
+    os->body_fill=os->body_fill_next;
+    _next_lace(&ob,os);
+  }else{
+    if(op){
+      op->packet=ogg_buffer_sub(os->body_tail,0,os->body_fill&FINMASK);
+      op->bytes=os->body_fill&FINMASK;
     }
   }
-  return(1);
+  
+  if(adv){
+    os->packetno++;
+    os->b_o_s=0;
+  }
+
+  return 1;
 }
 
 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
@@ -669,8 +1099,27 @@
   return _packetout(os,op,0);
 }
 
-void ogg_packet_clear(ogg_packet *op) {
-  _ogg_free(op->packet);
-  memset(op, 0, sizeof(*op));
+int ogg_packet_release(ogg_packet *op) {
+  if(op){
+    ogg_buffer_release(op->packet);
+    memset(op, 0, sizeof(*op));
+  }
+  return OGG_SUCCESS;
+}
+
+int ogg_page_release(ogg_page *og) {
+  if(og){
+    ogg_buffer_release(og->header);
+    ogg_buffer_release(og->body);
+    memset(og, 0, sizeof(*og));
+  }
+  return OGG_SUCCESS;
+}
+
+void ogg_page_dup(ogg_page *dup,ogg_page *orig){
+  dup->header_len=orig->header_len;
+  dup->body_len=orig->body_len;
+  dup->header=ogg_buffer_dup(orig->header);
+  dup->body=ogg_buffer_dup(orig->body);
 }
 

<p><p>1.3       +2 -2      Tremor/info.c

Index: info.c
===================================================================
RCS file: /usr/local/cvsroot/Tremor/info.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- info.c	3 Sep 2002 03:15:19 -0000	1.2
+++ info.c	29 Mar 2003 03:07:21 -0000	1.3
@@ -6,7 +6,7 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
@@ -300,7 +300,7 @@
   oggpack_buffer opb;
   
   if(op){
-    oggpack_readinit(&opb,op->packet,op->bytes);
+    oggpack_readinit(&opb,op->packet);
 
     /* Which of the three types of header is this? */
     /* Also verify header-ness, vorbis */

<p><p>1.3       +2 -1      Tremor/ivorbiscodec.h

Index: ivorbiscodec.h
===================================================================
RCS file: /usr/local/cvsroot/Tremor/ivorbiscodec.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ivorbiscodec.h	3 Sep 2002 03:15:19 -0000	1.2
+++ ivorbiscodec.h	29 Mar 2003 03:07:21 -0000	1.3
@@ -169,7 +169,8 @@
                                           ogg_packet *op);
 
 extern int      vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
-extern int      vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
+extern int      vorbis_synthesis_restart(vorbis_dsp_state *v);
+extern int      vorbis_synthesis(vorbis_block *vb,ogg_packet *op,int decodep);
 extern int      vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
 extern int      vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm);
 extern int      vorbis_synthesis_read(vorbis_dsp_state *v,int samples);

<p><p>1.3       +6 -7      Tremor/ivorbisfile.h

Index: ivorbisfile.h
===================================================================
RCS file: /usr/local/cvsroot/Tremor/ivorbisfile.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- ivorbisfile.h	3 Sep 2002 03:15:19 -0000	1.2
+++ ivorbisfile.h	29 Mar 2003 03:07:21 -0000	1.3
@@ -26,8 +26,7 @@
 #include <stdio.h>
 #include "ivorbiscodec.h"
 
-#define CHUNKSIZE 8192
-
+#define CHUNKSIZE 1024
 /* The function prototypes for the callbacks are basically the same as for
  * the stdio functions fread, fseek, fclose, ftell. 
  * The one difference is that the FILE * arguments have been replaced with
@@ -56,14 +55,14 @@
   int              seekable;
   ogg_int64_t      offset;
   ogg_int64_t      end;
-  ogg_sync_state   oy; 
+  ogg_sync_state   *oy; 
 
   /* If the FILE handle isn't seekable (eg, a pipe), only the current
      stream appears */
   int              links;
   ogg_int64_t     *offsets;
   ogg_int64_t     *dataoffsets;
-  long            *serialnos;
+  ogg_uint32_t    *serialnos;
   ogg_int64_t     *pcmlengths;
   vorbis_info     *vi;
   vorbis_comment  *vc;
@@ -71,13 +70,13 @@
   /* Decoding working state local storage */
   ogg_int64_t      pcm_offset;
   int              ready_state;
-  long             current_serialno;
+  ogg_uint32_t     current_serialno;
   int              current_link;
 
   ogg_int64_t      bittrack;
   ogg_int64_t      samptrack;
 
-  ogg_stream_state os; /* take physical pages, weld into a logical
+  ogg_stream_state *os; /* take physical pages, weld into a logical
                           stream of packets */
   vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
   vorbis_block     vb; /* local working space for packet->PCM decode */
@@ -106,7 +105,7 @@
 extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
 extern ogg_int64_t ov_time_total(OggVorbis_File *vf,int i);
 
-extern int ov_raw_seek(OggVorbis_File *vf,long pos);
+extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
 extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
 extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
 extern int ov_time_seek(OggVorbis_File *vf,ogg_int64_t pos);

<p><p>1.7       +15 -0     Tremor/misc.h

Index: misc.h
===================================================================
RCS file: /usr/local/cvsroot/Tremor/misc.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- misc.h	16 Oct 2002 09:12:08 -0000	1.6
+++ misc.h	29 Mar 2003 03:07:21 -0000	1.7
@@ -20,6 +20,21 @@
 #include "ivorbiscodec.h"
 #include "os_types.h"
 
+//#define _VDBG_GRAPHFILE "_0.m"
+extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line); 
+extern void _VDBG_free(void *ptr,char *file,long line); 
+
+#undef _ogg_malloc
+#undef _ogg_calloc
+#undef _ogg_realloc
+#undef _ogg_free
+
+#define _ogg_malloc(x) _VDBG_malloc(NULL,(x),__FILE__,__LINE__)
+#define _ogg_calloc(x,y) _VDBG_malloc(NULL,(x)*(y),__FILE__,__LINE__)
+#define _ogg_realloc(x,y) _VDBG_malloc((x),(y),__FILE__,__LINE__)
+#define _ogg_free(x) _VDBG_free((x),__FILE__,__LINE__)
+
+
 extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes);
 extern void _vorbis_block_ripcord(vorbis_block *vb);
 extern void _analysis_output(char *base,int i,ogg_int32_t *v,int point,

<p><p>1.4       +132 -84   Tremor/ogg.h

Index: ogg.h
===================================================================
RCS file: /usr/local/cvsroot/Tremor/ogg.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ogg.h	20 Sep 2002 01:31:39 -0000	1.3
+++ ogg.h	29 Mar 2003 03:07:21 -0000	1.4
@@ -6,7 +6,7 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
@@ -23,105 +23,138 @@
 
 #include "os_types.h"
 
-typedef struct {
-  long endbyte;
-  int  endbit;
+typedef struct ogg_buffer_state{
+  struct ogg_buffer    *unused_buffers;
+  struct ogg_reference *unused_references;
+  int                   outstanding;
+  int                   shutdown;
+} ogg_buffer_state;
+
+typedef struct ogg_buffer {
+  unsigned char      *data;
+  long                size;
+  int                 refcount;
+  
+  union {
+    ogg_buffer_state  *owner;
+    struct ogg_buffer *next;
+  } ptr;
+} ogg_buffer;
+
+typedef struct ogg_reference {
+  ogg_buffer    *buffer;
+  long           begin;
+  long           length;
+
+  struct ogg_reference *next;
+} ogg_reference;
+
+typedef struct oggpack_buffer {
+  int            headbit;
+  unsigned char *headptr;
+  long           headend;
+
+  /* memory management */
+  ogg_reference *head;
+  ogg_reference *tail;
 
-  unsigned char *buffer;
-  unsigned char *ptr;
-  long storage;
+  /* render the byte/bit counter API constant time */
+  long              count; /* doesn't count the tail */
 } oggpack_buffer;
 
-/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
-
-typedef struct {
-  unsigned char *header;
-  long header_len;
-  unsigned char *body;
-  long body_len;
-} ogg_page;
+typedef struct oggbyte_buffer {
+  ogg_reference *baseref;
 
-/* ogg_stream_state contains the current encode/decode state of a logical
-   Ogg bitstream **********************************************************/
+  ogg_reference *ref;
+  unsigned char *ptr;
+  long           pos;
+  long           end;
+} oggbyte_buffer;
+
+typedef struct ogg_sync_state {
+  /* decode memory management pool */
+  ogg_buffer_state *bufferpool;
+
+  /* stream buffers */
+  ogg_reference    *fifo_head;
+  ogg_reference    *fifo_tail;
+  long              fifo_fill;
+
+  /* stream sync management */
+  int               unsynced;
+  int               headerbytes;
+  int               bodybytes;
 
-typedef struct {
-  unsigned char   *body_data;    /* bytes from packet bodies */
-  long    body_storage;          /* storage elements allocated */
-  long    body_fill;             /* elements stored; fill mark */
-  long    body_returned;         /* elements of fill returned */
-
-
-  int     *lacing_vals;      /* The values that will go to the segment table */
-  ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
-				this way, but it is simple coupled to the
-				lacing fifo */
-  long    lacing_storage;
-  long    lacing_fill;
-  long    lacing_packet;
-  long    lacing_returned;
-
-  unsigned char    header[282];      /* working space for header encode */
-  int              header_fill;
-
-  int     e_o_s;          /* set when we have buffered the last packet in the
-                             logical bitstream */
-  int     b_o_s;          /* set after we've written the initial page
-                             of a logical bitstream */
-  long    serialno;
-  long    pageno;
-  ogg_int64_t  packetno;      /* sequence number for decode; the framing
-                             knows where there's a hole in the data,
-                             but we need coupling so that the codec
-                             (which is in a seperate abstraction
-                             layer) also knows about the gap */
-  ogg_int64_t   granulepos;
+} ogg_sync_state;
 
+typedef struct ogg_stream_state {
+  ogg_reference *header_head;
+  ogg_reference *header_tail;
+  ogg_reference *body_head;
+  ogg_reference *body_tail;
+
+  int            e_o_s;    /* set when we have buffered the last
+                              packet in the logical bitstream */
+  int            b_o_s;    /* set after we've written the initial page
+                              of a logical bitstream */
+  long           serialno;
+  long           pageno;
+  ogg_int64_t    packetno; /* sequence number for decode; the framing
+                              knows where there's a hole in the data,
+                              but we need coupling so that the codec
+                              (which is in a seperate abstraction
+                              layer) also knows about the gap */
+  ogg_int64_t    granulepos;
+
+  int            lacing_fill;
+  ogg_uint32_t   body_fill;
+
+  /* decode-side state data */
+  int            holeflag;
+  int            spanflag;
+  int            clearflag;
+  int            laceptr;
+  ogg_uint32_t   body_fill_next;
+  
 } ogg_stream_state;
 
-/* ogg_packet is used to encapsulate the data and metadata belonging
-   to a single raw Ogg/Vorbis packet *************************************/
-
 typedef struct {
-  unsigned char *packet;
-  long  bytes;
-  long  b_o_s;
-  long  e_o_s;
-
-  ogg_int64_t  granulepos;
-  
-  ogg_int64_t  packetno;     /* sequence number for decode; the framing
-				knows where there's a hole in the data,
-				but we need coupling so that the codec
-				(which is in a seperate abstraction
-				layer) also knows about the gap */
+  ogg_reference *packet;
+  long           bytes;
+  long           b_o_s;
+  long           e_o_s;
+  ogg_int64_t    granulepos;
+  ogg_int64_t    packetno;     /* sequence number for decode; the framing
+                                  knows where there's a hole in the data,
+                                  but we need coupling so that the codec
+                                  (which is in a seperate abstraction
+                                  layer) also knows about the gap */
 } ogg_packet;
 
 typedef struct {
-  unsigned char *data;
-  int storage;
-  int fill;
-  int returned;
-
-  int unsynced;
-  int headerbytes;
-  int bodybytes;
-} ogg_sync_state;
+  ogg_reference *header;
+  int            header_len;
+  ogg_reference *body;
+  long           body_len;
+} ogg_page;
 
 /* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
 
-extern void  oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void  oggpack_readinit(oggpack_buffer *b,ogg_reference *r);
 extern long  oggpack_look(oggpack_buffer *b,int bits);
 extern void  oggpack_adv(oggpack_buffer *b,int bits);
 extern long  oggpack_read(oggpack_buffer *b,int bits);
+extern long  oggpack_bytes(oggpack_buffer *b);
+extern long  oggpack_bits(oggpack_buffer *b);
+extern int   oggpack_eop(oggpack_buffer *b);
 
 /* Ogg BITSTREAM PRIMITIVES: decoding **************************/
 
-extern int      ogg_sync_init(ogg_sync_state *oy);
-extern int      ogg_sync_clear(ogg_sync_state *oy);
+extern ogg_sync_state *ogg_sync_create(void);
+extern int      ogg_sync_destroy(ogg_sync_state *oy);
 extern int      ogg_sync_reset(ogg_sync_state *oy);
-extern int	ogg_sync_destroy(ogg_sync_state *oy);
 
-extern char    *ogg_sync_buffer(ogg_sync_state *oy, long size);
+extern unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long size);
 extern int      ogg_sync_wrote(ogg_sync_state *oy, long bytes);
 extern long     ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
 extern int      ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
@@ -131,24 +164,39 @@
 
 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
 
-extern int      ogg_stream_init(ogg_stream_state *os,int serialno);
-extern int      ogg_stream_clear(ogg_stream_state *os);
-extern int      ogg_stream_reset(ogg_stream_state *os);
+extern ogg_stream_state *ogg_stream_create(int serialno);
 extern int      ogg_stream_destroy(ogg_stream_state *os);
+extern int      ogg_stream_reset(ogg_stream_state *os);
+extern int      ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
 extern int      ogg_stream_eos(ogg_stream_state *os);
 
-extern void     ogg_page_checksum_set(ogg_page *og);
+extern int      ogg_page_checksum_set(ogg_page *og);
 
 extern int      ogg_page_version(ogg_page *og);
 extern int      ogg_page_continued(ogg_page *og);
 extern int      ogg_page_bos(ogg_page *og);
 extern int      ogg_page_eos(ogg_page *og);
 extern ogg_int64_t  ogg_page_granulepos(ogg_page *og);
-extern int      ogg_page_serialno(ogg_page *og);
-extern long     ogg_page_pageno(ogg_page *og);
+extern ogg_uint32_t ogg_page_serialno(ogg_page *og);
+extern ogg_uint32_t ogg_page_pageno(ogg_page *og);
 extern int      ogg_page_packets(ogg_page *og);
+extern int      ogg_page_getbuffer(ogg_page *og, unsigned char **buffer);
+
+extern int      ogg_packet_release(ogg_packet *op);
+extern int      ogg_page_release(ogg_page *og);
+
+extern void     ogg_page_dup(ogg_page *d, ogg_page *s);
+
+/* Ogg BITSTREAM PRIMITIVES: return codes ***************************/
+
+#define  OGG_SUCCESS   0
 
-extern void     ogg_packet_clear(ogg_packet *op);
+#define  OGG_HOLE     -10
+#define  OGG_SPAN     -11
+#define  OGG_EVERSION -12
+#define  OGG_ESERIAL  -13
+#define  OGG_EINVAL   -14
+#define  OGG_EEOS     -15
 
 
 #ifdef __cplusplus

<p><p>1.4       +23 -15    Tremor/synthesis.c

Index: synthesis.c
===================================================================
RCS file: /usr/local/cvsroot/Tremor/synthesis.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- synthesis.c	16 Oct 2002 07:39:56 -0000	1.3
+++ synthesis.c	29 Mar 2003 03:07:21 -0000	1.4
@@ -6,13 +6,13 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
  function: single-block PCM synthesis
- last mod: $Id: synthesis.c,v 1.3 2002/10/16 07:39:56 xiphmont Exp $
+ last mod: $Id: synthesis.c,v 1.4 2003/03/29 03:07:21 xiphmont Exp $
 
  ********************************************************************/
 
@@ -24,7 +24,7 @@
 #include "misc.h"
 #include "os.h"
 
-int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){
+int vorbis_synthesis(vorbis_block *vb,ogg_packet *op,int decodep){
   vorbis_dsp_state     *vd=vb->vd;
   private_state        *b=(private_state *)vd->backend_state;
   vorbis_info          *vi=vd->vi;
@@ -34,7 +34,7 @@
  
   /* first things first.  Make sure decode is ready */
   _vorbis_block_ripcord(vb);
-  oggpack_readinit(opb,op->packet,op->bytes);
+  oggpack_readinit(opb,op->packet);
 
   /* Check the packet type */
   if(oggpack_read(opb,1)!=0){
@@ -62,16 +62,24 @@
   vb->sequence=op->packetno-3; /* first block is third packet */
   vb->eofflag=op->e_o_s;
 
-  /* alloc pcm passback storage */
-  vb->pcmend=ci->blocksizes[vb->W];
-  vb->pcm=(ogg_int32_t **)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
-  for(i=0;i<vi->channels;i++)
-    vb->pcm[i]=(ogg_int32_t *)_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
-
-  /* unpack_header enforces range checking */
-  type=ci->map_type[ci->mode_param[mode]->mapping];
-
-  return(_mapping_P[type]->inverse(vb,b->mode[mode]));
+  if(decodep){
+    /* alloc pcm passback storage */
+    vb->pcmend=ci->blocksizes[vb->W];
+    vb->pcm=(ogg_int32_t **)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
+    for(i=0;i<vi->channels;i++)
+      vb->pcm[i]=(ogg_int32_t *)_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
+    
+    /* unpack_header enforces range checking */
+    type=ci->map_type[ci->mode_param[mode]->mapping];
+    
+    return(_mapping_P[type]->inverse(vb,b->mode[mode]));
+  }else{
+    /* no pcm */
+    vb->pcmend=0;
+    vb->pcm=NULL;
+    
+    return(0);
+  }
 }
 
 long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
@@ -79,7 +87,7 @@
   oggpack_buffer       opb;
   int                  mode;
  
-  oggpack_readinit(&opb,op->packet,op->bytes);
+  oggpack_readinit(&opb,op->packet);
 
   /* Check the packet type */
   if(oggpack_read(&opb,1)!=0){

<p><p>1.5       +422 -250  Tremor/vorbisfile.c

Index: vorbisfile.c
===================================================================
RCS file: /usr/local/cvsroot/Tremor/vorbisfile.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- vorbisfile.c	16 Oct 2002 08:16:11 -0000	1.4
+++ vorbisfile.c	29 Mar 2003 03:07:21 -0000	1.5
@@ -6,12 +6,13 @@
  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002    *
+ * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
  *                                                                  *
  ********************************************************************
 
  function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c,v 1.5 2003/03/29 03:07:21 xiphmont Exp $
 
  ********************************************************************/
 
@@ -56,14 +57,14 @@
  * harder to understand anyway.  The high level functions are last.  Begin
  * grokking near the end of the file */
 
-/* read a little more data from the file/pipe into the ogg_sync framer
-*/
+
+/* read a little more data from the file/pipe into the ogg_sync framer */
 static long _get_data(OggVorbis_File *vf){
   errno=0;
   if(vf->datasource){
-    char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
+    char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE);
     long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
-    if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
+    if(bytes>0)ogg_sync_wrote(vf->oy,bytes);
     if(bytes==0 && errno)return(-1);
     return(bytes);
   }else
@@ -71,11 +72,11 @@
 }
 
 /* save a tiny smidge of verbosity to make the code more readable */
-static void _seek_helper(OggVorbis_File *vf,long offset){
+static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
   if(vf->datasource){ 
     (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
     vf->offset=offset;
-    ogg_sync_reset(&vf->oy);
+    ogg_sync_reset(vf->oy);
   }else{
     /* shouldn't happen unless someone writes a broken callback */
     return;
@@ -93,15 +94,18 @@
               n) search for a new page beginning for n bytes
 
    return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
-              n) found a page at absolute offset n */
+              n) found a page at absolute offset n 
+
+              produces a refcounted page */
 
-static long _get_next_page(OggVorbis_File *vf,ogg_page *og,int boundary){
+static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
+				  ogg_int64_t boundary){
   if(boundary>0)boundary+=vf->offset;
   while(1){
     long more;
 
     if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
-    more=ogg_sync_pageseek(&vf->oy,og);
+    more=ogg_sync_pageseek(vf->oy,og);
     
     if(more<0){
       /* skipped n bytes */
@@ -118,7 +122,7 @@
       }else{
         /* got a page.  Return the offset at the page beginning,
            advance the internal offset past the page end */
-	long ret=vf->offset;
+	ogg_int64_t ret=vf->offset;
         vf->offset+=more;
         return(ret);
         
@@ -131,19 +135,21 @@
    position. Much dirtier than the above as Ogg doesn't have any
    backward search linkage.  no 'readp' as it will certainly have to
    read. */
-/* returns offset or OV_EREAD, OV_FAULT */
-static long _get_prev_page(OggVorbis_File *vf,ogg_page *og){
-  long begin=vf->offset;
-  long ret;
-  int offset=-1;
+/* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */
+
+static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
+  ogg_int64_t begin=vf->offset;
+  ogg_int64_t end=begin;
+  ogg_int64_t ret;
+  ogg_int64_t offset=-1;
 
   while(offset==-1){
     begin-=CHUNKSIZE;
     if(begin<0)
       begin=0;
     _seek_helper(vf,begin);
-    while(vf->offset<begin+CHUNKSIZE){
-      ret=_get_next_page(vf,og,begin+CHUNKSIZE-vf->offset);
+    while(vf->offset<end){
+      ret=_get_next_page(vf,og,end-vf->offset);
       if(ret==OV_EREAD)return(OV_EREAD);
       if(ret<0){
         break;
@@ -168,20 +174,20 @@
    Recurses for each link so it can alloc the link storage after
    finding them all, then unroll and fill the cache at the same time */
 static int _bisect_forward_serialno(OggVorbis_File *vf,
-				    long begin,
-				    long searched,
-				    long end,
-				    long currentno,
+				    ogg_int64_t begin,
+				    ogg_int64_t searched,
+				    ogg_int64_t end,
+				    ogg_uint32_t currentno,
                                     long m){
-  long endsearched=end;
-  long next=end;
-  ogg_page og;
-  long ret;
+  ogg_int64_t endsearched=end;
+  ogg_int64_t next=end;
+  ogg_page og={0,0,0,0};
+  ogg_int64_t ret;
   
   /* the below guards against garbage seperating the last and
      first pages of two links. */
   while(searched<endsearched){
-    long bisect;
+    ogg_int64_t bisect;
     
     if(endsearched-searched<CHUNKSIZE){
       bisect=searched;
@@ -198,6 +204,7 @@
     }else{
       searched=ret+og.header_len+og.body_len;
     }
+    ogg_page_release(&og);
   }
 
   _seek_helper(vf,next);
@@ -205,36 +212,45 @@
   if(ret==OV_EREAD)return(OV_EREAD);
   
   if(searched>=end || ret<0){
+    ogg_page_release(&og);
     vf->links=m+1;
-    vf->offsets=(ogg_int64_t *)_ogg_malloc((m+2)*sizeof(*vf->offsets));
+    vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
+    vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
     vf->offsets[m+1]=searched;
   }else{
     ret=_bisect_forward_serialno(vf,next,vf->offset,
                                  end,ogg_page_serialno(&og),m+1);
+    ogg_page_release(&og);
     if(ret==OV_EREAD)return(OV_EREAD);
   }
   
   vf->offsets[m]=begin;
+  vf->serialnos[m]=currentno;
   return(0);
 }
 
 /* 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){
-  ogg_page og;
-  ogg_packet op;
-  int i,ret=0;
+/* consumes the page that's passed in (if any) */
+
+static int _fetch_headers(OggVorbis_File *vf,
+			  vorbis_info *vi,
+			  vorbis_comment *vc,
+			  ogg_uint32_t *serialno,
+			  ogg_page *og_ptr){
+  ogg_page og={0,0,0,0};
+  ogg_packet op={0,0,0,0,0,0};
+  int i,ret;
   
   if(!og_ptr){
-    ret=_get_next_page(vf,&og,CHUNKSIZE);
-    if(ret==OV_EREAD)return(OV_EREAD);
-    if(ret<0)return OV_ENOTVORBIS;
+    ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
+    if(llret==OV_EREAD)return(OV_EREAD);
+    if(llret<0)return OV_ENOTVORBIS;
     og_ptr=&og;
   }
 
-  if(serialno)*serialno=ogg_page_serialno(og_ptr);
-  ogg_stream_init(&vf->os,ogg_page_serialno(og_ptr));
+  ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
+  if(serialno)*serialno=vf->os->serialno;
   vf->ready_state=STREAMSET;
   
   /* extract the initial header from the first page and verify that the
@@ -245,9 +261,9 @@
   
   i=0;
   while(i<3){
-    ogg_stream_pagein(&vf->os,og_ptr);
+    ogg_stream_pagein(vf->os,og_ptr);
     while(i<3){
-      int result=ogg_stream_packetout(&vf->os,&op);
+      int result=ogg_stream_packetout(vf->os,&op);
       if(result==0)break;
       if(result==-1){
         ret=OV_EBADHEADER;
@@ -264,12 +280,16 @@
         goto bail_header;
       }
   }
+
+  ogg_packet_release(&op);
+  ogg_page_release(&og);
   return 0; 
 
  bail_header:
+  ogg_packet_release(&op);
+  ogg_page_release(&og);
   vorbis_info_clear(vi);
   vorbis_comment_clear(vc);
-  ogg_stream_clear(&vf->os);
   vf->ready_state=OPENED;
 
   return ret;
@@ -284,20 +304,22 @@
    able to open and use damaged bitstreams as well as we can.  Just
    watch out for missing information for links in the OggVorbis_File
    struct */
-static void _prefetch_all_headers(OggVorbis_File *vf, long dataoffset){
-  ogg_page og;
-  int i,ret;
-  
-  vf->vi=(vorbis_info *)_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
-  vf->vc=(vorbis_comment *)_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
-  vf->dataoffsets=(ogg_int64_t *)_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
-  vf->pcmlengths=(ogg_int64_t *)_ogg_malloc(vf->links*sizeof(*vf->pcmlengths));
-  vf->serialnos=(long *)_ogg_malloc(vf->links*sizeof(*vf->serialnos));
+static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){
+  ogg_page og={0,0,0,0};
+  int i;
+  ogg_int64_t ret;
+  
+  vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
+  vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
+  vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
+  vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
   
   for(i=0;i<vf->links;i++){
     if(i==0){
       /* we already grabbed the initial header earlier.  Just set the offset */
       vf->dataoffsets[i]=dataoffset;
+      _seek_helper(vf,dataoffset);
+
     }else{
 
       /* seek to the location of the initial header */
@@ -307,14 +329,62 @@
             vf->dataoffsets[i]=-1;
       }else{
         vf->dataoffsets[i]=vf->offset;
-        ogg_stream_clear(&vf->os);
       }
     }
 
-    /* get the serial number and PCM length of this link. To do this,
+    /* fetch beginning PCM offset */
+
+    if(vf->dataoffsets[i]!=-1){
+      ogg_int64_t accumulated=0,pos;
+      long        lastblock=-1;
+      int         result;
+
+      ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);
+
+      while(1){
+	ogg_packet op={0,0,0,0,0,0};
+
+	ret=_get_next_page(vf,&og,-1);
+	if(ret<0)
+	  /* this should not be possible unless the file is
+             truncated/mangled */
+	  break;
+       
+	if(ogg_page_serialno(&og)!=vf->serialnos[i])
+	  break;
+	
+	pos=ogg_page_granulepos(&og);
+
+	/* count blocksizes of all frames in the page */
+	ogg_stream_pagein(vf->os,&og);
+	while((result=ogg_stream_packetout(vf->os,&op))){
+	  if(result>0){ /* ignore holes */
+	    long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);
+	    if(lastblock!=-1)
+	      accumulated+=(lastblock+thisblock)>>2;
+	    lastblock=thisblock;
+	  }
+	}
+	ogg_packet_release(&op);
+
+	if(pos!=-1){
+	  /* pcm offset of last packet on the first audio page */
+	  accumulated= pos-accumulated;
+	  break;
+	}
+      }
+
+      /* less than zero?  This is a stream with samples trimmed off
+         the beginning, a normal occurrence; set the offset to zero */
+      if(accumulated<0)accumulated=0;
+
+      vf->pcmlengths[i*2]=accumulated;
+    }
+
+    /* get the PCM length of this link. To do this,
        get the last page of the stream */
     {
-      long end=vf->offsets[i+1];
+      ogg_int64_t end=vf->offsets[i+1];
       _seek_helper(vf,end);
 
       while(1){
@@ -326,14 +396,14 @@
           break;
         }
         if(ogg_page_granulepos(&og)!=-1){
-	  vf->serialnos[i]=ogg_page_serialno(&og);
-	  vf->pcmlengths[i]=ogg_page_granulepos(&og);
+	  vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
           break;
         }
         vf->offset=ret;
       }
     }
   }
+  ogg_page_release(&og);
 }
 
 static void _make_decode_ready(OggVorbis_File *vf){
@@ -345,13 +415,16 @@
   }    
   vorbis_block_init(&vf->vd,&vf->vb);
   vf->ready_state=INITSET;
+  vf->bittrack=0;
+  vf->samptrack=0;
   return;
 }
 
 static int _open_seekable2(OggVorbis_File *vf){
-  long serialno=vf->current_serialno,end;
-  long dataoffset=vf->offset;
-  ogg_page og;
+  ogg_uint32_t serialno=vf->current_serialno;
+  ogg_uint32_t tempserialno;
+  ogg_int64_t dataoffset=vf->offset, end;
+  ogg_page og={0,0,0,0};
 
   /* we're partially open and have a first link header state in
      storage in vf */
@@ -362,28 +435,22 @@
   /* We get the offset for the last page of the physical bitstream.
      Most OggVorbis files will contain a single logical bitstream */
   end=_get_prev_page(vf,&og);
-  if(end<0){
-    ov_clear(vf);
-    return(end);
-  }
+  if(end<0)return(end);
 
   /* more than one logical bitstream? */
-  if(ogg_page_serialno(&og)!=serialno){
+  tempserialno=ogg_page_serialno(&og);
+  ogg_page_release(&og);
+
+  if(tempserialno!=serialno){
 
     /* Chained bitstream. Bisect-search each logical bitstream
        section.  Do so based on serial number only */
-    if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0){
-      ov_clear(vf);
-      return(OV_EREAD);
-    }
+    if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
 
   }else{
 
     /* Only one logical bitstream */
-    if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0)){
-      ov_clear(vf);
-      return(OV_EREAD);
-    }
+    if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
 
   }
 
@@ -394,13 +461,9 @@
 
 /* clear out the current logical bitstream decoder */ 
 static void _decode_clear(OggVorbis_File *vf){
-  ogg_stream_clear(&vf->os);
   vorbis_dsp_clear(&vf->vd);
   vorbis_block_clear(&vf->vb);
   vf->ready_state=OPENED;
-
-  vf->bittrack=0;
-  vf->samptrack=0;
 }
 
 /* fetch and process a packet.  Handles the case where we're at a
@@ -414,8 +477,12 @@
             1) got a packet 
 */
 
-static int _process_packet(OggVorbis_File *vf,int readp){
-  ogg_page og;
+static int _fetch_and_process_packet(OggVorbis_File *vf,
+				     int readp,
+				     int spanp){
+  ogg_page og={0,0,0,0};
+  ogg_packet op={0,0,0,0,0,0};
+  int ret=0;
 
   /* handle one packet.  Try to fetch it from current stream state */
   /* extract packets from page */
@@ -425,25 +492,34 @@
        neither is a page */
     if(vf->ready_state==INITSET){
       while(1) {
-      	ogg_packet op;
-	int result=ogg_stream_packetout(&vf->os,&op);
+	int result=ogg_stream_packetout(vf->os,&op);
         ogg_int64_t granulepos;
 
-	if(result==-1)return(OV_HOLE); /* hole in the data. */
+	if(result<0){
+	  ret=OV_HOLE; /* hole in the data. */
+	  goto cleanup;
+	}
         if(result>0){
           /* got a packet.  process it */
           granulepos=op.granulepos;
-	  if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy
-                                                 header handling.  The
-                                                 header packets aren't
-                                                 audio, so if/when we
-                                                 submit them,
-                                                 vorbis_synthesis will
-                                                 reject them */
+	  if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy
+						      header handling.  The
+						      header packets aren't
+						      audio, so if/when we
+						      submit them,
+						      vorbis_synthesis will
+						      reject them */
 
             /* suck in the synthesis data and track bitrate */
             {
               int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
+	      /* for proper use of libvorbis within libvorbisfile,
+                 oldsamples will always be zero. */
+	      if(oldsamples){
+		ret=OV_EFAULT;
+		goto cleanup;
+	      }
+
               vorbis_synthesis_blockin(&vf->vd,&vf->vb);
               vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
               vf->bittrack+=op.bytes*8;
@@ -466,15 +542,23 @@
                  So, we need a previous granulepos from an in-sequence page
                  to have a reference point.  Thus the !op.e_o_s clause
                  above */
-	    
+
+	      if(vf->seekable && link>0)
+		granulepos-=vf->pcmlengths[link*2];
+	      if(granulepos<0)granulepos=0; /* actually, this
+					       shouldn't be possible
+					       here unless the stream
+					       is very broken */
+
               samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
             
               granulepos-=samples;
               for(i=0;i<link;i++)
-	        granulepos+=vf->pcmlengths[i];
+	        granulepos+=vf->pcmlengths[i*2+1];
               vf->pcm_offset=granulepos;
             }
-	    return(1);
+	    ret=1;
+	    goto cleanup;
           }
         }
         else 
@@ -483,16 +567,28 @@
     }
 
     if(vf->ready_state>=OPENED){
-      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 */
+      int ret;
+      if(!readp){
+	ret=0;
+	goto cleanup;
+      }
+      if((ret=_get_next_page(vf,&og,-1))<0){
+	ret=OV_EOF; /* eof. leave unitialized */
+	goto cleanup;
+      }
+
+	/* 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){
+	    ret=OV_EOF;
+	    goto cleanup;
+	  }
+
           _decode_clear(vf);
           
           if(!vf->seekable){
@@ -527,15 +623,15 @@
              boundaries */
           for(link=0;link<vf->links;link++)
             if(vf->serialnos[link]==vf->current_serialno)break;
-	  if(link==vf->links)return(OV_EBADLINK); /* sign of a bogus
-						     stream.  error out,
-						     leave machine
-						     uninitialized */
+	  if(link==vf->links){
+	    ret=OV_EBADLINK; /* sign of a bogus stream.  error out,
+				leave machine uninitialized */
+	    goto cleanup;
+	  }
           
           vf->current_link=link;
           
-	  ogg_stream_init(&vf->os,vf->current_serialno);
-	  ogg_stream_reset(&vf->os); 
+	  ogg_stream_reset_serialno(vf->os,vf->current_serialno);
           vf->ready_state=STREAMSET;
           
         }else{
@@ -543,7 +639,7 @@
           /* fetch the three header packets, build the info struct */
           
           int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
-	  if(ret)return(ret);
+	  if(ret) goto cleanup;
           vf->current_link++;
           link=0;
         }
@@ -551,18 +647,24 @@
       
       _make_decode_ready(vf);
     }
-    ogg_stream_pagein(&vf->os,&og);
+    ogg_stream_pagein(vf->os,&og);
   }
+ cleanup:
+  ogg_packet_release(&op);
+  ogg_page_release(&og);
+  return ret;
 }
 
+/* if, eg, 64 bit stdio is configured by default, this will build with
+   fseek64 */
 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
   if(f==NULL)return(-1);
-  return fseek(f,(int)off,whence);
+  return fseek(f,off,whence);
 }
 
 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
                      long ibytes, ov_callbacks callbacks){
-  long offset=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
+  int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
   int ret;
 
   memset(vf,0,sizeof(*vf));
@@ -570,27 +672,28 @@
   vf->callbacks = callbacks;
 
   /* init the framing state */
-  ogg_sync_init(&vf->oy);
+  vf->oy=ogg_sync_create();
 
   /* 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) */
   if(initial){
-    char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
+    char *buffer=ogg_sync_bufferin(vf->oy,ibytes);
     memcpy(buffer,initial,ibytes);
-    ogg_sync_wrote(&vf->oy,ibytes);
+    ogg_sync_wrote(vf->oy,ibytes);
   }
 
   /* can we seek? Stevens suggests the seek test was portable */
-  if(offset!=-1)vf->seekable=1;
+  if(offsettest!=-1)vf->seekable=1;
 
   /* No seeking yet; Set up a 'single' (current) logical bitstream
      entry for partial open */
   vf->links=1;
-  vf->vi=(vorbis_info *)_ogg_calloc(vf->links,sizeof(*vf->vi));
-  vf->vc=(vorbis_comment *)_ogg_calloc(vf->links,sizeof(*vf->vc));
-  
+  vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
+  vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
+  vf->os=ogg_stream_create(-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){
     vf->datasource=NULL;
@@ -620,7 +723,7 @@
   if(vf){
     vorbis_block_clear(&vf->vb);
     vorbis_dsp_clear(&vf->vd);
-    ogg_stream_clear(&vf->os);
+    ogg_stream_destroy(vf->os);
     
     if(vf->vi && vf->links){
       int i;
@@ -635,7 +738,8 @@
     if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
     if(vf->serialnos)_ogg_free(vf->serialnos);
     if(vf->offsets)_ogg_free(vf->offsets);
-    ogg_sync_clear(&vf->oy);
+    ogg_sync_destroy(vf->oy);
+
     if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
     memset(vf,0,sizeof(*vf));
   }
@@ -726,6 +830,10 @@
     int i;
     for(i=0;i<vf->links;i++)
       bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
+    /* This once read: return(rint(bits/ov_time_total(vf,-1)));
+     * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
+     * so this is slightly transformed to make it work.
+     */
     return(bits*1000/ov_time_total(vf,-1));
   }else{
     if(vf->seekable){
@@ -784,7 +892,7 @@
   if(vf->ready_state<OPENED)return(OV_EINVAL);
   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
   if(i<0){
-    long acc=0;
+    ogg_int64_t acc=0;
     int i;
     for(i=0;i<vf->links;i++)
       acc+=ov_raw_total(vf,i);
@@ -809,12 +917,12 @@
       acc+=ov_pcm_total(vf,i);
     return(acc);
   }else{
-    return(vf->pcmlengths[i]);
+    return(vf->pcmlengths[i*2+1]);
   }
 }
 
 /* returns: total milliseconds of content if i==-1
-            seconds in that logical bitstream for i==0 to n
+            milliseconds in that logical bitstream for i==0 to n
             OV_EINVAL if the stream is not seekable (we can't know the
             length) or only partially open 
 */
@@ -839,19 +947,26 @@
 
    returns zero on success, nonzero on failure */
 
-int ov_raw_seek(OggVorbis_File *vf,long pos){
-  ogg_stream_state work_os;
-
+int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
+  ogg_stream_state *work_os=NULL;
+  ogg_page og={0,0,0,0};
+  ogg_packet op={0,0,0,0,0,0};
+  
   if(vf->ready_state<OPENED)return(OV_EINVAL);
   if(!vf->seekable)
     return(OV_ENOSEEK); /* don't dump machine if we can't seek */
 
-  if(pos<0 || pos>vf->offsets[vf->links])return(OV_EINVAL);
-  
-  /* clear out decoding machine state */
+  if(pos<0 || pos>vf->end)return(OV_EINVAL);
+
+  /* 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 */
+  vorbis_synthesis_restart(&vf->vd);
+    
   _seek_helper(vf,pos);
 
   /* we need to make sure the pcm_offset is set, but we don't want to
@@ -860,7 +975,7 @@
      decoding as immediately after the seek position as possible.
 
      So, a hack.  We use two stream states; a local scratch state and
-     a the shared vf->os stream state.  We use the local state to
+     the shared vf->os stream state.  We use the local state to
      scan, and the shared state as a buffer for later decode. 
 
      Unfortuantely, on the last page we still advance to last packet
@@ -870,42 +985,46 @@
   */
 
   {
-    ogg_page og;
-    ogg_packet op;
     int lastblock=0;
     int accblock=0;
-    int thisblock=-1;
-    int eosflag=0;
-
-    memset(&work_os,0,sizeof(work_os));/* so that it's safe to clear
-					  it later even if we don't
-					  init it */
+    int thisblock;
+    int eosflag;
 
+    work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */
     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);
+	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(eosflag)
-	    ogg_stream_packetout(&vf->os,NULL);
-	  else
-	    if(lastblock)accblock+=(lastblock+thisblock)>>2;
-
-	  if(op.granulepos!=-1){
-	    int i,link=vf->current_link;
-	    ogg_int64_t granulepos=op.granulepos;
-	    
-	    for(i=0;i<link;i++)
-	      granulepos+=vf->pcmlengths[i];
-	    vf->pcm_offset=granulepos-accblock;
-	    break;
-	  }
-	  lastblock=thisblock;
-	  continue;
+	    if(thisblock<0){
+	      ogg_stream_packetout(vf->os,NULL);
+	      thisblock=0;
+	    }else{
+	      
+	      if(eosflag)
+		ogg_stream_packetout(vf->os,NULL);
+	      else
+		if(lastblock)accblock+=(lastblock+thisblock)>>2;
+	    }	    
+
+	    if(op.granulepos!=-1){
+	      int i,link=vf->current_link;
+	      ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
+	      if(granulepos<0)granulepos=0;
+	      
+	      for(i=0;i<link;i++)
+		granulepos+=vf->pcmlengths[i*2+1];
+	      vf->pcm_offset=granulepos-accblock;
+	      break;
+	    }
+	    lastblock=thisblock;
+	    continue;
+	  }else
+	    ogg_stream_packetout(vf->os,NULL);
         }
       }
       
@@ -921,11 +1040,11 @@
       }
       
       /* 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_destroy(work_os);
+	}
 
       if(vf->ready_state<STREAMSET){
         int link;
@@ -933,32 +1052,42 @@
         vf->current_serialno=ogg_page_serialno(&og);
         for(link=0;link<vf->links;link++)
           if(vf->serialnos[link]==vf->current_serialno)break;
-	if(link==vf->links)goto seek_error; /* sign of a bogus stream.
-					       error out, leave
-					       machine uninitialized */
+	if(link==vf->links)
+	  goto seek_error; /* sign of a bogus stream.  error out,
+			      leave machine uninitialized */
+ 
         vf->current_link=link;
         
-	ogg_stream_init(&vf->os,vf->current_serialno);
-	ogg_stream_reset(&vf->os); 
-	ogg_stream_init(&work_os,vf->current_serialno);
-	ogg_stream_reset(&work_os); 
+	ogg_stream_reset_serialno(vf->os,vf->current_serialno);
+	ogg_stream_reset_serialno(work_os,vf->current_serialno); 
         vf->ready_state=STREAMSET;
         
       }
     
-      ogg_stream_pagein(&vf->os,&og);
-      ogg_stream_pagein(&work_os,&og);
-      eosflag=ogg_page_eos(&og);
+      {
+	ogg_page dup;
+	ogg_page_dup(&dup,&og);
+	eosflag=ogg_page_eos(&og);
+	ogg_stream_pagein(vf->os,&og);
+	ogg_stream_pagein(work_os,&dup);
+      }
     }
   }
 
-  ogg_stream_clear(&work_os);
+  ogg_packet_release(&op);
+  ogg_page_release(&og);
+  ogg_stream_destroy(work_os);
+  vf->bittrack=0;
+  vf->samptrack=0;
   return(0);
 
  seek_error:
+  ogg_packet_release(&op);
+  ogg_page_release(&og);
+
   /* dump the machine so we're in a known state */
   vf->pcm_offset=-1;
-  ogg_stream_clear(&work_os);
+  ogg_stream_destroy(work_os);
   _decode_clear(vf);
   return OV_EBADLINK;
 }
@@ -971,8 +1100,10 @@
    arrive at the requested position. */
 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
   int link=-1;
-  long ret;
+  ogg_int64_t result=0;
   ogg_int64_t total=ov_pcm_total(vf,-1);
+  ogg_page og={0,0,0,0};
+  ogg_packet op={0,0,0,0,0,0};
 
   if(vf->ready_state<OPENED)return(OV_EINVAL);
   if(!vf->seekable)return(OV_ENOSEEK);
@@ -980,7 +1111,7 @@
  
   /* which bitstream section does this pcm offset occur in? */
   for(link=vf->links-1;link>=0;link--){
-    total-=vf->pcmlengths[link];
+    total-=vf->pcmlengths[link*2+1];
     if(pos>=total)break;
   }
 
@@ -992,16 +1123,15 @@
 
   /* new search algorithm by HB (Nicholas Vinen) */
   {
-    ogg_int64_t target=pos-total;
-    long end=vf->offsets[link+1];
-    long begin=vf->offsets[link];
-    ogg_int64_t endtime = vf->pcmlengths[link];
-    ogg_int64_t begintime = 0;
-    long best=begin;
+    ogg_int64_t end=vf->offsets[link+1];
+    ogg_int64_t begin=vf->offsets[link];
+    ogg_int64_t begintime = vf->pcmlengths[link*2];
+    ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
+    ogg_int64_t target=pos-total+begintime;
+    ogg_int64_t best=begin;
     
-    ogg_page og;
     while(begin<end){
-      long bisect;
+      ogg_int64_t bisect;
       
       if(end-begin<CHUNKSIZE){
         bisect=begin;
@@ -1012,40 +1142,42 @@
         if(bisect<=begin)
           bisect=begin+1;
       }
+      
       _seek_helper(vf,bisect);
     
       while(begin<end){
-	ret=_get_next_page(vf,&og,end-bisect);
-	if(ret==OV_EREAD) goto seek_error;
-	if(ret<0){
+	result=_get_next_page(vf,&og,end-vf->offset);
+	if(result==OV_EREAD) goto seek_error;
+	if(result<0){
           if(bisect<=begin+1)
             end=begin; /* found it */
           else{
-	    if(bisect==0)goto seek_error;
+	    if(bisect==0) goto seek_error;
             bisect-=CHUNKSIZE;
             if(bisect<=begin)bisect=begin+1;
             _seek_helper(vf,bisect);
           }
         }else{
           ogg_int64_t granulepos=ogg_page_granulepos(&og);
+	  if(granulepos==-1)continue;
           if(granulepos<target){
-	    best=ret;  /* raw offset of packet with granulepos */ 
+	    best=result;  /* raw offset of packet with granulepos */ 
             begin=vf->offset; /* raw offset of next page */
             begintime=granulepos;
             
-	    if(target-begin>44100)break;
+	    if(target-begintime>44100)break;
             bisect=begin; /* *not* begin + 1 */
           }else{
             if(bisect<=begin+1)
               end=begin;  /* found it */
             else{
               if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
-		end=ret;
+		end=result;
                 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
                 if(bisect<=begin)bisect=begin+1;
                 _seek_helper(vf,bisect);
               }else{
-		end=ret;
+		end=result;
                 endtime=granulepos;
                 break;
               }
@@ -1058,103 +1190,139 @@
     /* found our page. seek to it, update pcm offset. Easier case than
        raw_seek, don't keep packets preceeding granulepos. */
     {
-      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;
-      
-      ogg_stream_init(&vf->os,vf->current_serialno);
-      ogg_stream_reset(&vf->os); 
-      vf->ready_state=STREAMSET;
-      ogg_stream_pagein(&vf->os,&og);
+      if(_get_next_page(vf,&og,-1)<0){
+	ogg_page_release(&og);
+	return(OV_EOF); /* shouldn't happen */
+      }
+
+      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{
+	vorbis_synthesis_restart(&vf->vd);
+      }
+
+      ogg_stream_reset_serialno(vf->os,vf->current_serialno);
+      ogg_stream_pagein(vf->os,&og);
 
       /* pull out all but last packet; the one with granulepos */
       while(1){
-	ret=ogg_stream_packetpeek(&vf->os,&op);
-	if(ret==0){
+	result=ogg_stream_packetpeek(vf->os,&op);
+	if(result==0){
           /* !!! the packet finishing this page originated on a
              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. */
+	  
+	  _seek_helper(vf,best);
+	  
           while(1){
-	    ret=_get_prev_page(vf,&og);
-	    if(ret<0)goto seek_error;
+	    result=_get_prev_page(vf,&og);
+	    if(result<0) goto seek_error;
             if(ogg_page_granulepos(&og)>-1 ||
                !ogg_page_continued(&og)){
-	      return ov_raw_seek(vf,ret);
+	      return ov_raw_seek(vf,result);
             }
-	    vf->offset=ret;
+	    vf->offset=result;
           }
         }
-	if(ret<0)goto seek_error;
+	if(result<0){
+	  result = OV_EBADPACKET; 
+	  goto seek_error;
+	}
         if(op.granulepos!=-1){
-	  vf->pcm_offset=op.granulepos+total;
+	  vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+	  if(vf->pcm_offset<0)vf->pcm_offset=0;
+	  vf->pcm_offset+=total;
           break;
         }else
-	  ret=ogg_stream_packetout(&vf->os,NULL);
+	  result=ogg_stream_packetout(vf->os,NULL);
       }
     }
   }
   
   /* verify result */
   if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
-    ret=OV_EFAULT;
+    result=OV_EFAULT;
     goto seek_error;
   }
+  vf->bittrack=0;
+  vf->samptrack=0;
+
+  ogg_page_release(&og);
+  ogg_packet_release(&op);
   return(0);
   
  seek_error:
+
+  ogg_page_release(&og);
+  ogg_packet_release(&op);
+
   /* dump machine so we're in a known state */
   vf->pcm_offset=-1;
   _decode_clear(vf);
-  return ret;
+  return (int)result;
 }
 
 /* seek to a sample offset relative to the decompressed pcm stream 
    returns zero on success, nonzero on failure */
 
 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
+  ogg_packet op={0,0,0,0,0,0};
+  ogg_page og={0,0,0,0};
   int thisblock,lastblock=0;
   int ret=ov_pcm_seek_page(vf,pos);
   if(ret<0)return(ret);
+  _make_decode_ready(vf);
 
   /* discard leading packets we don't need for the lapping of the
      position we want; don't decode them */
 
   while(1){
-    ogg_packet op;
-    ogg_page og;
 
-    int ret=ogg_stream_packetpeek(&vf->os,&op);
+    int ret=ogg_stream_packetpeek(vf->os,&op);
     if(ret>0){
       thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
+      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+
                           vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
-
-      ogg_stream_packetout(&vf->os,NULL);
       
-
+      /* remove the packet from packet queue and track its granulepos */
+      ogg_stream_packetout(vf->os,NULL);
+      vorbis_synthesis(&vf->vb,&op,0);  /* set up a vb with
+					   only tracking, no
+					   pcm_decode */
+      vorbis_synthesis_blockin(&vf->vd,&vf->vb); 
+      
       /* end of logical stream case is hard, especially with exact
-         length positioning. */
-
+	 length positioning. */
+      
       if(op.granulepos>-1){
         int i;
         /* always believe the stream markers */
-	vf->pcm_offset=op.granulepos;
+	vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
+	if(vf->pcm_offset<0)vf->pcm_offset=0;
         for(i=0;i<vf->current_link;i++)
-	  vf->pcm_offset+=vf->pcmlengths[i];
+	  vf->pcm_offset+=vf->pcmlengths[i*2+1];
       }
-
+	
       lastblock=thisblock;
-
+      
     }else{
       if(ret<0 && ret!=OV_HOLE)break;
       
@@ -1168,34 +1336,42 @@
         vf->current_serialno=ogg_page_serialno(&og);
         for(link=0;link<vf->links;link++)
           if(vf->serialnos[link]==vf->current_serialno)break;
-	if(link==vf->links)return(OV_EBADLINK);
+	if(link==vf->links){
+	  ogg_page_release(&og);
+	  ogg_packet_release(&op);
+	  return(OV_EBADLINK);
+	}
         vf->current_link=link;
         
-	ogg_stream_init(&vf->os,vf->current_serialno);
-	ogg_stream_reset(&vf->os); 
+	ogg_stream_reset_serialno(vf->os,vf->current_serialno); 
         vf->ready_state=STREAMSET;      
+	_make_decode_ready(vf);
         lastblock=0;
       }
-      ogg_stream_pagein(&vf->os,&og);
+
+      ogg_stream_pagein(vf->os,&og);
     }
   }
 
+  vf->bittrack=0;
+  vf->samptrack=0;
   /* discard samples until we reach the desired position. Crossing a
      logical bitstream boundary with abandon is OK. */
-  _make_decode_ready(vf);
   while(vf->pcm_offset<pos){
-    ogg_int32_t **pcm;
-    long target=pos-vf->pcm_offset;
-    long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
+    ogg_int64_t target=pos-vf->pcm_offset;
+    long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
 
     if(samples>target)samples=target;
     vorbis_synthesis_read(&vf->vd,samples);
     vf->pcm_offset+=samples;
     
     if(samples<target)
-      if(_process_packet(vf,1)<=0)
+      if(_fetch_and_process_packet(vf,1,1)<=0)
         vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
   }
+
+  ogg_page_release(&og);
+  ogg_packet_release(&op);
   return 0;
 }
 
@@ -1214,7 +1390,7 @@
   
   /* which bitstream section does this time offset occur in? */
   for(link=vf->links-1;link>=0;link--){
-    pcm_total-=vf->pcmlengths[link];
+    pcm_total-=vf->pcmlengths[link*2+1];
     time_total-=ov_time_total(vf,link);
     if(milliseconds>=time_total)break;
   }
@@ -1241,7 +1417,7 @@
   
   /* which bitstream section does this time offset occur in? */
   for(link=vf->links-1;link>=0;link--){
-    pcm_total-=vf->pcmlengths[link];
+    pcm_total-=vf->pcmlengths[link*2+1];
     time_total-=ov_time_total(vf,link);
     if(milliseconds>=time_total)break;
   }
@@ -1268,11 +1444,9 @@
 
 /* return time offset (milliseconds) of next PCM sample to be read */
 ogg_int64_t ov_time_tell(OggVorbis_File *vf){
-  /* translate time to PCM position and call ov_pcm_seek */
-
   int link=0;
   ogg_int64_t pcm_total=0;
-  ogg_int64_t time_total=0;
+  ogg_int64_t time_total=0.f;
   
   if(vf->ready_state<OPENED)return(OV_EINVAL);
   if(vf->seekable){
@@ -1281,7 +1455,7 @@
   
     /* which bitstream section does this time offset occur in? */
     for(link=vf->links-1;link>=0;link--){
-      pcm_total-=vf->pcmlengths[link];
+      pcm_total-=vf->pcmlengths[link*2+1];
       time_total-=ov_time_total(vf,link);
       if(vf->pcm_offset>=pcm_total)break;
     }
@@ -1369,16 +1543,18 @@
   if(vf->ready_state<OPENED)return(OV_EINVAL);
 
   while(1){
-    if(vf->ready_state>=STREAMSET){
+    if(vf->ready_state==INITSET){
       samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
       if(samples)break;
     }
 
     /* suck in another packet */
     {
-      int ret=_process_packet(vf,1);
-      if(ret==OV_EOF)return(0);
-      if(ret<=0)return(ret);
+      int ret=_fetch_and_process_packet(vf,1,1);
+      if(ret==OV_EOF)
+	return(0);
+      if(ret<=0)
+	return(ret);
     }
 
   }
@@ -1391,18 +1567,18 @@
 
     if(channels==1){
       if(samples>(bytes_req/2))
-	samples=bytes_req/2;      
+        samples=bytes_req/2;      
     }else{
       if(samples>(bytes_req/4))
-	samples=bytes_req/4;
+        samples=bytes_req/4;
     }
     
     for(i=0;i<channels;i++) { /* It's faster in this order */
       ogg_int32_t *src=pcm[i];
       short *dest=((short *)buffer)+i;
       for(j=0;j<samples;j++) {
-	*dest=CLIP_TO_15(src[j]>>9);
-	dest+=channels;
+        *dest=CLIP_TO_15(src[j]>>9);
+        dest+=channels;
       }
     }
     
@@ -1414,7 +1590,3 @@
     return(samples);
   }
 }
-
-
-
-

<p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list