Finished all unit tests for framing; passes all tests
authorMonty <xiphmont@xiph.org>
Thu, 22 Jul 1999 10:52:11 +0000 (10:52 +0000)
committerMonty <xiphmont@xiph.org>
Thu, 22 Jul 1999 10:52:11 +0000 (10:52 +0000)
Monty 19990722

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

lib/codec.h
lib/framing.c

index a4c8f35..f1bef8b 100644 (file)
@@ -71,7 +71,7 @@ typedef struct {
   long header_len;
   unsigned char *body;
   long body_len;
-} vorbis_page;
+} ogg_page;
 
 typedef struct {
  
@@ -111,7 +111,7 @@ typedef struct {
   long    pageno;
   size64  pcmpos;
 
-} vorbis_stream_state;
+} ogg_stream_state;
 
 typedef struct {
   unsigned char *packet;
@@ -121,10 +121,10 @@ typedef struct {
 
   size64 pcm_pos;
 
-} vorbis_packet;
+} ogg_packet;
 
 typedef struct {
-  char *data;
+  unsigned char *data;
   int storage;
   int fill;
   int returned;
@@ -132,11 +132,11 @@ typedef struct {
   int unsynced;
   int headerbytes;
   int bodybytes;
-} vorbis_sync_state;
+} ogg_sync_state;
 
 /* libvorbis encodes in two abstraction layers; first we perform DSP
    and produce a packet (see docs/analysis.txt).  The packet is then
-   coded into a framed bitstream by the second layer (see
+   coded into a framed OggSquish bitstream by the second layer (see
    docs/framing.txt).  Decode is the reverse process; we sync/frame
    the bitstream and extract individual packets, then decode the
    packet back into PCM audio.
@@ -146,53 +146,52 @@ typedef struct {
    packetization aren't necessary as they're provided by the transport
    and the streaming layer is not used */
 
-/* ENCODING PRIMITIVES: analysis/DSP layer **************************/
+/* OggSquish BITSREAM PRIMITIVES: encoding **************************/
 
-extern int vorbis_analysis_init(vorbis_dsp_state *vd,vorbis_info *i);
-extern void vorbis_dsp_state_free(vorbis_dsp_state *vd);
-extern int vorbis_analysis_input(vorbis_dsp_state *vd,double **pcm,int vals);
-extern int vorbis_analysis(vorbis_dsp_state *vd,vorbis_packet *vp);
-
-/* GENERAL PRIMITIVES: packet streaming layer ***********************/
+extern int    ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
+extern int    ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
 
-extern int vorbis_stream_init(vorbis_stream_state *vs,int serialno);
-extern int vorbis_stream_clear(vorbis_stream_state *vs);
-extern int vorbis_stream_destroy(vorbis_stream_state *vs);
-extern int vorbis_stream_eof(vorbis_stream_state *vs);
+/* OggSquish BITSREAM PRIMITIVES: decoding **************************/
 
-extern int vorbis_page_version(vorbis_page *vg);
-extern int vorbis_page_continued(vorbis_page *vg);
-extern int vorbis_page_bos(vorbis_page *vg);
-extern int vorbis_page_eos(vorbis_page *vg);
-extern size64 vorbis_page_pcmpos(vorbis_page *vg);
-extern int vorbis_page_serialno(vorbis_page *vg);
-extern int vorbis_page_pageno(vorbis_page *vg);
+extern int    ogg_sync_init(ogg_sync_state *oy);
+extern int    ogg_sync_clear(ogg_sync_state *oy);
+extern int    ogg_sync_destroy(ogg_sync_state *oy);
+extern int    ogg_sync_reset(ogg_sync_state *oy);
 
-/* ENCODING PRIMITIVES: packet streaming layer **********************/
+extern char  *ogg_sync_buffer(ogg_sync_state *oy, long size);
+extern int    ogg_sync_wrote(ogg_sync_state *oy, long bytes);
+extern int    ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
+extern int    ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
+extern int    ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
 
-extern int vorbis_stream_encode(vorbis_stream_state *vs,vorbis_packet *vp);
-extern int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg);
+/* OggSquish BITSREAM PRIMITIVES: general ***************************/
 
-/* DECODING PRIMITIVES: packet streaming layer **********************/
+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 int    ogg_stream_destroy(ogg_stream_state *os);
+extern int    ogg_stream_eof(ogg_stream_state *os);
 
-extern int vorbis_sync_init(vorbis_sync_state *vs);
-extern int vorbis_sync_clear(vorbis_sync_state *vs);
-extern int vorbis_sync_destroy(vorbis_sync_state *vs);
+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 size64 ogg_page_frameno(ogg_page *og);
+extern int    ogg_page_serialno(ogg_page *og);
+extern int    ogg_page_pageno(ogg_page *og);
 
-extern char *vorbis_decode_buffer(vorbis_sync_state *vs, long size);
-extern int vorbis_decode_wrote(vorbis_sync_state *vs, long bytes);
-extern int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg);
-extern int vorbis_decode_page(vorbis_stream_state *vs, vorbis_page *vg);
-extern int vorbis_stream_packet(vorbis_stream_state *vs,vorbis_packet *vp);
+/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/
 
-extern int vorbis_sync_reset(vorbis_sync_state *vs);
-extern int vorbis_stream_reset(vorbis_stream_state *vs);
+extern int  vorbis_analysis_init(vorbis_dsp_state *vd,vorbis_info *vi);
+extern void vorbis_dsp_state_free(vorbis_dsp_state *vd);
+extern int  vorbis_analysis_input(vorbis_dsp_state *vd,double **pcm,int vals);
+extern int  vorbis_analysis(vorbis_dsp_state *vd,ogg_packet *op);
 
-/* DECODING PRIMITIVES: synthesis layer *****************************/
+/* Vorbis PRIMITIVES: synthesis layer *******************************/
 
-extern int vorbis_synthesis_info(vorbis_dsp_state *vd,vorbis_info *vi);
-extern int vorbis_synthesis(vorbis_dsp_state *vd,vorbis_packet *vp);
-extern int vorbis_synthesis_output(vorbis_dsp_state *vd,double **pcm);
+extern int  vorbis_synthesis_info(vorbis_dsp_state *vd,vorbis_info *vi);
+extern int  vorbis_synthesis_packet(vorbis_dsp_state *vd,ogg_packet *op);
+extern int  vorbis_synthesis_output(vorbis_dsp_state *vd,double **pcm);
 
 #endif
 
index 1a9fdb1..3000d8f 100644 (file)
  *                                                                  *
  ********************************************************************
 
- function: code raw Vorbis packets into framed vorbis stream and
-           decode vorbis streams back into raw packets
+ function: code raw [Vorbis] packets into framed OggSquish stream and
+           decode Ogg streams back into raw packets
  author: Monty <xiphmont@mit.edu>
  modifications by: Monty
- last modification date: Jul 13 1999
+ last modification date: Jul 22 1999
 
  note: The CRC code is directly derived from public domain code by
  Ross Williams (ross@guest.adelaide.edu.au).  See framing.txt for
 #include <string.h>
 #include "codec.h"
 
-/* A complete description of Vorbis framing exists in docs/framing.txt */
+/* A complete description of Ogg framing exists in docs/framing.html */
 
