misc/libtremor/tremor/vorbisfile.c
branchwebgl
changeset 9521 8054d9d775fd
parent 9282 92af50454cf2
parent 9519 b8b5c82eb61b
child 9950 2759212a27de
--- a/misc/libtremor/tremor/vorbisfile.c	Fri Oct 11 11:55:31 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1587 +0,0 @@
-/********************************************************************
- *                                                                  *
- * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
- *                                                                  *
- * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
- * 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-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.6 2003/03/30 23:40:56 xiphmont Exp $
-
- ********************************************************************/
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <math.h>
-
-#include "ivorbiscodec.h"
-#include "ivorbisfile.h"
-
-#include "misc.h"
-
-/* A 'chained bitstream' is a Vorbis bitstream that contains more than
-   one logical bitstream arranged end to end (the only form of Ogg
-   multiplexing allowed in a Vorbis bitstream; grouping [parallel
-   multiplexing] is not allowed in Vorbis) */
-
-/* A Vorbis file can be played beginning to end (streamed) without
-   worrying ahead of time about chaining (see decoder_example.c).  If
-   we have the whole file, however, and want random access
-   (seeking/scrubbing) or desire to know the total length/time of a
-   file, we need to account for the possibility of chaining. */
-
-/* We can handle things a number of ways; we can determine the entire
-   bitstream structure right off the bat, or find pieces on demand.
-   This example determines and caches structure for the entire
-   bitstream, but builds a virtual decoder on the fly when moving
-   between links in the chain. */
-
-/* There are also different ways to implement seeking.  Enough
-   information exists in an Ogg bitstream to seek to
-   sample-granularity positions in the output.  Or, one can seek by
-   picking some portion of the stream roughly in the desired area if
-   we only want coarse navigation through the stream. */
-
-/*************************************************************************
- * Many, many internal helpers.  The intention is not to be confusing; 
- * rampant duplication and monolithic function implementation would be 
- * 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 */
-static long _get_data(OggVorbis_File *vf){
-  errno=0;
-  if(vf->datasource){
-    unsigned 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 && errno)return(-1);
-    return(bytes);
-  }else
-    return(0);
-}
-
-/* save a tiny smidge of verbosity to make the code more readable */
-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);
-  }else{
-    /* shouldn't happen unless someone writes a broken callback */
-    return;
-  }
-}
-
-/* The read/seek functions track absolute position within the stream */
-
-/* from the head of the stream, get the next page.  boundary specifies
-   if the function is allowed to fetch more data from the stream (and
-   how much) or only use internally buffered data.
-
-   boundary: -1) unbounded search
-              0) read no additional data; use cached only
-	      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 
-
-              produces a refcounted page */
-
-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);
-    
-    if(more<0){
-      /* skipped n bytes */
-      vf->offset-=more;
-    }else{
-      if(more==0){
-	/* send more paramedics */
-	if(!boundary)return(OV_FALSE);
-	{
-	  long ret=_get_data(vf);
-	  if(ret==0)return(OV_EOF);
-	  if(ret<0)return(OV_EREAD);
-	}
-      }else{
-	/* got a page.  Return the offset at the page beginning,
-           advance the internal offset past the page end */
-	ogg_int64_t ret=vf->offset;
-	vf->offset+=more;
-	return(ret);
-	
-      }
-    }
-  }
-}
-
-/* find the latest page beginning before the current stream cursor
-   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 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<end){
-      ret=_get_next_page(vf,og,end-vf->offset);
-      if(ret==OV_EREAD)return(OV_EREAD);
-      if(ret<0){
-	break;
-      }else{
-	offset=ret;
-      }
-    }
-  }
-
-  /* we have the offset.  Actually snork and hold the page now */
-  _seek_helper(vf,offset);
-  ret=_get_next_page(vf,og,CHUNKSIZE);
-  if(ret<0)
-    /* this shouldn't be possible */
-    return(OV_EFAULT);
-
-  return(offset);
-}
-
-/* finds each bitstream link one at a time using a bisection search
-   (has to begin by knowing the offset of the lb's initial page).
-   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,
-				    ogg_int64_t begin,
-				    ogg_int64_t searched,
-				    ogg_int64_t end,
-				    ogg_uint32_t currentno,
-				    long m){
-  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){
-    ogg_int64_t bisect;
-    
-    if(endsearched-searched<CHUNKSIZE){
-      bisect=searched;
-    }else{
-      bisect=(searched+endsearched)/2;
-    }
-    
-    _seek_helper(vf,bisect);
-    ret=_get_next_page(vf,&og,-1);
-    if(ret==OV_EREAD)return(OV_EREAD);
-    if(ret<0 || ogg_page_serialno(&og)!=currentno){
-      endsearched=bisect;
-      if(ret>=0)next=ret;
-    }else{
-      searched=ret+og.header_len+og.body_len;
-    }
-    ogg_page_release(&og);
-  }
-
-  _seek_helper(vf,next);
-  ret=_get_next_page(vf,&og,-1);
-  if(ret==OV_EREAD)return(OV_EREAD);
-  
-  if(searched>=end || ret<0){
-    ogg_page_release(&og);
-    vf->links=m+1;
-    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 */
-/* 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){
-    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;
-  }
-
-  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
-     Ogg bitstream is in fact Vorbis data */
-  
-  vorbis_info_init(vi);
-  vorbis_comment_init(vc);
-  
-  i=0;
-  while(i<3){
-    ogg_stream_pagein(vf->os,og_ptr);
-    while(i<3){
-      int result=ogg_stream_packetout(vf->os,&op);
-      if(result==0)break;
-      if(result==-1){
-	ret=OV_EBADHEADER;
-	goto bail_header;
-      }
-      if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
-	goto bail_header;
-      }
-      i++;
-    }
-    if(i<3)
-      if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
-	ret=OV_EBADHEADER;
-	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);
-  vf->ready_state=OPENED;
-
-  return ret;
-}
-
-/* last step of the OggVorbis_File initialization; get all the
-   vorbis_info structs and PCM positions.  Only called by the seekable
-   initialization (local stream storage is hacked slightly; pay
-   attention to how that's done) */
-
-/* this is void and does not propogate errors up because we want to be
-   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, 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 */
-
-      _seek_helper(vf,vf->offsets[i]);
-      if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
-    	vf->dataoffsets[i]=-1;
-      }else{
-	vf->dataoffsets[i]=vf->offset;
-      }
-    }
-
-    /* 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 */
-    {
-      ogg_int64_t end=vf->offsets[i+1];
-      _seek_helper(vf,end);
-
-      while(1){
-	ret=_get_prev_page(vf,&og);
-	if(ret<0){
-	  /* this should not be possible */
-	  vorbis_info_clear(vf->vi+i);
-	  vorbis_comment_clear(vf->vc+i);
-	  break;
-	}
-	if(ogg_page_granulepos(&og)!=-1){
-	  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){
-  if(vf->ready_state!=STREAMSET)return;
-  if(vf->seekable){
-    vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);
-  }else{
-    vorbis_synthesis_init(&vf->vd,vf->vi);
-  }    
-  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){
-  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 */
-  /* we can seek, so set out learning all about this file */
-  (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
-  vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
-  
-  /* 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)return(end);
-
-  /* more than one logical bitstream? */
-  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)return(OV_EREAD);
-
-  }else{
-
-    /* Only one logical bitstream */
-    if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
-
-  }
-
-  /* the initial header memory is referenced by vf after; don't free it */
-  _prefetch_all_headers(vf,dataoffset);
-  return(ov_raw_seek(vf,0));
-}
-
-/* clear out the current logical bitstream decoder */ 
-static void _decode_clear(OggVorbis_File *vf){
-  vorbis_dsp_clear(&vf->vd);
-  vorbis_block_clear(&vf->vb);
-  vf->ready_state=OPENED;
-}
-
-/* fetch and process a packet.  Handles the case where we're at a
-   bitstream boundary and dumps the decoding machine.  If the decoding
-   machine is unloaded, it loads it.  It also keeps pcm_offset up to
-   date (seek and read both use this.  seek uses a special hack with
-   readp). 
-
-   return: <0) error, OV_HOLE (lost packet) or OV_EOF
-            0) need more data (only if readp==0)
-	    1) got a packet 
-*/
-
-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 */
-  while(1){
-    
-    /* process a packet if we can.  If the machine isn't loaded,
-       neither is a page */
-    if(vf->ready_state==INITSET){
-      while(1) {
-	int result=ogg_stream_packetout(vf->os,&op);
-	ogg_int64_t granulepos;
-
-	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,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;
-	    }
-	  
-	    /* update the pcm offset. */
-	    if(granulepos!=-1 && !op.e_o_s){
-	      int link=(vf->seekable?vf->current_link:0);
-	      int i,samples;
-	    
-	      /* this packet has a pcm_offset on it (the last packet
-	         completed on a page carries the offset) After processing
-	         (above), we know the pcm position of the *last* sample
-	         ready to be returned. Find the offset of the *first*
-
-	         As an aside, this trick is inaccurate if we begin
-	         reading anew right at the last page; the end-of-stream
-	         granulepos declares the last frame in the stream, and the
-	         last packet of the last page may be a partial frame.
-	         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*2+1];
-	      vf->pcm_offset=granulepos;
-	    }
-	    ret=1;
-	    goto cleanup;
-	  }
-	}
-	else 
-	  break;
-      }
-    }
-
-    if(vf->ready_state>=OPENED){
-      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){
-	    vorbis_info_clear(vf->vi);
-	    vorbis_comment_clear(vf->vc);
-	  }
-	}
-      }
-    }
-
-    /* Do we need to load a new machine before submitting the page? */
-    /* This is different in the seekable and non-seekable cases.  
-
-       In the seekable case, we already have all the header
-       information loaded and cached; we just initialize the machine
-       with it and continue on our merry way.
-
-       In the non-seekable (streaming) case, we'll only be at a
-       boundary if we just left the previous logical bitstream and
-       we're now nominally at the header of the next bitstream
-    */
-
-    if(vf->ready_state!=INITSET){ 
-      int link;
-
-      if(vf->ready_state<STREAMSET){
-	if(vf->seekable){
-	  vf->current_serialno=ogg_page_serialno(&og);
-	  
-	  /* match the serialno to bitstream section.  We use this rather than
-	     offset positions to avoid problems near logical bitstream
-	     boundaries */
-	  for(link=0;link<vf->links;link++)
-	    if(vf->serialnos[link]==vf->current_serialno)break;
-	  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_reset_serialno(vf->os,vf->current_serialno);
-	  vf->ready_state=STREAMSET;
-	  
-	}else{
-	  /* we're streaming */
-	  /* fetch the three header packets, build the info struct */
-	  
-	  int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
-	  if(ret) goto cleanup;
-	  vf->current_link++;
-	  link=0;
-	}
-      }
-      
-      _make_decode_ready(vf);
-    }
-    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,off,whence);
-}
-
-static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
-		     long ibytes, ov_callbacks callbacks){
-  int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
-  int ret;
-
-  memset(vf,0,sizeof(*vf));
-  vf->datasource=f;
-  vf->callbacks = callbacks;
-
-  /* init the framing state */
-  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){
-    unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes);
-    memcpy(buffer,initial,ibytes);
-    ogg_sync_wrote(vf->oy,ibytes);
-  }
-
-  /* can we seek? Stevens suggests the seek test was portable */
-  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=_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;
-    ov_clear(vf);
-  }else if(vf->ready_state < PARTOPEN)
-    vf->ready_state=PARTOPEN;
-  return(ret);
-}
-
-static int _ov_open2(OggVorbis_File *vf){
-  if(vf->ready_state < OPENED)
-    vf->ready_state=OPENED;
-  if(vf->seekable){
-    int ret=_open_seekable2(vf);
-    if(ret){
-      vf->datasource=NULL;
-      ov_clear(vf);
-    }
-    return(ret);
-  }
-  return 0;
-}
-
-
-/* clear out the OggVorbis_File struct */
-int ov_clear(OggVorbis_File *vf){
-  if(vf){
-    vorbis_block_clear(&vf->vb);
-    vorbis_dsp_clear(&vf->vd);
-    ogg_stream_destroy(vf->os);
-    
-    if(vf->vi && vf->links){
-      int i;
-      for(i=0;i<vf->links;i++){
-	vorbis_info_clear(vf->vi+i);
-	vorbis_comment_clear(vf->vc+i);
-      }
-      _ogg_free(vf->vi);
-      _ogg_free(vf->vc);
-    }
-    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
-    if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
-    if(vf->serialnos)_ogg_free(vf->serialnos);
-    if(vf->offsets)_ogg_free(vf->offsets);
-    ogg_sync_destroy(vf->oy);
-
-    if(vf->datasource && vf->callbacks.close_func)
-        (vf->callbacks.close_func)(vf->datasource);
-    memset(vf,0,sizeof(*vf));
-  }
-#ifdef DEBUG_LEAKS
-  _VDBG_dump();
-#endif
-  return(0);
-}
-
-/* inspects the OggVorbis file and finds/documents all the logical
-   bitstreams contained in it.  Tries to be tolerant of logical
-   bitstream sections that are truncated/woogie. 
-
-   return: -1) error
-            0) OK
-*/
-
-int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
-    ov_callbacks callbacks){
-  int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
-  if(ret)return ret;
-  return _ov_open2(vf);
-}
-
-int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
-  ov_callbacks callbacks = {
-    (size_t (*)(void *, size_t, size_t, void *))  fread,
-    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
-    (int (*)(void *))                             fclose,
-    (long (*)(void *))                            ftell
-  };
-
-  return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
-}
-  
-/* Only partially open the vorbis file; test for Vorbisness, and load
-   the headers for the first chain.  Do not seek (although test for
-   seekability).  Use ov_test_open to finish opening the file, else
-   ov_clear to close/free it. Same return codes as open. */
-
-int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
-    ov_callbacks callbacks)
-{
-  return _ov_open1(f,vf,initial,ibytes,callbacks);
-}
-
-int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
-  ov_callbacks callbacks = {
-    (size_t (*)(void *, size_t, size_t, void *))  fread,
-    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
-    (int (*)(void *))                             fclose,
-    (long (*)(void *))                            ftell
-  };
-
-  return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
-}
-  
-int ov_test_open(OggVorbis_File *vf){
-  if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
-  return _ov_open2(vf);
-}
-
-/* How many logical bitstreams in this physical bitstream? */
-long ov_streams(OggVorbis_File *vf){
-  return vf->links;
-}
-
-/* Is the FILE * associated with vf seekable? */
-long ov_seekable(OggVorbis_File *vf){
-  return vf->seekable;
-}
-
-/* returns the bitrate for a given logical bitstream or the entire
-   physical bitstream.  If the file is open for random access, it will
-   find the *actual* average bitrate.  If the file is streaming, it
-   returns the nominal bitrate (if set) else the average of the
-   upper/lower bounds (if set) else -1 (unset).
-
-   If you want the actual bitrate field settings, get them from the
-   vorbis_info structs */
-
-long ov_bitrate(OggVorbis_File *vf,int i){
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(i>=vf->links)return(OV_EINVAL);
-  if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
-  if(i<0){
-    ogg_int64_t bits=0;
-    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){
-      /* return the actual bitrate */
-      return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));
-    }else{
-      /* return nominal if set */
-      if(vf->vi[i].bitrate_nominal>0){
-	return vf->vi[i].bitrate_nominal;
-      }else{
-	if(vf->vi[i].bitrate_upper>0){
-	  if(vf->vi[i].bitrate_lower>0){
-	    return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
-	  }else{
-	    return vf->vi[i].bitrate_upper;
-	  }
-	}
-	return(OV_FALSE);
-      }
-    }
-  }
-}
-
-/* returns the actual bitrate since last call.  returns -1 if no
-   additional data to offer since last call (or at beginning of stream),
-   EINVAL if stream is only partially open 
-*/
-long ov_bitrate_instant(OggVorbis_File *vf){
-  int link=(vf->seekable?vf->current_link:0);
-  long ret;
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(vf->samptrack==0)return(OV_FALSE);
-  ret=vf->bittrack/vf->samptrack*vf->vi[link].rate;
-  vf->bittrack=0;
-  vf->samptrack=0;
-  return(ret);
-}
-
-/* Guess */
-long ov_serialnumber(OggVorbis_File *vf,int i){
-  if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
-  if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
-  if(i<0){
-    return(vf->current_serialno);
-  }else{
-    return(vf->serialnos[i]);
-  }
-}
-
-/* returns: total raw (compressed) length of content if i==-1
-            raw (compressed) length of that logical bitstream for i==0 to n
-	    OV_EINVAL if the stream is not seekable (we can't know the length)
-	    or if stream is only partially open
-*/
-ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
-  if(i<0){
-    ogg_int64_t acc=0;
-    int i;
-    for(i=0;i<vf->links;i++)
-      acc+=ov_raw_total(vf,i);
-    return(acc);
-  }else{
-    return(vf->offsets[i+1]-vf->offsets[i]);
-  }
-}
-
-/* returns: total PCM length (samples) of content if i==-1 PCM length
-	    (samples) of 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 
-*/
-ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
-  if(i<0){
-    ogg_int64_t acc=0;
-    int i;
-    for(i=0;i<vf->links;i++)
-      acc+=ov_pcm_total(vf,i);
-    return(acc);
-  }else{
-    return(vf->pcmlengths[i*2+1]);
-  }
-}
-
-/* returns: total milliseconds of content if i==-1
-            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 
-*/
-ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
-  if(i<0){
-    ogg_int64_t acc=0;
-    int i;
-    for(i=0;i<vf->links;i++)
-      acc+=ov_time_total(vf,i);
-    return(acc);
-  }else{
-    return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
-  }
-}
-
-/* seek to an offset relative to the *compressed* data. This also
-   scans packets to update the PCM cursor. It will cross a logical
-   bitstream boundary, but only if it can't get any packets out of the
-   tail of the bitstream we seek to (so no surprises).
-
-   returns zero on success, nonzero on failure */
-
-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->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;
-  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
-     advance the raw cursor past good packets just to get to the first
-     with a granulepos.  That's not equivalent behavior to beginning
-     decoding as immediately after the seek position as possible.
-
-     So, a hack.  We use two stream states; a local scratch state and
-     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
-     because the granulepos on the last page is not necessarily on a
-     packet boundary, and we need to make sure the granpos is
-     correct. 
-  */
-
-  {
-    int lastblock=0;
-    int accblock=0;
-    int thisblock;
-    int eosflag=0;
-
-    work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */
-    while(1){
-      if(vf->ready_state>=STREAMSET){
-	/* snarf/scan a packet if we can */
-	int result=ogg_stream_packetout(work_os,&op);
-      
-	if(result>0){
-
-	  if(vf->vi[vf->current_link].codec_setup){
-	    thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
-	    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);
-	}
-      }
-      
-      if(!lastblock){
-	if(_get_next_page(vf,&og,-1)<0){
-	  vf->pcm_offset=ov_pcm_total(vf,-1);
-	  break;
-	}
-      }else{
-	/* huh?  Bogus stream with packets but no granulepos */
-	vf->pcm_offset=-1;
-	break;
-      }
-      
-      /* has our decoding just traversed a bitstream boundary? */
-      if(vf->ready_state>=STREAMSET)
-	if(vf->current_serialno!=ogg_page_serialno(&og)){
-	  _decode_clear(vf); /* clear out stream state */
-	  ogg_stream_destroy(work_os);
-	}
-
-      if(vf->ready_state<STREAMSET){
-	int link;
-	
-	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 */
- 
-	vf->current_link=link;
-	
-	ogg_stream_reset_serialno(vf->os,vf->current_serialno);
-	ogg_stream_reset_serialno(work_os,vf->current_serialno); 
-	vf->ready_state=STREAMSET;
-	
-      }
-    
-      {
-	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_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_destroy(work_os);
-  _decode_clear(vf);
-  return OV_EBADLINK;
-}
-
-/* Page granularity seek (faster than sample granularity because we
-   don't do the last bit of decode to find a specific sample).
-
-   Seek to the last [granule marked] page preceeding the specified pos
-   location, such that decoding past the returned point will quickly
-   arrive at the requested position. */
-int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
-  int link=-1;
-  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);
-  if(pos<0 || pos>total)return(OV_EINVAL);
- 
-  /* which bitstream section does this pcm offset occur in? */
-  for(link=vf->links-1;link>=0;link--){
-    total-=vf->pcmlengths[link*2+1];
-    if(pos>=total)break;
-  }
-
-  /* search within the logical bitstream for the page with the highest
-     pcm_pos preceeding (or equal to) pos.  There is a danger here;
-     missing pages or incorrect frame number information in the
-     bitstream could make our task impossible.  Account for that (it
-     would be an error condition) */
-
-  /* new search algorithm by HB (Nicholas Vinen) */
-  {
-    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;
-    
-    while(begin<end){
-      ogg_int64_t bisect;
-      
-      if(end-begin<CHUNKSIZE){
-	bisect=begin;
-      }else{
-	/* take a (pretty decent) guess. */
-	bisect=begin + 
-	  (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
-	if(bisect<=begin)
-	  bisect=begin+1;
-      }
-      
-      _seek_helper(vf,bisect);
-    
-      while(begin<end){
-	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;
-	    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=result;  /* raw offset of packet with granulepos */ 
-	    begin=vf->offset; /* raw offset of next page */
-	    begintime=granulepos;
-	    
-	    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=result;
-		bisect-=CHUNKSIZE; /* an endless loop otherwise. */
-		if(bisect<=begin)bisect=begin+1;
-		_seek_helper(vf,bisect);
-	      }else{
-		end=result;
-		endtime=granulepos;
-		break;
-	      }
-	    }
-	  }
-	}
-      }
-    }
-
-    /* found our page. seek to it, update pcm offset. Easier case than
-       raw_seek, don't keep packets preceeding granulepos. */
-    {
-      
-      /* seek */
-      _seek_helper(vf,best);
-      vf->pcm_offset=-1;
-      
-      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){
-	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){
-	    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,result);
-	    }
-	    vf->offset=result;
-	  }
-	}
-	if(result<0){
-	  result = OV_EBADPACKET; 
-	  goto seek_error;
-	}
-	if(op.granulepos!=-1){
-	  vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
-	  if(vf->pcm_offset<0)vf->pcm_offset=0;
-	  vf->pcm_offset+=total;
-	  break;
-	}else
-	  result=ogg_stream_packetout(vf->os,NULL);
-      }
-    }
-  }
-  
-  /* verify result */
-  if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
-    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 (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){
-
-    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;
-      
-      /* 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. */
-      
-      if(op.granulepos>-1){
-	int i;
-	/* always believe the stream markers */
-	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*2+1];
-      }
-	
-      lastblock=thisblock;
-      
-    }else{
-      if(ret<0 && ret!=OV_HOLE)break;
-      
-      /* suck in a new page */
-      if(_get_next_page(vf,&og,-1)<0)break;
-      if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
-      
-      if(vf->ready_state<STREAMSET){
-	int link;
-	
-	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){
-	  ogg_page_release(&og);
-	  ogg_packet_release(&op);
-	  return(OV_EBADLINK);
-	}
-	vf->current_link=link;
-	
-	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);
-    }
-  }
-
-  vf->bittrack=0;
-  vf->samptrack=0;
-  /* discard samples until we reach the desired position. Crossing a
-     logical bitstream boundary with abandon is OK. */
-  while(vf->pcm_offset<pos){
-    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(_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;
-}
-
-/* seek to a playback time relative to the decompressed pcm stream 
-   returns zero on success, nonzero on failure */
-int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
-  /* translate time to PCM position and call ov_pcm_seek */
-
-  int link=-1;
-  ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
-  ogg_int64_t time_total=ov_time_total(vf,-1);
-
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(!vf->seekable)return(OV_ENOSEEK);
-  if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
-  
-  /* which bitstream section does this time offset occur in? */
-  for(link=vf->links-1;link>=0;link--){
-    pcm_total-=vf->pcmlengths[link*2+1];
-    time_total-=ov_time_total(vf,link);
-    if(milliseconds>=time_total)break;
-  }
-
-  /* enough information to convert time offset to pcm offset */
-  {
-    ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
-    return(ov_pcm_seek(vf,target));
-  }
-}
-
-/* page-granularity version of ov_time_seek 
-   returns zero on success, nonzero on failure */
-int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){
-  /* translate time to PCM position and call ov_pcm_seek */
-
-  int link=-1;
-  ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
-  ogg_int64_t time_total=ov_time_total(vf,-1);
-
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(!vf->seekable)return(OV_ENOSEEK);
-  if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
-  
-  /* which bitstream section does this time offset occur in? */
-  for(link=vf->links-1;link>=0;link--){
-    pcm_total-=vf->pcmlengths[link*2+1];
-    time_total-=ov_time_total(vf,link);
-    if(milliseconds>=time_total)break;
-  }
-
-  /* enough information to convert time offset to pcm offset */
-  {
-    ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
-    return(ov_pcm_seek_page(vf,target));
-  }
-}
-
-/* tell the current stream offset cursor.  Note that seek followed by
-   tell will likely not give the set offset due to caching */
-ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  return(vf->offset);
-}
-
-/* return PCM offset (sample) of next PCM sample to be read */
-ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  return(vf->pcm_offset);
-}
-
-/* return time offset (milliseconds) of next PCM sample to be read */
-ogg_int64_t ov_time_tell(OggVorbis_File *vf){
-  int link=0;
-  ogg_int64_t pcm_total=0;
-  ogg_int64_t time_total=0;
-  
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-  if(vf->seekable){
-    pcm_total=ov_pcm_total(vf,-1);
-    time_total=ov_time_total(vf,-1);
-  
-    /* which bitstream section does this time offset occur in? */
-    for(link=vf->links-1;link>=0;link--){
-      pcm_total-=vf->pcmlengths[link*2+1];
-      time_total-=ov_time_total(vf,link);
-      if(vf->pcm_offset>=pcm_total)break;
-    }
-  }
-
-  return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
-}
-
-/*  link:   -1) return the vorbis_info struct for the bitstream section
-                currently being decoded
-           0-n) to request information for a specific bitstream section
-    
-    In the case of a non-seekable bitstream, any call returns the
-    current bitstream.  NULL in the case that the machine is not
-    initialized */
-
-vorbis_info *ov_info(OggVorbis_File *vf,int link){
-  if(vf->seekable){
-    if(link<0)
-      if(vf->ready_state>=STREAMSET)
-	return vf->vi+vf->current_link;
-      else
-      return vf->vi;
-    else
-      if(link>=vf->links)
-	return NULL;
-      else
-	return vf->vi+link;
-  }else{
-    return vf->vi;
-  }
-}
-
-/* grr, strong typing, grr, no templates/inheritence, grr */
-vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
-  if(vf->seekable){
-    if(link<0)
-      if(vf->ready_state>=STREAMSET)
-	return vf->vc+vf->current_link;
-      else
-	return vf->vc;
-    else
-      if(link>=vf->links)
-	return NULL;
-      else
-	return vf->vc+link;
-  }else{
-    return vf->vc;
-  }
-}
-
-/* up to this point, everything could more or less hide the multiple
-   logical bitstream nature of chaining from the toplevel application
-   if the toplevel application didn't particularly care.  However, at
-   the point that we actually read audio back, the multiple-section
-   nature must surface: Multiple bitstream sections do not necessarily
-   have to have the same number of channels or sampling rate.
-
-   ov_read returns the sequential logical bitstream number currently
-   being decoded along with the PCM data in order that the toplevel
-   application can take action on channel/sample rate changes.  This
-   number will be incremented even for streamed (non-seekable) streams
-   (for seekable streams, it represents the actual logical bitstream
-   index within the physical bitstream.  Note that the accessor
-   functions above are aware of this dichotomy).
-
-   input values: buffer) a buffer to hold packed PCM data for return
-		 length) the byte length requested to be placed into buffer
-
-   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
-                   0) EOF
-		   n) number of bytes of PCM actually returned.  The
-		   below works on a packet-by-packet basis, so the
-		   return length is not related to the 'length' passed
-		   in, just guaranteed to fit.
-
-	    *section) set to the logical bitstream number */
-
-long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){
-  int i,j;
-
-  ogg_int32_t **pcm;
-  long samples;
-
-  if(vf->ready_state<OPENED)return(OV_EINVAL);
-
-  while(1){
-    if(vf->ready_state==INITSET){
-      samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
-      if(samples)break;
-    }
-
-    /* suck in another packet */
-    {
-      int ret=_fetch_and_process_packet(vf,1,1);
-      if(ret==OV_EOF)
-	return(0);
-      if(ret<=0)
-	return(ret);
-    }
-
-  }
-
-  if(samples>0){
-  
-    /* yay! proceed to pack data into the byte buffer */
-    
-    long channels=ov_info(vf,-1)->channels;
-
-    if(samples>(bytes_req/(2*channels)))
-      samples=bytes_req/(2*channels);      
-    
-    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;
-      }
-    }
-    
-    vorbis_synthesis_read(&vf->vd,samples);
-    vf->pcm_offset+=samples;
-    if(bitstream)*bitstream=vf->current_link;
-    return(samples*2*channels);
-  }else{
-    return(samples);
-  }
-}