-int vorbis_page_version(vorbis_page *vg){
-  return((int)(vg->header[4]));
+int ogg_page_version(ogg_page *og){
+  return((int)(og->header[4]));
 }
 
-int vorbis_page_continued(vorbis_page *vg){
-  return((int)(vg->header[5]&0x01));
+int ogg_page_continued(ogg_page *og){
+  return((int)(og->header[5]&0x01));
 }
 
-int vorbis_page_bos(vorbis_page *vg){
-  return((int)(vg->header[5]&0x02));
+int ogg_page_bos(ogg_page *og){
+  return((int)(og->header[5]&0x02));
 }
 
-int vorbis_page_eos(vorbis_page *vg){
-  return((int)(vg->header[5]&0x04));
+int ogg_page_eos(ogg_page *og){
+  return((int)(og->header[5]&0x04));
 }
 
-size64 vorbis_page_pcmpos(vorbis_page *vg){
-  char *page=vg->header;
-  size64 pcmpos=page[13];
-  pcmpos= (pcmpos<<8)|page[12];
-  pcmpos= (pcmpos<<8)|page[11];
-  pcmpos= (pcmpos<<8)|page[10];
-  pcmpos= (pcmpos<<8)|page[9];
-  pcmpos= (pcmpos<<8)|page[8];
-  pcmpos= (pcmpos<<8)|page[7];
-  pcmpos= (pcmpos<<8)|page[6];
+size64 ogg_page_frameno(ogg_page *og){
+  unsigned char *page=og->header;
+  size64 pcmpos=page[13]&(0xff);
+  pcmpos= (pcmpos<<8)|(page[12]&0xff);
+  pcmpos= (pcmpos<<8)|(page[11]&0xff);
+  pcmpos= (pcmpos<<8)|(page[10]&0xff);
+  pcmpos= (pcmpos<<8)|(page[9]&0xff);
+  pcmpos= (pcmpos<<8)|(page[8]&0xff);
+  pcmpos= (pcmpos<<8)|(page[7]&0xff);
+  pcmpos= (pcmpos<<8)|(page[6]&0xff);
   return(pcmpos);
 }
 
-int vorbis_page_serialno(vorbis_page *vg){
-  return(vg->header[14] |
-        (vg->header[15]<<8) |
-        (vg->header[16]<<16) |
-        (vg->header[17]<<24));
+int ogg_page_serialno(ogg_page *og){
+  return(og->header[14] |
+        (og->header[15]<<8) |
+        (og->header[16]<<16) |
+        (og->header[17]<<24));
 }
  
-int vorbis_page_pageno(vorbis_page *vg){
-  return(vg->header[18] |
-        (vg->header[19]<<8) |
-        (vg->header[20]<<16) |
-        (vg->header[21]<<24));
+int ogg_page_pageno(ogg_page *og){
+  return(og->header[18] |
+        (og->header[19]<<8) |
+        (og->header[20]<<16) |
+        (og->header[21]<<24));
 }
 
 /* helper to initialize lookup for direct-table CRC */
@@ -77,7 +77,7 @@ int vorbis_page_pageno(vorbis_page *vg){
 static unsigned size32 crc_lookup[256];
 static int crc_ready=0;
 
-static unsigned size32 _vorbis_crc_entry(unsigned long index){
+static unsigned size32 _ogg_crc_entry(unsigned long index){
   int           i;
   unsigned long r;
 
@@ -96,73 +96,73 @@ static unsigned size32 _vorbis_crc_entry(unsigned long index){
 /* mind this in threaded code; sync_init and stream_init call it.
    It's thread safe only after the first time it returns */
 
-static void _vorbis_crc_init(void){
+static void _ogg_crc_init(void){
   if(!crc_ready){
     /* initialize the crc_lookup table */
     int i;
     for (i=0;i<256;i++)
-      crc_lookup[i]=_vorbis_crc_entry((unsigned long)i);
+      crc_lookup[i]=_ogg_crc_entry((unsigned long)i);
     crc_ready=0;
   }
 }
 
 /* init the encode/decode logical stream state */
 
-int vorbis_stream_init(vorbis_stream_state *vs,int serialno){
-  if(vs){
-    memset(vs,0,sizeof(vorbis_stream_state));
-    vs->body_storage=16*1024;
-    vs->body_data=malloc(vs->body_storage*sizeof(char));
+int ogg_stream_init(ogg_stream_state *os,int serialno){
+  if(os){
+    memset(os,0,sizeof(ogg_stream_state));
+    os->body_storage=16*1024;
+    os->body_data=malloc(os->body_storage*sizeof(char));
 
-    vs->lacing_storage=1024;
-    vs->lacing_vals=malloc(vs->lacing_storage*sizeof(int));
-    vs->pcm_vals=malloc(vs->lacing_storage*sizeof(size64));
+    os->lacing_storage=1024;
+    os->lacing_vals=malloc(os->lacing_storage*sizeof(int));
+    os->pcm_vals=malloc(os->lacing_storage*sizeof(size64));
 
     /* initialize the crc_lookup table if not done */
-    _vorbis_crc_init();
+    _ogg_crc_init();
 
-    vs->serialno=serialno;
+    os->serialno=serialno;
 
     return(0);
   }
   return(-1);
 } 
 
-/* _clear does not free vs, only the non-flat storage within */
-int vorbis_stream_clear(vorbis_stream_state *vs){
-  if(vs){
-    if(vs->body_data)free(vs->body_data);
-    if(vs->lacing_vals)free(vs->lacing_vals);
-    if(vs->pcm_vals)free(vs->pcm_vals);
+/* _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)free(os->body_data);
+    if(os->lacing_vals)free(os->lacing_vals);
+    if(os->pcm_vals)free(os->pcm_vals);
 
-    memset(vs,0,sizeof(vorbis_stream_state));    
+    memset(os,0,sizeof(ogg_stream_state));    
   }
   return(0);
 } 
 
-int vorbis_stream_destroy(vorbis_stream_state *vs){
-  if(vs){
-    vorbis_stream_clear(vs);
-    free(vs);
+int ogg_stream_destroy(ogg_stream_state *os){
+  if(os){
+    ogg_stream_clear(os);
+    free(os);
   }
   return(0);
 } 
 
-/* Helpers for vorbis_stream_encode; this keeps the structure and
+/* Helpers for ogg_stream_encode; this keeps the structure and
    what's happening fairly clear */
 
-static void _vs_body_expand(vorbis_stream_state *vs,int needed){
-  if(vs->body_storage<=vs->body_fill+needed){
-    vs->body_storage+=(needed+1024);
-    vs->body_data=realloc(vs->body_data,vs->body_storage);
+static void _os_body_expand(ogg_stream_state *os,int needed){
+  if(os->body_storage<=os->body_fill+needed){
+    os->body_storage+=(needed+1024);
+    os->body_data=realloc(os->body_data,os->body_storage);
   }
 }
 
-static void _vs_lacing_expand(vorbis_stream_state *vs,int needed){
-  if(vs->lacing_storage<=vs->lacing_fill+needed){
-    vs->lacing_storage+=(needed+32);
-    vs->lacing_vals=realloc(vs->lacing_vals,vs->lacing_storage*sizeof(int));
-    vs->pcm_vals=realloc(vs->pcm_vals,vs->lacing_storage*sizeof(size64));
+static void _os_lacing_expand(ogg_stream_state *os,int needed){
+  if(os->lacing_storage<=os->lacing_fill+needed){
+    os->lacing_storage+=(needed+32);
+    os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int));
+    os->pcm_vals=realloc(os->pcm_vals,os->lacing_storage*sizeof(size64));
   }
 }
 
@@ -170,116 +170,117 @@ static void _vs_lacing_expand(vorbis_stream_state *vs,int needed){
 /* Direct table CRC; note that this will be faster in the future if we
    perform the checksum silmultaneously with other copies */
 
-static void _vs_checksum(vorbis_page *vg){
+static void _os_checksum(ogg_page *og){
   unsigned size32 crc_reg=0;
   int i;
 
-  for(i=0;i<vg->header_len;i++)
-    crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^vg->header[i]];
-  for(i=0;i<vg->body_len;i++)
-    crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^vg->body[i]];
+  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]];
   
-  vg->header[22]=crc_reg&0xff;
-  vg->header[23]=(crc_reg>>8)&0xff;
-  vg->header[24]=(crc_reg>>16)&0xff;
-  vg->header[25]=(crc_reg>>24)&0xff;
+  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;
 }
 
 /* submit data to the internal buffer of the framing engine */
-int vorbis_stream_encode(vorbis_stream_state *vs,vorbis_packet *vp){
-  int lacing_vals=vp->bytes/255+1,i;
+int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
+  int lacing_vals=op->bytes/255+1,i;
 
   /* make sure we have the buffer storage */
-  _vs_body_expand(vs,vp->bytes);
-  _vs_lacing_expand(vs,lacing_vals);
+  _os_body_expand(os,op->bytes);
+  _os_lacing_expand(os,lacing_vals);
 
   /* Copy in the submitted packet.  Yes, the copy is a waste; this is
      the liability of overly clean abstraction for the time being.  It
      will actually be fairly easy to eliminate the extra copy in the
      future */
 
-  memcpy(vs->body_data+vs->body_fill,vp->packet,vp->bytes);
-  vs->body_fill+=vp->bytes;
+  memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
+  os->body_fill+=op->bytes;
 
   /* Store lacing vals for this packet */
   for(i=0;i<lacing_vals-1;i++){
-    vs->lacing_vals[vs->lacing_fill+i]=255;
-    vs->pcm_vals[vs->lacing_fill+i]=vp->pcm_pos;
+    os->lacing_vals[os->lacing_fill+i]=255;
+    os->pcm_vals[os->lacing_fill+i]=os->pcmpos;
   }
-  vs->lacing_vals[vs->lacing_fill+i]=(vp->bytes)%255;
-  vs->pcm_vals[vs->lacing_fill+i]=vp->pcm_pos;
+  os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
+  os->pcmpos=os->pcm_vals[os->lacing_fill+i]=op->pcm_pos;
 
   /* flag the first segment as the beginning of the packet */
-  vs->lacing_vals[vs->lacing_fill]|= 0x100;
+  os->lacing_vals[os->lacing_fill]|= 0x100;
 
-  vs->lacing_fill+=lacing_vals;
+  os->lacing_fill+=lacing_vals;
 
-  if(vp->e_o_s)vs->e_o_s=1;
+  if(op->e_o_s)os->e_o_s=1;
 
   return(0);
 }
 
 /* This constructs pages from buffered packet segments.  The pointers
 returned are to static buffers; do not free. The returned buffers are
-good only until the next call (using the same vs) */
+good only until the next call (using the same os) */
 
-int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg){
+int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
   int i;
 
-  if(vs->body_returned){
+  if(os->body_returned){
     /* advance packet data according to the body_returned pointer. We
        had to keep it around to return a pointer into the buffer last
        call */
 
-    vs->body_fill-=vs->body_returned;
-    memmove(vs->body_data,vs->body_data+vs->body_returned,
-           (vs->body_fill-vs->body_returned)*sizeof(char));
-    vs->body_returned=0;
+    os->body_fill-=os->body_returned;
+    if(os->body_fill)
+      memmove(os->body_data,os->body_data+os->body_returned,
+             os->body_fill*sizeof(char));
+    os->body_returned=0;
   }
 
-  if((vs->e_o_s&&vs->lacing_fill) || 
-     vs->body_fill > 4096 || 
-     vs->lacing_fill>=255){
+  if((os->e_o_s&&os->lacing_fill) || 
+     os->body_fill > 4096 || 
+     os->lacing_fill>=255){
     int vals=0,bytes=0;
-    int maxvals=(vs->lacing_fill>255?255:vs->lacing_fill);
+    int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
     long acc=0;
-    size64 pcm_pos=vs->pcm_vals[0];
+    size64 pcm_pos=os->pcm_vals[0];
 
     /* construct a page */
     /* decide how many segments to include */
     for(vals=0;vals<maxvals;vals++){
       if(acc>4096)break;
-      acc+=vs->lacing_vals[vals]&0x0ff;
-      if((vs->lacing_vals[vals]&0x0ff)<255)pcm_pos=vs->pcm_vals[vals];
+      acc+=os->lacing_vals[vals]&0x0ff;
+      if((os->lacing_vals[vals]&0x0ff)<255)pcm_pos=os->pcm_vals[vals];
     }
 
     /* construct the header in temp storage */
-    memcpy(vs->header,"OggS",4);
+    memcpy(os->header,"OggS",4);
 
     /* stream structure version */
-    vs->header[4]=0x00;
+    os->header[4]=0x00;
 
     
-    vs->header[5]=0x00;
+    os->header[5]=0x00;
     /* continued packet flag? */
-    if((vs->lacing_vals[0]&0x100)==0)vs->header[5]|=0x01;
+    if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
     /* first page flag? */
-    if(vs->b_o_s==0)vs->header[5]|=0x02;
+    if(os->b_o_s==0)os->header[5]|=0x02;
     /* last page flag? */
-    if(vs->e_o_s && vs->lacing_fill==vals)vs->header[5]|=0x04;
-    vs->b_o_s=1;
+    if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
+    os->b_o_s=1;
 
     /* 64 bits of PCM position */
     for(i=6;i<14;i++){
-      vs->header[i]=(pcm_pos&0xff);
+      os->header[i]=(pcm_pos&0xff);
       pcm_pos>>=8;
     }
 
     /* 32 bits of stream serial number */
     {
-      long serialno=vs->serialno;
+      long serialno=os->serialno;
       for(i=14;i<18;i++){
-       vs->header[i]=(serialno&0xff);
+       os->header[i]=(serialno&0xff);
        serialno>>=8;
       }
     }
@@ -287,40 +288,40 @@ int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg){
     /* 32 bits of page counter (we have both counter and page header
        because this val can roll over) */
     {
-      long pageno=vs->pageno++;
+      long pageno=os->pageno++;
       for(i=18;i<22;i++){
-       vs->header[i]=(pageno&0xff);
+       os->header[i]=(pageno&0xff);
        pageno>>=8;
       }
     }
 
     /* zero for computation; filled in later */
-    vs->header[22]=0;
-    vs->header[23]=0;
-    vs->header[24]=0;
-    vs->header[25]=0;
+    os->header[22]=0;
+    os->header[23]=0;
+    os->header[24]=0;
+    os->header[25]=0;
 
     /* segment table */
-    vs->header[26]=vals&0xff;
+    os->header[26]=vals&0xff;
     for(i=0;i<vals;i++)
-      bytes+=vs->header[i+27]=(vs->lacing_vals[i]&0xff);
+      bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
       
     /* advance the lacing data and set the body_returned pointer */
 
-    vs->lacing_fill-=vals;
-    memmove(vs->lacing_vals,vs->lacing_vals+vals,vs->lacing_fill*sizeof(int));
-    memmove(vs->pcm_vals,vs->pcm_vals+vals,vs->lacing_fill*sizeof(size64));
-    vs->body_returned=bytes;
+    os->lacing_fill-=vals;
+    memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int));
+    memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(size64));
+    os->body_returned=bytes;
 
-    /* set pointers in the vorbis_page struct */
-    vg->header=vs->header;
-    vg->header_len=vs->header_fill=vals+27;
-    vg->body=vs->body_data;
-    vg->body_len=bytes;
+    /* set pointers in the ogg_page struct */
+    og->header=os->header;
+    og->header_len=os->header_fill=vals+27;
+    og->body=os->body_data;
+    og->body_len=bytes;
 
     /* calculate the checksum */
 
-    _vs_checksum(vg);
+    _os_checksum(og);
 
     return(1);
   }
@@ -329,73 +330,73 @@ int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg){
   return(0);
 }
 
-int vorbis_stream_eof(vorbis_stream_state *vs){
-  return vs->e_o_s;
+int ogg_stream_eof(ogg_stream_state *os){
+  return os->e_o_s;
 }
 
 /* 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 vorbis_decode_buffer().  The app either copies into the
+   using ogg_decode_buffer().  The app either copies into the
    buffer, or passes it directly to read(), etc.  We then call
-   vorbis_decode_wrote() to tell how many bytes we just added.
-
-   Pages are returned (pointers into the buffer in vorbis_sync_state)
-   by vorbis_decode_stream().  The page is then submitted to
-   vorbis_decode_page() along with the appropriate
-   vorbis_stream_state* (ie, matching serialno).  We then get raw
-   packets out calling vorbis_stream_packet() with a
-   vorbis_stream_state.  See the 'frame-prog.txt' docs for details and
+   ogg_decode_wrote() to tell how many bytes we just added.
+
+   Pages are returned (pointers into the buffer in ogg_sync_state)
+   by ogg_decode_stream().  The page is then submitted to
+   ogg_decode_page() along with the appropriate
+   ogg_stream_state* (ie, matching serialno).  We then get raw
+   packets out calling ogg_stream_packet() with a
+   ogg_stream_state.  See the 'frame-prog.txt' docs for details and
    example code. */
 
 /* initialize the struct to a known state */
-int vorbis_sync_init(vorbis_sync_state *vs){
-  if(vs){
-    memset(vs,0,sizeof(vorbis_sync_state));
-    _vorbis_crc_init();
+int ogg_sync_init(ogg_sync_state *oy){
+  if(oy){
+    memset(oy,0,sizeof(ogg_sync_state));
+    _ogg_crc_init();
   }
   return(0);
 }
 
 /* clear non-flat storage within */
-int vorbis_sync_clear(vorbis_sync_state *vs){
-  if(vs){
-    if(vs->data)free(vs->data);
-    vorbis_sync_init(vs);
+int ogg_sync_clear(ogg_sync_state *oy){
+  if(oy){
+    if(oy->data)free(oy->data);
+    ogg_sync_init(oy);
   }
   return(0);
 }
 
-char *vorbis_decode_buffer(vorbis_sync_state *vs, long size){
+char *ogg_sync_buffer(ogg_sync_state *oy, long size){
 
   /* first, clear out any space that has been previously returned */
-  if(vs->returned){
-    vs->fill-=vs->returned;
-    if(vs->fill-vs->returned>0)
-      memmove(vs->data,vs->data+vs->returned,
-             (vs->fill-vs->returned)*sizeof(char));
-    vs->returned=0;
+  if(oy->returned){
+    oy->fill-=oy->returned;
+    if(oy->fill>0)
+      memmove(oy->data,oy->data+oy->returned,
+             (oy->fill)*sizeof(char));
+    oy->returned=0;
   }
 
-  if(size>vs->storage-vs->fill){
+  if(size>oy->storage-oy->fill){
     /* We need to extend the internal buffer */
-    long newsize=size+vs->fill+4096; /* an extra page to be nice */
+    long newsize=size+oy->fill+4096; /* an extra page to be nice */
 
-    if(vs->data)
-      vs->data=realloc(vs->data,newsize);
+    if(oy->data)
+      oy->data=realloc(oy->data,newsize);
     else
-      vs->data=malloc(newsize);
-    vs->storage=newsize;
+      oy->data=malloc(newsize);
+    oy->storage=newsize;
   }
 
   /* expose a segment at least as large as requested at the fill mark */
-  return(vs->data+vs->fill);
+  return(oy->data+oy->fill);
 }
 
-int vorbis_decode_wrote(vorbis_sync_state *vs, long bytes){
-  if(vs->fill+bytes>vs->storage)return(-1);
-  vs->fill+=bytes;
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
+  if(oy->fill+bytes>oy->storage)return(-1);
+  oy->fill+=bytes;
   return(0);
 }
 
@@ -406,17 +407,17 @@ int vorbis_decode_wrote(vorbis_sync_state *vs, long bytes){
    Returns pointers into buffered data; invalidated by next call to
    _stream, _clear, _init, or _buffer */
 
-int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){
+int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
 
   /* all we need to do is verify a page at the head of the stream
      buffer.  If it doesn't verify, we look for the next potential
      frame */
 
   while(1){
-    char *page=vs->data+vs->returned;
-    long bytes=vs->fill-vs->returned;
+    unsigned char *page=oy->data+oy->returned;
+    long bytes=oy->fill-oy->returned;
       
-    if(vs->headerbytes==0){
+    if(oy->headerbytes==0){
       int headerbytes,i;
       if(bytes<27)return(0); /* not enough for a header */
 
@@ -429,27 +430,27 @@ int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){
       /* count up body length in the segment table */
 
       for(i=0;i<page[26];i++)
-       vs->bodybytes+=page[27+i];
-      vs->headerbytes=headerbytes;
+       oy->bodybytes+=page[27+i];
+      oy->headerbytes=headerbytes;
     }
     
-    if(vs->bodybytes+vs->headerbytes>bytes)return(0);
+    if(oy->bodybytes+oy->headerbytes>bytes)return(0);
 
     /* The whole test page is buffered.  Verify the checksum */
     {
       /* Grab the checksum bytes, set the header field to zero */
       char chksum[4];
-      vorbis_page lvg;
+      ogg_page log;
       
       memcpy(chksum,page+22,4);
       memset(page+22,0,4);
       
       /* set up a temp page struct and recompute the checksum */
-      lvg.header=page;
-      lvg.header_len=vs->headerbytes;
-      lvg.body=page+vs->headerbytes;
-      lvg.body_len=vs->bodybytes;
-      _vs_checksum(&lvg);
+      log.header=page;
+      log.header_len=oy->headerbytes;
+      log.body=page+oy->headerbytes;
+      log.body_len=oy->bodybytes;
+      _os_checksum(&log);
        
       /* Compare */
       if(memcmp(chksum,page+22,4)){
@@ -463,33 +464,33 @@ int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){
       }
     }
        
-    vg->header=page;
-    vg->header_len=vs->headerbytes;
-    vg->body=page+vs->headerbytes;
-    vg->body_len=vs->bodybytes;
+    og->header=page;
+    og->header_len=oy->headerbytes;
+    og->body=page+oy->headerbytes;
+    og->body_len=oy->bodybytes;
     
-    vs->unsynced=0;
-    vs->returned+=vs->headerbytes+vs->bodybytes;
-    vs->headerbytes=0;
-    vs->bodybytes=0;
+    oy->unsynced=0;
+    oy->returned+=oy->headerbytes+oy->bodybytes;
+    oy->headerbytes=0;
+    oy->bodybytes=0;
 
     return(1);
 
   sync_fail:
     
-    vs->headerbytes=0;
-    vs->bodybytes=0;
+    oy->headerbytes=0;
+    oy->bodybytes=0;
 
     /* search for possible capture */
     
     page=memchr(page+1,'O',bytes-1);
     if(page)
-      vs->returned=page-vs->data;
+      oy->returned=page-oy->data;
     else
-      vs->returned=vs->fill;
+      oy->returned=oy->fill;
 
-    if(!vs->unsynced){
-      vs->unsynced=1;
+    if(!oy->unsynced){
+      oy->unsynced=1;
       return(-1);
     }
 
@@ -501,62 +502,66 @@ int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){
 /* add the incoming page to the stream state; we decompose the page
    into packet segments here as well. */
 
-int vorbis_decode_page(vorbis_stream_state *vs, vorbis_page *vg){
-  unsigned char *header=vg->header;
-  unsigned char *body=vg->body;
-  long            bodysize=vg->body_len;
-  int segptr=0;
-
-  int version=vorbis_page_version(vg);
-  int continued=vorbis_page_continued(vg);
-  int bos=vorbis_page_bos(vg);
-  int eos=vorbis_page_eos(vg);
-  size64 pcmpos=vorbis_page_pcmpos(vg);
-  int serialno=vorbis_page_serialno(vg);
-  int pageno=vorbis_page_pageno(vg);
+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;
+
+  int version=ogg_page_version(og);
+  int continued=ogg_page_continued(og);
+  int bos=ogg_page_bos(og);
+  int eos=ogg_page_eos(og);
+  size64 pcmpos=ogg_page_frameno(og);
+  int serialno=ogg_page_serialno(og);
+  int pageno=ogg_page_pageno(og);
   int segments=header[26];
   
   /* clean up 'returned data' */
   {
-    long lr=vs->lacing_returned;
-    long br=vs->body_returned;
+    long lr=os->lacing_returned;
+    long br=os->body_returned;
 
     /* body data */
-    if(vs->body_fill-br)
-      memmove(vs->body_data,vs->body_data+br,vs->body_fill-br);
-    vs->body_fill-=br;
-    vs->body_returned=0;
+    if(br){
+      os->body_fill-=br;
+      if(os->body_fill)
+       memmove(os->body_data,os->body_data+br,os->body_fill);
+      os->body_returned=0;
+    }
 
-    /* segment table */
-    if(vs->lacing_fill-lr){
-      memmove(vs->lacing_vals,vs->lacing_vals+lr,
-             (vs->lacing_fill-lr)*sizeof(int));
-      memmove(vs->pcm_vals,vs->pcm_vals+lr,
-             (vs->lacing_fill-lr)*sizeof(size64));
+    if(lr){
+      /* segment table */
+      if(os->lacing_fill-lr){
+       memmove(os->lacing_vals,os->lacing_vals+lr,
+               (os->lacing_fill-lr)*sizeof(int));
+       memmove(os->pcm_vals,os->pcm_vals+lr,
+               (os->lacing_fill-lr)*sizeof(size64));
+      }
+      os->lacing_fill-=lr;
+      os->lacing_packet-=lr;
+      os->lacing_returned=0;
     }
-    vs->lacing_fill-=lr;
-    vs->lacing_packet-=lr;
-    vs->lacing_returned=0;
   }
 
   /* check the serial number */
-  if(serialno!=vs->serialno)return(-1);
+  if(serialno!=os->serialno)return(-1);
   if(version>0)return(-1);
 
-  _vs_lacing_expand(vs,segments+1);
+  _os_lacing_expand(os,segments+1);
 
   /* are we in sequence? */
-  if(pageno!=vs->pageno){
+  if(pageno!=os->pageno){
     int i;
 
     /* unroll previous partial packet (if any) */
-    for(i=vs->lacing_packet;i<vs->lacing_fill;i++)
-      vs->body_fill-=vs->lacing_vals[i]&0xff;
-    vs->lacing_fill=vs->lacing_packet;
+    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 */
-    vs->lacing_vals[vs->lacing_fill++]=0x400;
-    vs->lacing_packet++;
+    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 */
@@ -575,101 +580,113 @@ int vorbis_decode_page(vorbis_stream_state *vs, vorbis_page *vg){
   }
   
   if(bodysize){
-    _vs_body_expand(vs,bodysize);
-    memcpy(vs->body_data+vs->body_fill,body,bodysize);
-    vs->body_fill+=bodysize;
+    _os_body_expand(os,bodysize);
+    memcpy(os->body_data+os->body_fill,body,bodysize);
+    os->body_fill+=bodysize;
   }
 
-  while(segptr<segments){
-    int val=header[27+segptr];
-    vs->lacing_vals[vs->lacing_fill]=val;
-    vs->pcm_vals[vs->lacing_fill]=pcmpos;
-
-    if(bos){
-      vs->lacing_vals[vs->lacing_fill]|=0x100;
-      bos=0;
+  {
+    int saved=-1;
+    while(segptr<segments){
+      int val=header[27+segptr];
+      os->lacing_vals[os->lacing_fill]=val;
+      os->pcm_vals[os->lacing_fill]=-1;
+      
+      if(bos){
+       os->lacing_vals[os->lacing_fill]|=0x100;
+       bos=0;
+      }
+      
+      if(val<255)saved=os->lacing_fill;
+      
+      os->lacing_fill++;
+      segptr++;
+      
+      if(val<255)os->lacing_packet=os->lacing_fill;
+    }
+  
+    /* set the pcmpos on the last pcmval of the last full packet */
+    if(saved!=-1){
+      os->pcm_vals[saved]=pcmpos;
     }
 
-    vs->lacing_fill++;
-    segptr++;
-
-    if(val<255)vs->lacing_packet=vs->lacing_fill;
   }
+
   if(eos){
-    vs->e_o_s=1;
-    if(vs->lacing_fill>0)
-      vs->lacing_vals[vs->lacing_fill-1]|=0x200;
+    os->e_o_s=1;
+    if(os->lacing_fill>0)
+      os->lacing_vals[os->lacing_fill-1]|=0x200;
   }
 
-  vs->pageno=pageno;
+  os->pageno=pageno+1;
 
   return(0);
 }
 
 /* clear things to an initial state.  Good to call, eg, before seeking */
-int vorbis_sync_reset(vorbis_sync_state *vs){
-  vs->fill=0;
-  vs->returned=0;
-  vs->unsynced=0;
-  vs->headerbytes=0;
-  vs->bodybytes=0;
+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);
 }
 
-int vorbis_stream_reset(vorbis_stream_state *vs){
-  vs->body_fill=0;
-  vs->body_returned=0;
+int ogg_stream_reset(ogg_stream_state *os){
+  os->body_fill=0;
+  os->body_returned=0;
 
-  vs->lacing_fill=0;
-  vs->lacing_packet=0;
-  vs->lacing_returned=0;
+  os->lacing_fill=0;
+  os->lacing_packet=0;
+  os->lacing_returned=0;
 
-  vs->header_fill=0;
+  os->header_fill=0;
 
-  vs->e_o_s=0;
-  vs->b_o_s=0;
-  vs->pageno=0;
-  vs->pcmpos=0;
+  os->e_o_s=0;
+  os->b_o_s=0;
+  os->pageno=0;
+  os->pcmpos=0;
 
   return(0);
 }
 
-int vorbis_stream_packet(vorbis_stream_state *vs,vorbis_packet *vp){
+int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
 
   /* 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=vs->lacing_returned;
+  int ptr=os->lacing_returned;
 
-  if(vs->lacing_packet<=ptr)return(0);
-  if(vs->lacing_vals[ptr]&=0x400){
+  if(os->lacing_packet<=ptr)return(0);
+  if(os->lacing_vals[ptr]&0x400){
     /* We lost sync here; let the app know */
-    vs->lacing_returned++;
+    os->lacing_returned++;
     return(-1);
   }
 
   /* Gather the whole packet. We'll have no holes or a partial packet */
   {
-    int size=vs->lacing_vals[ptr]&0xff;
+    int size=os->lacing_vals[ptr]&0xff;
     int bytes=0;
 
-    vp->packet=vs->body_data+vs->body_returned;
-    vp->e_o_s=vs->lacing_vals[ptr]&0x200; /* last packet of the stream? */
-    vp->b_o_s=vs->lacing_vals[ptr]&0x100; /* first packet of the stream? */
+    op->packet=os->body_data+os->body_returned;
+    op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
+    op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
     bytes+=size;
 
     while(size==255){
-      int val=vs->lacing_vals[++ptr];
+      int val=os->lacing_vals[++ptr];
       size=val&0xff;
-      if(val&0x200)vp->e_o_s=0x200;
+      if(val&0x200)op->e_o_s=0x200;
       bytes+=size;
     }
-    vp->pcm_pos=vs->pcm_vals[ptr];
-    vp->bytes=bytes;
+    op->pcm_pos=os->pcm_vals[ptr];
+    op->bytes=bytes;
 
-    vs->body_returned+=bytes;
-    vs->lacing_returned=ptr+1;
+    os->body_returned+=bytes;
+    os->lacing_returned=ptr+1;
   }
   return(1);
 }
@@ -677,37 +694,135 @@ int vorbis_stream_packet(vorbis_stream_state *vs,vorbis_packet *vp){
 #ifdef _V_SELFTEST
 #include <stdio.h>
 
-void test_pack(vorbis_stream_state *vs,int *pl, int **headers){
+ogg_stream_state os_en, os_de;
+ogg_sync_state oy;
+
+void checkpacket(ogg_packet *op,int len, int no, int pos){
+  long j;
+  if(op->bytes!=len){
+    fprintf(stderr,"incorrect packet length!\n");
+    exit(1);
+  }
+  if(op->pcm_pos!=pos){
+    fprintf(stderr,"incorrect packet position!\n");
+    exit(1);
+  }
+
+  /* Test data */
+  for(j=0;j<op->bytes;j++)
+    if(op->packet[j]!=((j+no)&0xff)){
+      fprintf(stderr,"body data mismatch at pos %ld: %x!=%lx!\n\n",
+             j,op->packet[j],(j+no)&0xff);
+      exit(1);
+    }
+}
+
+void check_page(unsigned char *data,int *header,ogg_page *og){
+  long j;
+  /* Test data */
+  for(j=0;j<og->body_len;j++)
+    if(og->body[j]!=data[j]){
+      fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
+             j,data[j],og->body[j]);
+      exit(1);
+    }
+
+  /* Test header */
+  for(j=0;j<og->header_len;j++){
+    if(og->header[j]!=header[j]){
+      fprintf(stderr,"header content mismatch at pos %ld:\n",j);
+      for(j=0;j<header[26]+27;j++)
+       fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
+      fprintf(stderr,"\n");
+      exit(1);
+    }
+  }
+  if(og->header_len!=header[26]+27){
+    fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
+           og->header_len,header[26]+27);
+    exit(1);
+  }
+}
+
+void print_header(ogg_page *og){
+  int j;
+  fprintf(stderr,"\nHEADER:\n");
+  fprintf(stderr,"  capture: %c %c %c %c  version: %d  flags: %x\n",
+         og->header[0],og->header[1],og->header[2],og->header[3],
+         (int)og->header[4],(int)og->header[5]);
+
+  fprintf(stderr,"  pcmpos: %d  serialno: %d  pageno: %d\n",
+         (og->header[9]<<24)|(og->header[8]<<16)|
+         (og->header[7]<<8)|og->header[6],
+         (og->header[17]<<24)|(og->header[16]<<16)|
+         (og->header[15]<<8)|og->header[14],
+         (og->header[21]<<24)|(og->header[20]<<16)|
+         (og->header[19]<<8)|og->header[18]);
+
+  fprintf(stderr,"  checksum: %02x:%02x:%02x:%02x\n  segments: %d (",
+         (int)og->header[22],(int)og->header[23],
+         (int)og->header[24],(int)og->header[25],
+         (int)og->header[26]);
+
+  for(j=27;j<og->header_len;j++)
+    fprintf(stderr,"%d ",(int)og->header[j]);
+  fprintf(stderr,")\n\n");
+}
+
+void copy_page(ogg_page *og){
+  char *temp=malloc(og->header_len);
+  memcpy(temp,og->header,og->header_len);
+  og->header=temp;
+
+  temp=malloc(og->body_len);
+  memcpy(temp,og->body,og->body_len);
+  og->body=temp;
+}
+
+void error(void){
+  fprintf(stderr,"error!\n");
+  exit(1);
+}
+
+void test_pack(int *pl, int **headers){
   unsigned char *data=malloc(1024*1024); /* for scripted test cases only */
   long inptr=0;
   long outptr=0;
-  long pcm_pos=0;
-  int i,j,packets,pageno=0;
+  long deptr=0;
+  long depacket=0;
+  long pcm_pos=7;
+  int i,j,packets,pageno=0,pageout=0;
+  int eosflag=0;
+  int bosflag=0;
+
+  ogg_stream_reset(&os_en);
+  ogg_stream_reset(&os_de);
+  ogg_sync_reset(&oy);
 
   for(packets=0;;packets++)if(pl[packets]==-1)break;
 
   for(i=0;i<packets;i++){
     /* construct a test packet */
-    vorbis_packet vp;
+    ogg_packet op;
     int len=pl[i];
     
-    vp.packet=data+inptr;
-    vp.bytes=len;
-    vp.e_o_s=(pl[i+1]<0?1:0);
-    vp.pcm_pos=pcm_pos;
+    op.packet=data+inptr;
+    op.bytes=len;
+    op.e_o_s=(pl[i+1]<0?1:0);
+    op.pcm_pos=pcm_pos;
 
     pcm_pos+=1024;
 
     for(j=0;j<len;j++)data[inptr++]=i+j;
 
     /* submit the test packet */
-    vorbis_stream_encode(vs,&vp);
+    ogg_stream_packetin(&os_en,&op);
 
     /* retrieve any finished pages */
     {
-      vorbis_page vg;
+      ogg_page og;
       
-      while(vorbis_stream_page(vs,&vg)){
+      while(ogg_stream_pageout(&os_en,&og)){
        /* We have a page.  Check it carefully */
 
        fprintf(stderr,"%d, ",pageno);
@@ -717,31 +832,68 @@ void test_pack(vorbis_stream_state *vs,int *pl, int **headers){
          exit(1);
        }
 
-       /* Test data */
-       for(j=0;j<vg.body_len;j++)
-       if(vg.body[j]!=(data+outptr)[j]){
-         fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
-                 outptr+j,(data+outptr)[j],vg.body[j]);
-         exit(1);
-       }
-       outptr+=vg.body_len;
-
-       /* Test header */
-       for(j=0;j<vg.header_len;j++){
-         if(vg.header[j]!=headers[pageno][j]){
-           fprintf(stderr,"header content mismatch at pos %ld:\n",j);
-           for(j=0;j<headers[pageno][26]+27;j++)
-             fprintf(stderr," (%d)%02x:%02x",j,headers[pageno][j],vg.header[j]);
-           fprintf(stderr,"\n");
-           exit(1);
+       check_page(data+outptr,headers[pageno],&og);
+
+       outptr+=og.body_len;
+       pageno++;
+
+       /* have a complete page; submit it to sync/decode */
+
+       {
+         ogg_page og_de;
+         ogg_packet op_de;
+         char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
+         memcpy(buf,og.header,og.header_len);
+         memcpy(buf+og.header_len,og.body,og.body_len);
+         ogg_sync_wrote(&oy,og.header_len+og.body_len);
+
+         while(ogg_sync_pageout(&oy,&og_de)>0){
+           /* got a page.  Happy happy.  Verify that it's good. */
+           
+           check_page(data+deptr,headers[pageout],&og_de);
+           deptr+=og_de.body_len;
+           pageout++;
+
+           /* submit it to deconstitution */
+           ogg_stream_pagein(&os_de,&og_de);
+
+           /* packets out? */
+           while(ogg_stream_packetout(&os_de,&op_de)>0){
+             
+             /* verify the packet! */
+             /* check data */
+             if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
+               fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
+                       depacket);
+               exit(1);
+             }
+             /* check bos flag */
+             if(bosflag==0 && op_de.b_o_s==0){
+               fprintf(stderr,"b_o_s flag not set on packet!\n");
+               exit(1);
+             }
+             if(bosflag && op_de.b_o_s){
+               fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
+               exit(1);
+             }
+             bosflag=1;
+             depacket+=op_de.bytes;
+             
+             /* check eos flag */
+             if(eosflag){
+               fprintf(stderr,"Multiple decoded packets with eos flag!\n");
+               exit(1);
+             }
+
+             if(op_de.e_o_s)eosflag=1;
+
+             /* check pcmpos flag */
+             if(op_de.pcm_pos!=-1){
+               fprintf(stderr," pcm:%ld ",(long)op_de.pcm_pos);
+             }
+           }
          }
        }
-       if(vg.header_len!=headers[pageno][26]+27){
-         fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
-                 vg.header_len,headers[pageno][26]+27);
-         exit(1);
-       }
-       pageno++;
       }
     }
   }
@@ -750,15 +902,34 @@ void test_pack(vorbis_stream_state *vs,int *pl, int **headers){
     fprintf(stderr,"did not write last page!\n");
     exit(1);
   }
+  if(headers[pageout]!=NULL){
+    fprintf(stderr,"did not decode last page!\n");
+    exit(1);
+  }
   if(inptr!=outptr){
-    fprintf(stderr,"packet data incomplete!\n");
+    fprintf(stderr,"encoded page data incomplete!\n");
+    exit(1);
+  }
+  if(inptr!=deptr){
+    fprintf(stderr,"decoded page data incomplete!\n");
+    exit(1);
+  }
+  if(inptr!=depacket){
+    fprintf(stderr,"decoded packet data incomplete!\n");
+    exit(1);
+  }
+  if(!eosflag){
+    fprintf(stderr,"Never got a packet with EOS set!\n");
     exit(1);
   }
   fprintf(stderr,"ok.\n");
 }
 
 int main(void){
-  vorbis_stream_state vs;
+
+  ogg_stream_init(&os_en,0x04030201);
+  ogg_stream_init(&os_de,0x04030201);
+  ogg_sync_init(&oy);
 
   /* Exercise each code path in the framing code.  Also verify that
      the checksums are working.  */
@@ -766,90 +937,81 @@ int main(void){
   {
     /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
     int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0,
-                  0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
+                  0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0x7e,0xea,0x18,0xd0,
+                  0x46,0x39,0xee,0xcb,
                   14,
                   17,254,255,0,255,1,255,245,255,255,0,
                   255,255,90};
     int *headret[]={head1,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
     fprintf(stderr,"testing basic page encoding... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    test_pack(packets,headret);
   }
 
   {
     /* nil packets; beginning,middle,end */
     int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
 
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0,
-                  0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
+                  0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0xcf,0x70,0xa4,0x1b,
+                  0xf6,0x56,0x56,0x9e,
                   18,
                   0,17,254,255,0,0,255,1,0,255,245,255,255,0,
                   255,255,90,0};
     int *headret[]={head1,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
     fprintf(stderr,"testing basic nil packets... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    test_pack(packets,headret);
   }
 
   {
     /* starting new page with first segment */
     int packets[]={4345,259,255,-1};
 
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
                   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0xe7,0xdc,0x6d,0x09,
+                  0x7e,0x3e,0xa9,0x86,
                   17,
                   255,255,255,255,255,255,255,255,
                   255,255,255,255,255,255,255,255,255};
 
-    int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
-                  0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head2[] = {0x4f,0x67,0x67,0x53,0,0x05,
+                  0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,1,0,0,0,
-                  0x5f,0x54,0x07,0x69,
+                  0x28,0x26,0x8c,0x6a,
                   5,
                   10,255,4,255,0};
     int *headret[]={head1,head2,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
     fprintf(stderr,"testing single-packet page span... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    test_pack(packets,headret);
   }
 
   {
-    /* starting new page with first segment */
     int packets[]={100,4345,259,255,-1};
 
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
-                  0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+                  0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0x6f,0xac,0x43,0x67,
+                  0x9f,0x45,0x89,0x8c,
                   17,
                   100,255,255,255,255,255,255,255,255,
                   255,255,255,255,255,255,255,255};
 
-    int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
-                  0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head2[] = {0x4f,0x67,0x67,0x53,0,0x05,
+                  0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,1,0,0,0,
-                  0xe7,0xa3,0x34,0x53,
+                  0xe6,0x35,0xfc,0xb7,
                   6,
                   255,10,255,4,255,0};
     int *headret[]={head1,head2,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
     fprintf(stderr,"testing multi-packet page span... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    test_pack(packets,headret);
   }
 
 
@@ -889,10 +1051,10 @@ int main(void){
                   10,10,10,10,10,10,10,10,
                   10,10,10,10,10,10,10,50,-1};
 
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
-                  0x00,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+                  0x07,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0xb1,0xd0,0xab,0xbc,
+                  0x2f,0xe5,0xf5,0x43,
                   255,
                   10,10,10,10,10,10,10,10,
                   10,10,10,10,10,10,10,10,
@@ -927,18 +1089,16 @@ int main(void){
                   10,10,10,10,10,10,10,10,
                   10,10,10,10,10,10,10};
 
-    int head2[] = {0x4f,0x67,0x67,0x53,0,0x01,
-                  0x00,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+    int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
+                  0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,1,0,0,0,
-                  0xb1,0x1e,0x4f,0x41,
+                  0x46,0x8b,0x88,0x90,
                   1,
                   50};
     int *headret[]={head1,head2,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
     fprintf(stderr,"testing max packet segments... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    test_pack(packets,headret);
   }
 
   {
@@ -946,64 +1106,330 @@ int main(void){
 
     int packets[]={100,9000,259,255,-1};
 
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
-                  0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+                  0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0x6f,0xac,0x43,0x67,
+                  0x9f,0x45,0x89,0x8c,
                   17,
                   100,255,255,255,255,255,255,255,255,
                   255,255,255,255,255,255,255,255};
 
-    int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
-                  0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head2[] = {0x4f,0x67,0x67,0x53,0,0x01,
+                  0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,1,0,0,0,
-                  0x65,0x4e,0xbd,0x96,
+                  0xaf,0x9d,0xf1,0x76,
                   17,
                   255,255,255,255,255,255,255,255,
                   255,255,255,255,255,255,255,255,255};
 
-    int head3[] = {0x4f,0x67,0x67,0x53,0,0x02,
-                  0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
+                  0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,2,0,0,0,
-                  0x84,0x86,0x86,0xf4,
+                  0xe1,0x61,0x9f,0xbd,
                   7,
                   255,255,75,255,4,255,0};
     int *headret[]={head1,head2,head3,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
     fprintf(stderr,"testing very large packets... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    test_pack(packets,headret);
   }
 
   {
-    /* nil page.  why not? */
+    /* term only page.  why not? */
 
     int packets[]={100,4080,-1};
 
-    int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
-                  0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+                  0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,0,0,0,0,
-                  0x6f,0xac,0x43,0x67,
+                  0x9f,0x45,0x89,0x8c,
                   17,
                   100,255,255,255,255,255,255,255,255,
                   255,255,255,255,255,255,255,255};
 
-    int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
-                  0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+    int head2[] = {0x4f,0x67,0x67,0x53,0,0x05,
+                  0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
                   0x01,0x02,0x03,0x04,1,0,0,0,
-                  0x71,0xc8,0x17,0x8c,
+                  0xf1,0x29,0xfc,0x4c,
                   1,0};
 
     int *headret[]={head1,head2,NULL};
     
-    vorbis_stream_init(&vs,0x04030201);
-    fprintf(stderr,"testing nil page... ");
-    test_pack(&vs,packets,headret);
-    vorbis_stream_clear(&vs);
+    fprintf(stderr,"testing zero data page (1 nil packet)... ");
+    test_pack(packets,headret);
   }
 
-  
+
+
+  {
+    /* build a bunch of pages for testing */
+    unsigned char *data=malloc(1024*1024);
+    int pl[]={100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
+    int inptr=0,i,j;
+    ogg_page og[4];
+    
+    ogg_stream_reset(&os_en);
+
+    for(i=0;pl[i]!=-1;i++){
+      ogg_packet op;
+      int len=pl[i];
+      
+      op.packet=data+inptr;
+      op.bytes=len;
+      op.e_o_s=(pl[i+1]<0?1:0);
+      op.pcm_pos=(i+1)*1000;
+
+      for(j=0;j<len;j++)data[inptr++]=i+j;
+      ogg_stream_packetin(&os_en,&op);
+    }
+
+    free(data);
+
+    /* retrieve finished pages */
+    for(i=0;i<4;i++){
+      if(ogg_stream_pageout(&os_en,&og[i])==0){
+       fprintf(stderr,"Too few pages output building sync tests!\n");
+       exit(1);
+      }
+      copy_page(&og[i]);
+    }
+
+    /* Test lost pages on pagein/packetout: no rollback */
+    {
+      ogg_page temp;
+      ogg_packet test;
+
+      fprintf(stderr,"Testing loss of pages... ");
+
+      ogg_sync_reset(&oy);
+      ogg_stream_reset(&os_de);
+      for(i=0;i<4;i++){
+       memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+              og[i].header_len);
+       ogg_sync_wrote(&oy,og[i].header_len);
+       memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+       ogg_sync_wrote(&oy,og[i].body_len);
+      }
+
+      ogg_sync_pageout(&oy,&temp);
+      ogg_stream_pagein(&os_de,&temp);
+      ogg_sync_pageout(&oy,&temp);
+      /* skip */
+      ogg_sync_pageout(&oy,&temp);
+      ogg_stream_pagein(&os_de,&temp);
+
+      /* do we get the expected results/packets? */
+      
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,100,0,-1);
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,4079,1,2000);
+      if(ogg_stream_packetout(&os_de,&test)!=-1){
+       fprintf(stderr,"Error: loss of page did not return error\n");
+       exit(1);
+      }
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,76,4,-1);
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,34,5,-1);
+      fprintf(stderr,"ok.\n");
+    }
+
+    /* Test lost pages on pagein/packetout: rollback with continuation */
+    {
+      ogg_page temp;
+      ogg_packet test;
+
+      fprintf(stderr,"Testing loss of pages (rollback required)... ");
+
+      ogg_sync_reset(&oy);
+      ogg_stream_reset(&os_de);
+      for(i=0;i<4;i++){
+       memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+              og[i].header_len);
+       ogg_sync_wrote(&oy,og[i].header_len);
+       memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+       ogg_sync_wrote(&oy,og[i].body_len);
+      }
+
+      ogg_sync_pageout(&oy,&temp);
+      ogg_stream_pagein(&os_de,&temp);
+      ogg_sync_pageout(&oy,&temp);
+      ogg_stream_pagein(&os_de,&temp);
+      ogg_sync_pageout(&oy,&temp);
+      /* skip */
+      ogg_sync_pageout(&oy,&temp);
+      ogg_stream_pagein(&os_de,&temp);
+
+      /* do we get the expected results/packets? */
+      
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,100,0,-1);
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,4079,1,2000);
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,2956,2,3000);
+      if(ogg_stream_packetout(&os_de,&test)!=-1){
+       fprintf(stderr,"Error: loss of page did not return error\n");
+       exit(1);
+      }
+      if(ogg_stream_packetout(&os_de,&test)!=1)error();
+      checkpacket(&test,300,12,13000);
+      fprintf(stderr,"ok.\n");
+    }
+    
+    /* the rest only test sync */
+    {
+      ogg_page og_de;
+      /* Test fractional page inputs: incomplete capture */
+      fprintf(stderr,"Testing sync on partial inputs... ");
+      ogg_sync_reset(&oy);
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header,
+            3);
+      ogg_sync_wrote(&oy,3);
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      
+      /* Test fractional page inputs: incomplete fixed header */
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header+3,
+            20);
+      ogg_sync_wrote(&oy,20);
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      
+      /* Test fractional page inputs: incomplete header */
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header+23,
+            5);
+      ogg_sync_wrote(&oy,5);
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      
+      /* Test fractional page inputs: incomplete body */
+      
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header+28,
+            og[0].header_len-28);
+      ogg_sync_wrote(&oy,og[0].header_len-28);
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      
+      memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,1000);
+      ogg_sync_wrote(&oy,1000);
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      
+      memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body+1000,
+            og[0].body_len-1000);
+      ogg_sync_wrote(&oy,og[0].body_len-1000);
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+      
+      fprintf(stderr,"ok.\n");
+    }
+
+    /* Test fractional page inputs: page + incomplete capture */
+    {
+      ogg_page og_de;
+      fprintf(stderr,"Testing sync on 1+partial inputs... ");
+      ogg_sync_reset(&oy); 
+
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header,
+            og[0].header_len);
+      ogg_sync_wrote(&oy,og[0].header_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+            og[0].body_len);
+      ogg_sync_wrote(&oy,og[0].body_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+            20);
+      ogg_sync_wrote(&oy,20);
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
+            og[1].header_len-20);
+      ogg_sync_wrote(&oy,og[1].header_len-20);
+      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+            og[1].body_len);
+      ogg_sync_wrote(&oy,og[1].body_len);
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+      fprintf(stderr,"ok.\n");
+    }
+    
+    /* Test recapture: garbage + page */
+    {
+      ogg_page og_de;
+      fprintf(stderr,"Testing search for capture... ");
+      ogg_sync_reset(&oy); 
+      
+      /* 'garbage' */
+      memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+            og[0].body_len);
+      ogg_sync_wrote(&oy,og[0].body_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header,
+            og[0].header_len);
+      ogg_sync_wrote(&oy,og[0].header_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+            og[0].body_len);
+      ogg_sync_wrote(&oy,og[0].body_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+            20);
+      ogg_sync_wrote(&oy,20);
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
+            og[1].header_len-20);
+      ogg_sync_wrote(&oy,og[1].header_len-20);
+      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+            og[1].body_len);
+      ogg_sync_wrote(&oy,og[1].body_len);
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+      fprintf(stderr,"ok.\n");
+    }
+
+    /* Test recapture: page + garbage + page */
+    {
+      ogg_page og_de;
+      fprintf(stderr,"Testing recapture... ");
+      ogg_sync_reset(&oy); 
+
+      memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header,
+            og[0].header_len);
+      ogg_sync_wrote(&oy,og[0].header_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+            og[0].body_len);
+      ogg_sync_wrote(&oy,og[0].body_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+            og[1].header_len);
+      ogg_sync_wrote(&oy,og[1].header_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+            og[1].header_len);
+      ogg_sync_wrote(&oy,og[1].header_len);
+
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+      memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+            og[1].body_len-5);
+      ogg_sync_wrote(&oy,og[1].body_len-5);
+
+      memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+            og[2].header_len);
+      ogg_sync_wrote(&oy,og[2].header_len);
+
+      memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+            og[2].body_len);
+      ogg_sync_wrote(&oy,og[2].body_len);
+
+      if(ogg_sync_pageout(&oy,&og_de)>0)error();
+      if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+      fprintf(stderr,"ok.\n");
+    }
+  }    
 
   return(0);
 }