examples/sfexamples/oggvorbiscodec/src/libvorbis/lib/vorbisfile.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
00004  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00005  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00006  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00007  *                                                                  *
00008  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
00009  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
00010  *                                                                  *
00011  ********************************************************************
00012 
00013  function: stdio-based convenience library for opening/seeking/decoding
00014  last mod: $Id: vorbisfile.c 7198 2004-07-21 01:35:06Z msmith $
00015 
00016  ********************************************************************/
00017 
00018 #include <stdlib.h>
00019 #include <stdio.h>
00020 #include <errno.h>
00021 #include <string.h>
00022 #include <math.h>
00023 
00024 #include "vorbis/codec.h"
00025 #include "vorbis/vorbisfile.h"
00026 
00027 #include "os.h"
00028 #include "misc.h"
00029 
00030 /* A 'chained bitstream' is a Vorbis bitstream that contains more than
00031    one logical bitstream arranged end to end (the only form of Ogg
00032    multiplexing allowed in a Vorbis bitstream; grouping [parallel
00033    multiplexing] is not allowed in Vorbis) */
00034 
00035 /* A Vorbis file can be played beginning to end (streamed) without
00036    worrying ahead of time about chaining (see decoder_example.c).  If
00037    we have the whole file, however, and want random access
00038    (seeking/scrubbing) or desire to know the total length/time of a
00039    file, we need to account for the possibility of chaining. */
00040 
00041 /* We can handle things a number of ways; we can determine the entire
00042    bitstream structure right off the bat, or find pieces on demand.
00043    This example determines and caches structure for the entire
00044    bitstream, but builds a virtual decoder on the fly when moving
00045    between links in the chain. */
00046 
00047 /* There are also different ways to implement seeking.  Enough
00048    information exists in an Ogg bitstream to seek to
00049    sample-granularity positions in the output.  Or, one can seek by
00050    picking some portion of the stream roughly in the desired area if
00051    we only want coarse navigation through the stream. */
00052 
00053 /*************************************************************************
00054  * Many, many internal helpers.  The intention is not to be confusing; 
00055  * rampant duplication and monolithic function implementation would be 
00056  * harder to understand anyway.  The high level functions are last.  Begin
00057  * grokking near the end of the file */
00058 
00059 /* read a little more data from the file/pipe into the ogg_sync framer
00060 */
00061 #define CHUNKSIZE 8500 /* a shade over 8k; anyone using pages well
00062                           over 8k gets what they deserve */
00063 static long _get_data(OggVorbis_File *vf){
00064   errno=0;
00065   if(vf->datasource){
00066     char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
00067     long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
00068     if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
00069     if(bytes==0 && errno)return(-1);
00070     return(bytes);
00071   }else
00072     return(0);
00073 }
00074 
00075 /* save a tiny smidge of verbosity to make the code more readable */
00076 static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
00077   if(vf->datasource){ 
00078     (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
00079     vf->offset=offset;
00080     ogg_sync_reset(&vf->oy);
00081   }else{
00082     /* shouldn't happen unless someone writes a broken callback */
00083     return;
00084   }
00085 }
00086 
00087 /* The read/seek functions track absolute position within the stream */
00088 
00089 /* from the head of the stream, get the next page.  boundary specifies
00090    if the function is allowed to fetch more data from the stream (and
00091    how much) or only use internally buffered data.
00092 
00093    boundary: -1) unbounded search
00094               0) read no additional data; use cached only
00095               n) search for a new page beginning for n bytes
00096 
00097    return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
00098               n) found a page at absolute offset n */
00099 
00100 static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
00101                                   ogg_int64_t boundary){
00102   if(boundary>0)boundary+=vf->offset;
00103   while(1){
00104     long more;
00105 
00106     if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
00107     more=ogg_sync_pageseek(&vf->oy,og);
00108     
00109     if(more<0){
00110       /* skipped n bytes */
00111       vf->offset-=more;
00112     }else{
00113       if(more==0){
00114         /* send more paramedics */
00115         if(!boundary)return(OV_FALSE);
00116         {
00117           long ret=_get_data(vf);
00118           if(ret==0)return(OV_EOF);
00119           if(ret<0)return(OV_EREAD);
00120         }
00121       }else{
00122         /* got a page.  Return the offset at the page beginning,
00123            advance the internal offset past the page end */
00124         ogg_int64_t ret=vf->offset;
00125         vf->offset+=more;
00126         return(ret);
00127         
00128       }
00129     }
00130   }
00131 }
00132 
00133 /* find the latest page beginning before the current stream cursor
00134    position. Much dirtier than the above as Ogg doesn't have any
00135    backward search linkage.  no 'readp' as it will certainly have to
00136    read. */
00137 /* returns offset or OV_EREAD, OV_FAULT */
00138 static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
00139   ogg_int64_t begin=vf->offset;
00140   ogg_int64_t end=begin;
00141   ogg_int64_t ret;
00142   ogg_int64_t offset=-1;
00143 
00144   while(offset==-1){
00145     begin-=CHUNKSIZE;
00146     if(begin<0)
00147       begin=0;
00148     _seek_helper(vf,begin);
00149     while(vf->offset<end){
00150       ret=_get_next_page(vf,og,end-vf->offset);
00151       if(ret==OV_EREAD)return(OV_EREAD);
00152       if(ret<0){
00153         break;
00154       }else{
00155         offset=ret;
00156       }
00157     }
00158   }
00159 
00160   /* we have the offset.  Actually snork and hold the page now */
00161   _seek_helper(vf,offset);
00162   ret=_get_next_page(vf,og,CHUNKSIZE);
00163   if(ret<0)
00164     /* this shouldn't be possible */
00165     return(OV_EFAULT);
00166 
00167   return(offset);
00168 }
00169 
00170 /* finds each bitstream link one at a time using a bisection search
00171    (has to begin by knowing the offset of the lb's initial page).
00172    Recurses for each link so it can alloc the link storage after
00173    finding them all, then unroll and fill the cache at the same time */
00174 static int _bisect_forward_serialno(OggVorbis_File *vf,
00175                                     ogg_int64_t begin,
00176                                     ogg_int64_t searched,
00177                                     ogg_int64_t end,
00178                                     long currentno,
00179                                     long m){
00180   ogg_int64_t endsearched=end;
00181   ogg_int64_t next=end;
00182   ogg_page og;
00183   ogg_int64_t ret;
00184   
00185   /* the below guards against garbage seperating the last and
00186      first pages of two links. */
00187   while(searched<endsearched){
00188     ogg_int64_t bisect;
00189     
00190     if(endsearched-searched<CHUNKSIZE){
00191       bisect=searched;
00192     }else{
00193       bisect=(searched+endsearched)/2;
00194     }
00195     
00196     _seek_helper(vf,bisect);
00197     ret=_get_next_page(vf,&og,-1);
00198     if(ret==OV_EREAD)return(OV_EREAD);
00199     if(ret<0 || ogg_page_serialno(&og)!=currentno){
00200       endsearched=bisect;
00201       if(ret>=0)next=ret;
00202     }else{
00203       searched=ret+og.header_len+og.body_len;
00204     }
00205   }
00206 
00207   _seek_helper(vf,next);
00208   ret=_get_next_page(vf,&og,-1);
00209   if(ret==OV_EREAD)return(OV_EREAD);
00210   
00211   if(searched>=end || ret<0){
00212     vf->links=m+1;
00213     vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
00214     vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
00215     vf->offsets[m+1]=searched;
00216   }else{
00217     ret=_bisect_forward_serialno(vf,next,vf->offset,
00218                                  end,ogg_page_serialno(&og),m+1);
00219     if(ret==OV_EREAD)return(OV_EREAD);
00220   }
00221   
00222   vf->offsets[m]=begin;
00223   vf->serialnos[m]=currentno;
00224   return(0);
00225 }
00226 
00227 /* uses the local ogg_stream storage in vf; this is important for
00228    non-streaming input sources */
00229 static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
00230                           long *serialno,ogg_page *og_ptr){
00231   ogg_page og;
00232   ogg_packet op;
00233   int i,ret;
00234   
00235   if(!og_ptr){
00236     ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
00237     if(llret==OV_EREAD)return(OV_EREAD);
00238     if(llret<0)return OV_ENOTVORBIS;
00239     og_ptr=&og;
00240   }
00241 
00242   ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
00243   if(serialno)*serialno=vf->os.serialno;
00244   vf->ready_state=STREAMSET;
00245   
00246   /* extract the initial header from the first page and verify that the
00247      Ogg bitstream is in fact Vorbis data */
00248   
00249   vorbis_info_init(vi);
00250   vorbis_comment_init(vc);
00251   
00252   i=0;
00253   while(i<3){
00254     ogg_stream_pagein(&vf->os,og_ptr);
00255     while(i<3){
00256       int result=ogg_stream_packetout(&vf->os,&op);
00257       if(result==0)break;
00258       if(result==-1){
00259         ret=OV_EBADHEADER;
00260         goto bail_header;
00261       }
00262       if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
00263         goto bail_header;
00264       }
00265       i++;
00266     }
00267     if(i<3)
00268       if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
00269         ret=OV_EBADHEADER;
00270         goto bail_header;
00271       }
00272   }
00273   return 0; 
00274 
00275  bail_header:
00276   vorbis_info_clear(vi);
00277   vorbis_comment_clear(vc);
00278   vf->ready_state=OPENED;
00279 
00280   return ret;
00281 }
00282 
00283 /* last step of the OggVorbis_File initialization; get all the
00284    vorbis_info structs and PCM positions.  Only called by the seekable
00285    initialization (local stream storage is hacked slightly; pay
00286    attention to how that's done) */
00287 
00288 /* this is void and does not propogate errors up because we want to be
00289    able to open and use damaged bitstreams as well as we can.  Just
00290    watch out for missing information for links in the OggVorbis_File
00291    struct */
00292 static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){
00293   ogg_page og;
00294   int i;
00295   ogg_int64_t ret;
00296   
00297   vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
00298   vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
00299   vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
00300   vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
00301   
00302   for(i=0;i<vf->links;i++){
00303     if(i==0){
00304       /* we already grabbed the initial header earlier.  Just set the offset */
00305       vf->dataoffsets[i]=dataoffset;
00306       _seek_helper(vf,dataoffset);
00307 
00308     }else{
00309 
00310       /* seek to the location of the initial header */
00311 
00312       _seek_helper(vf,vf->offsets[i]);
00313       if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
00314         vf->dataoffsets[i]=-1;
00315       }else{
00316         vf->dataoffsets[i]=vf->offset;
00317       }
00318     }
00319 
00320     /* fetch beginning PCM offset */
00321 
00322     if(vf->dataoffsets[i]!=-1){
00323       ogg_int64_t accumulated=0;
00324       long        lastblock=-1;
00325       int         result;
00326 
00327       ogg_stream_reset_serialno(&vf->os,vf->serialnos[i]);
00328 
00329       while(1){
00330         ogg_packet op;
00331 
00332         ret=_get_next_page(vf,&og,-1);
00333         if(ret<0)
00334           /* this should not be possible unless the file is
00335              truncated/mangled */
00336           break;
00337        
00338         if(ogg_page_serialno(&og)!=vf->serialnos[i])
00339           break;
00340         
00341         /* count blocksizes of all frames in the page */
00342         ogg_stream_pagein(&vf->os,&og);
00343         while((result=ogg_stream_packetout(&vf->os,&op))){
00344           if(result>0){ /* ignore holes */
00345             long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);
00346             if(lastblock!=-1)
00347               accumulated+=(lastblock+thisblock)>>2;
00348             lastblock=thisblock;
00349           }
00350         }
00351 
00352         if(ogg_page_granulepos(&og)!=-1){
00353           /* pcm offset of last packet on the first audio page */
00354           accumulated= ogg_page_granulepos(&og)-accumulated;
00355           break;
00356         }
00357       }
00358 
00359       /* less than zero?  This is a stream with samples trimmed off
00360          the beginning, a normal occurrence; set the offset to zero */
00361       if(accumulated<0)accumulated=0;
00362 
00363       vf->pcmlengths[i*2]=accumulated;
00364     }
00365 
00366     /* get the PCM length of this link. To do this,
00367        get the last page of the stream */
00368     {
00369       ogg_int64_t end=vf->offsets[i+1];
00370       _seek_helper(vf,end);
00371 
00372       while(1){
00373         ret=_get_prev_page(vf,&og);
00374         if(ret<0){
00375           /* this should not be possible */
00376           vorbis_info_clear(vf->vi+i);
00377           vorbis_comment_clear(vf->vc+i);
00378           break;
00379         }
00380         if(ogg_page_granulepos(&og)!=-1){
00381           vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
00382           break;
00383         }
00384         vf->offset=ret;
00385       }
00386     }
00387   }
00388 }
00389 
00390 static int _make_decode_ready(OggVorbis_File *vf){
00391   if(vf->ready_state>STREAMSET)return 0;
00392   if(vf->ready_state<STREAMSET)return OV_EFAULT;
00393   if(vf->seekable){
00394     if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
00395       return OV_EBADLINK;
00396   }else{
00397     if(vorbis_synthesis_init(&vf->vd,vf->vi))
00398       return OV_EBADLINK;
00399   }    
00400   vorbis_block_init(&vf->vd,&vf->vb);
00401   vf->ready_state=INITSET;
00402   vf->bittrack=0.f;
00403   vf->samptrack=0.f;
00404   return 0;
00405 }
00406 
00407 static int _open_seekable2(OggVorbis_File *vf){
00408   long serialno=vf->current_serialno;
00409   ogg_int64_t dataoffset=vf->offset, end;
00410   ogg_page og;
00411 
00412   /* we're partially open and have a first link header state in
00413      storage in vf */
00414   /* we can seek, so set out learning all about this file */
00415   (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
00416   vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
00417   
00418   /* We get the offset for the last page of the physical bitstream.
00419      Most OggVorbis files will contain a single logical bitstream */
00420   end=_get_prev_page(vf,&og);
00421   if(end<0)return(end);
00422 
00423   /* more than one logical bitstream? */
00424   if(ogg_page_serialno(&og)!=serialno){
00425 
00426     /* Chained bitstream. Bisect-search each logical bitstream
00427        section.  Do so based on serial number only */
00428     if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
00429 
00430   }else{
00431 
00432     /* Only one logical bitstream */
00433     if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
00434 
00435   }
00436 
00437   /* the initial header memory is referenced by vf after; don't free it */
00438   _prefetch_all_headers(vf,dataoffset);
00439   return(ov_raw_seek(vf,0));
00440 }
00441 
00442 /* clear out the current logical bitstream decoder */ 
00443 static void _decode_clear(OggVorbis_File *vf){
00444   vorbis_dsp_clear(&vf->vd);
00445   vorbis_block_clear(&vf->vb);
00446   vf->ready_state=OPENED;
00447 }
00448 
00449 /* fetch and process a packet.  Handles the case where we're at a
00450    bitstream boundary and dumps the decoding machine.  If the decoding
00451    machine is unloaded, it loads it.  It also keeps pcm_offset up to
00452    date (seek and read both use this.  seek uses a special hack with
00453    readp). 
00454 
00455    return: <0) error, OV_HOLE (lost packet) or OV_EOF
00456             0) need more data (only if readp==0)
00457             1) got a packet 
00458 */
00459 
00460 static int _fetch_and_process_packet(OggVorbis_File *vf,
00461                                      ogg_packet *op_in,
00462                                      int readp,
00463                                      int spanp){
00464   ogg_page og;
00465 
00466   /* handle one packet.  Try to fetch it from current stream state */
00467   /* extract packets from page */
00468   while(1){
00469     
00470     /* process a packet if we can.  If the machine isn't loaded,
00471        neither is a page */
00472     if(vf->ready_state==INITSET){
00473       while(1) {
00474         ogg_packet op;
00475         ogg_packet *op_ptr=(op_in?op_in:&op);
00476         int result=ogg_stream_packetout(&vf->os,op_ptr);
00477         ogg_int64_t granulepos;
00478 
00479         op_in=NULL;
00480         if(result==-1)return(OV_HOLE); /* hole in the data. */
00481         if(result>0){
00482           /* got a packet.  process it */
00483           granulepos=op_ptr->granulepos;
00484           if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
00485                                                     header handling.  The
00486                                                     header packets aren't
00487                                                     audio, so if/when we
00488                                                     submit them,
00489                                                     vorbis_synthesis will
00490                                                     reject them */
00491 
00492             /* suck in the synthesis data and track bitrate */
00493             {
00494               int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
00495               /* for proper use of libvorbis within libvorbisfile,
00496                  oldsamples will always be zero. */
00497               if(oldsamples)return(OV_EFAULT);
00498               
00499               vorbis_synthesis_blockin(&vf->vd,&vf->vb);
00500               vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
00501               vf->bittrack+=op_ptr->bytes*8;
00502             }
00503           
00504             /* update the pcm offset. */
00505             if(granulepos!=-1 && !op_ptr->e_o_s){
00506               int link=(vf->seekable?vf->current_link:0);
00507               int i,samples;
00508             
00509               /* this packet has a pcm_offset on it (the last packet
00510                  completed on a page carries the offset) After processing
00511                  (above), we know the pcm position of the *last* sample
00512                  ready to be returned. Find the offset of the *first*
00513 
00514                  As an aside, this trick is inaccurate if we begin
00515                  reading anew right at the last page; the end-of-stream
00516                  granulepos declares the last frame in the stream, and the
00517                  last packet of the last page may be a partial frame.
00518                  So, we need a previous granulepos from an in-sequence page
00519                  to have a reference point.  Thus the !op_ptr->e_o_s clause
00520                  above */
00521 
00522               if(vf->seekable && link>0)
00523                 granulepos-=vf->pcmlengths[link*2];
00524               if(granulepos<0)granulepos=0; /* actually, this
00525                                                shouldn't be possible
00526                                                here unless the stream
00527                                                is very broken */
00528 
00529               samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
00530             
00531               granulepos-=samples;
00532               for(i=0;i<link;i++)
00533                 granulepos+=vf->pcmlengths[i*2+1];
00534               vf->pcm_offset=granulepos;
00535             }
00536             return(1);
00537           }
00538         }
00539         else 
00540           break;
00541       }
00542     }
00543 
00544     if(vf->ready_state>=OPENED){
00545       ogg_int64_t ret;
00546       if(!readp)return(0);
00547       if((ret=_get_next_page(vf,&og,-1))<0){
00548         return(OV_EOF); /* eof. 
00549                            leave unitialized */
00550       }
00551 
00552         /* bitrate tracking; add the header's bytes here, the body bytes
00553            are done by packet above */
00554       vf->bittrack+=og.header_len*8;
00555       
00556       /* has our decoding just traversed a bitstream boundary? */
00557       if(vf->ready_state==INITSET){
00558         if(vf->current_serialno!=ogg_page_serialno(&og)){
00559           if(!spanp)
00560             return(OV_EOF);
00561 
00562           _decode_clear(vf);
00563           
00564           if(!vf->seekable){
00565             vorbis_info_clear(vf->vi);
00566             vorbis_comment_clear(vf->vc);
00567           }
00568         }
00569       }
00570     }
00571 
00572     /* Do we need to load a new machine before submitting the page? */
00573     /* This is different in the seekable and non-seekable cases.  
00574 
00575        In the seekable case, we already have all the header
00576        information loaded and cached; we just initialize the machine
00577        with it and continue on our merry way.
00578 
00579        In the non-seekable (streaming) case, we'll only be at a
00580        boundary if we just left the previous logical bitstream and
00581        we're now nominally at the header of the next bitstream
00582     */
00583 
00584     if(vf->ready_state!=INITSET){ 
00585       int link;
00586 
00587       if(vf->ready_state<STREAMSET){
00588         if(vf->seekable){
00589           vf->current_serialno=ogg_page_serialno(&og);
00590           
00591           /* match the serialno to bitstream section.  We use this rather than
00592              offset positions to avoid problems near logical bitstream
00593              boundaries */
00594           for(link=0;link<vf->links;link++)
00595             if(vf->serialnos[link]==vf->current_serialno)break;
00596           if(link==vf->links)return(OV_EBADLINK); /* sign of a bogus
00597                                                      stream.  error out,
00598                                                      leave machine
00599                                                      uninitialized */
00600           
00601           vf->current_link=link;
00602           
00603           ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
00604           vf->ready_state=STREAMSET;
00605           
00606         }else{
00607           /* we're streaming */
00608           /* fetch the three header packets, build the info struct */
00609           
00610           int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
00611           if(ret)return(ret);
00612           vf->current_link++;
00613           link=0;
00614         }
00615       }
00616       
00617       {
00618         int ret=_make_decode_ready(vf);
00619         if(ret<0)return ret;
00620       }
00621     }
00622     ogg_stream_pagein(&vf->os,&og);
00623   }
00624 }
00625 
00626 /* if, eg, 64 bit stdio is configured by default, this will build with
00627    fseek64 */
00628 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
00629   if(f==NULL)return(-1);
00630   return fseek(f,off,whence);
00631 }
00632 
00633 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
00634                      long ibytes, ov_callbacks callbacks){
00635   int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
00636   int ret;
00637 
00638   memset(vf,0,sizeof(*vf));
00639   vf->datasource=f;
00640   vf->callbacks = callbacks;
00641 
00642   /* init the framing state */
00643   ogg_sync_init(&vf->oy);
00644 
00645   /* perhaps some data was previously read into a buffer for testing
00646      against other stream types.  Allow initialization from this
00647      previously read data (as we may be reading from a non-seekable
00648      stream) */
00649   if(initial){
00650     char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
00651     memcpy(buffer,initial,ibytes);
00652     ogg_sync_wrote(&vf->oy,ibytes);
00653   }
00654 
00655   /* can we seek? Stevens suggests the seek test was portable */
00656   if(offsettest!=-1)vf->seekable=1;
00657 
00658   /* No seeking yet; Set up a 'single' (current) logical bitstream
00659      entry for partial open */
00660   vf->links=1;
00661   vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
00662   vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
00663   ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
00664 
00665   /* Try to fetch the headers, maintaining all the storage */
00666   if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
00667     vf->datasource=NULL;
00668     ov_clear(vf);
00669   }else 
00670     vf->ready_state=PARTOPEN;
00671   return(ret);
00672 }
00673 
00674 static int _ov_open2(OggVorbis_File *vf){
00675   if(vf->ready_state != PARTOPEN) return OV_EINVAL;
00676   vf->ready_state=OPENED;
00677   if(vf->seekable){
00678     int ret=_open_seekable2(vf);
00679     if(ret){
00680       vf->datasource=NULL;
00681       ov_clear(vf);
00682     }
00683     return(ret);
00684   }else
00685     vf->ready_state=STREAMSET;
00686 
00687   return 0;
00688 }
00689 
00690 
00691 /* clear out the OggVorbis_File struct */
00692 int ov_clear(OggVorbis_File *vf){
00693   if(vf){
00694     vorbis_block_clear(&vf->vb);
00695     vorbis_dsp_clear(&vf->vd);
00696     ogg_stream_clear(&vf->os);
00697     
00698     if(vf->vi && vf->links){
00699       int i;
00700       for(i=0;i<vf->links;i++){
00701         vorbis_info_clear(vf->vi+i);
00702         vorbis_comment_clear(vf->vc+i);
00703       }
00704       _ogg_free(vf->vi);
00705       _ogg_free(vf->vc);
00706     }
00707     if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
00708     if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
00709     if(vf->serialnos)_ogg_free(vf->serialnos);
00710     if(vf->offsets)_ogg_free(vf->offsets);
00711     ogg_sync_clear(&vf->oy);
00712     if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
00713     memset(vf,0,sizeof(*vf));
00714   }
00715 #ifdef DEBUG_LEAKS
00716   _VDBG_dump();
00717 #endif
00718   return(0);
00719 }
00720 
00721 /* inspects the OggVorbis file and finds/documents all the logical
00722    bitstreams contained in it.  Tries to be tolerant of logical
00723    bitstream sections that are truncated/woogie. 
00724 
00725    return: -1) error
00726             0) OK
00727 */
00728 
00729 int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
00730     ov_callbacks callbacks){
00731   int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
00732   if(ret)return ret;
00733   return _ov_open2(vf);
00734 }
00735 
00736 int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
00737   ov_callbacks callbacks = {
00738     (size_t (*)(void *, size_t, size_t, void *))  fread,
00739     (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
00740     (int (*)(void *))                             fclose,
00741     (long (*)(void *))                            ftell
00742   };
00743 
00744   return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
00745 }
00746  
00747 /* cheap hack for game usage where downsampling is desirable; there's
00748    no need for SRC as we can just do it cheaply in libvorbis. */
00749  
00750 int ov_halfrate(OggVorbis_File *vf,int flag){
00751   int i;
00752   if(vf->vi==NULL)return OV_EINVAL;
00753   if(!vf->seekable)return OV_EINVAL;
00754   if(vf->ready_state>=STREAMSET)
00755     _decode_clear(vf); /* clear out stream state; later on libvorbis
00756                           will be able to swap this on the fly, but
00757                           for now dumping the decode machine is needed
00758                           to reinit the MDCT lookups.  1.1 libvorbis
00759                           is planned to be able to switch on the fly */
00760   
00761   for(i=0;i<vf->links;i++){
00762     if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
00763       ov_halfrate(vf,0);
00764       return OV_EINVAL;
00765     }
00766   }
00767   return 0;
00768 }
00769 
00770 int ov_halfrate_p(OggVorbis_File *vf){
00771   if(vf->vi==NULL)return OV_EINVAL;
00772   return vorbis_synthesis_halfrate_p(vf->vi);
00773 }
00774 
00775 /* Only partially open the vorbis file; test for Vorbisness, and load
00776    the headers for the first chain.  Do not seek (although test for
00777    seekability).  Use ov_test_open to finish opening the file, else
00778    ov_clear to close/free it. Same return codes as open. */
00779 
00780 int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
00781     ov_callbacks callbacks)
00782 {
00783   return _ov_open1(f,vf,initial,ibytes,callbacks);
00784 }
00785 
00786 int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
00787   ov_callbacks callbacks = {
00788     (size_t (*)(void *, size_t, size_t, void *))  fread,
00789     (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
00790     (int (*)(void *))                             fclose,
00791     (long (*)(void *))                            ftell
00792   };
00793 
00794   return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
00795 }
00796   
00797 int ov_test_open(OggVorbis_File *vf){
00798   if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
00799   return _ov_open2(vf);
00800 }
00801 
00802 /* How many logical bitstreams in this physical bitstream? */
00803 long ov_streams(OggVorbis_File *vf){
00804   return vf->links;
00805 }
00806 
00807 /* Is the FILE * associated with vf seekable? */
00808 long ov_seekable(OggVorbis_File *vf){
00809   return vf->seekable;
00810 }
00811 
00812 /* returns the bitrate for a given logical bitstream or the entire
00813    physical bitstream.  If the file is open for random access, it will
00814    find the *actual* average bitrate.  If the file is streaming, it
00815    returns the nominal bitrate (if set) else the average of the
00816    upper/lower bounds (if set) else -1 (unset).
00817 
00818    If you want the actual bitrate field settings, get them from the
00819    vorbis_info structs */
00820 
00821 long ov_bitrate(OggVorbis_File *vf,int i){
00822   if(vf->ready_state<OPENED)return(OV_EINVAL);
00823   if(i>=vf->links)return(OV_EINVAL);
00824   if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
00825   if(i<0){
00826     ogg_int64_t bits=0;
00827     int i;
00828     float br;
00829     for(i=0;i<vf->links;i++)
00830       bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
00831     /* This once read: return(rint(bits/ov_time_total(vf,-1)));
00832      * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
00833      * so this is slightly transformed to make it work.
00834      */
00835     br = bits/ov_time_total(vf,-1);
00836     return(rint(br));
00837   }else{
00838     if(vf->seekable){
00839       /* return the actual bitrate */
00840       return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
00841     }else{
00842       /* return nominal if set */
00843       if(vf->vi[i].bitrate_nominal>0){
00844         return vf->vi[i].bitrate_nominal;
00845       }else{
00846         if(vf->vi[i].bitrate_upper>0){
00847           if(vf->vi[i].bitrate_lower>0){
00848             return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
00849           }else{
00850             return vf->vi[i].bitrate_upper;
00851           }
00852         }
00853         return(OV_FALSE);
00854       }
00855     }
00856   }
00857 }
00858 
00859 /* returns the actual bitrate since last call.  returns -1 if no
00860    additional data to offer since last call (or at beginning of stream),
00861    EINVAL if stream is only partially open 
00862 */
00863 long ov_bitrate_instant(OggVorbis_File *vf){
00864   int link=(vf->seekable?vf->current_link:0);
00865   long ret;
00866   if(vf->ready_state<OPENED)return(OV_EINVAL);
00867   if(vf->samptrack==0)return(OV_FALSE);
00868   ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
00869   vf->bittrack=0.f;
00870   vf->samptrack=0.f;
00871   return(ret);
00872 }
00873 
00874 /* Guess */
00875 long ov_serialnumber(OggVorbis_File *vf,int i){
00876   if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
00877   if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
00878   if(i<0){
00879     return(vf->current_serialno);
00880   }else{
00881     return(vf->serialnos[i]);
00882   }
00883 }
00884 
00885 /* returns: total raw (compressed) length of content if i==-1
00886             raw (compressed) length of that logical bitstream for i==0 to n
00887             OV_EINVAL if the stream is not seekable (we can't know the length)
00888             or if stream is only partially open
00889 */
00890 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
00891   if(vf->ready_state<OPENED)return(OV_EINVAL);
00892   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
00893   if(i<0){
00894     ogg_int64_t acc=0;
00895     int i;
00896     for(i=0;i<vf->links;i++)
00897       acc+=ov_raw_total(vf,i);
00898     return(acc);
00899   }else{
00900     return(vf->offsets[i+1]-vf->offsets[i]);
00901   }
00902 }
00903 
00904 /* returns: total PCM length (samples) of content if i==-1 PCM length
00905             (samples) of that logical bitstream for i==0 to n
00906             OV_EINVAL if the stream is not seekable (we can't know the
00907             length) or only partially open 
00908 */
00909 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
00910   if(vf->ready_state<OPENED)return(OV_EINVAL);
00911   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
00912   if(i<0){
00913     ogg_int64_t acc=0;
00914     int i;
00915     for(i=0;i<vf->links;i++)
00916       acc+=ov_pcm_total(vf,i);
00917     return(acc);
00918   }else{
00919     return(vf->pcmlengths[i*2+1]);
00920   }
00921 }
00922 
00923 /* returns: total seconds of content if i==-1
00924             seconds in that logical bitstream for i==0 to n
00925             OV_EINVAL if the stream is not seekable (we can't know the
00926             length) or only partially open 
00927 */
00928 double ov_time_total(OggVorbis_File *vf,int i){
00929   if(vf->ready_state<OPENED)return(OV_EINVAL);
00930   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
00931   if(i<0){
00932     double acc=0;
00933     int i;
00934     for(i=0;i<vf->links;i++)
00935       acc+=ov_time_total(vf,i);
00936     return(acc);
00937   }else{
00938     return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
00939   }
00940 }
00941 
00942 /* seek to an offset relative to the *compressed* data. This also
00943    scans packets to update the PCM cursor. It will cross a logical
00944    bitstream boundary, but only if it can't get any packets out of the
00945    tail of the bitstream we seek to (so no surprises).
00946 
00947    returns zero on success, nonzero on failure */
00948 
00949 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
00950   ogg_stream_state work_os;
00951 
00952   if(vf->ready_state<OPENED)return(OV_EINVAL);
00953   if(!vf->seekable)
00954     return(OV_ENOSEEK); /* don't dump machine if we can't seek */
00955 
00956   if(pos<0 || pos>vf->end)return(OV_EINVAL);
00957 
00958   /* don't yet clear out decoding machine (if it's initialized), in
00959      the case we're in the same link.  Restart the decode lapping, and
00960      let _fetch_and_process_packet deal with a potential bitstream
00961      boundary */
00962   vf->pcm_offset=-1;
00963   ogg_stream_reset_serialno(&vf->os,
00964                             vf->current_serialno); /* must set serialno */
00965   vorbis_synthesis_restart(&vf->vd);
00966     
00967   _seek_helper(vf,pos);
00968 
00969   /* we need to make sure the pcm_offset is set, but we don't want to
00970      advance the raw cursor past good packets just to get to the first
00971      with a granulepos.  That's not equivalent behavior to beginning
00972      decoding as immediately after the seek position as possible.
00973 
00974      So, a hack.  We use two stream states; a local scratch state and
00975      the shared vf->os stream state.  We use the local state to
00976      scan, and the shared state as a buffer for later decode. 
00977 
00978      Unfortuantely, on the last page we still advance to last packet
00979      because the granulepos on the last page is not necessarily on a
00980      packet boundary, and we need to make sure the granpos is
00981      correct. 
00982   */
00983 
00984   {
00985     ogg_page og;
00986     ogg_packet op;
00987     int lastblock=0;
00988     int accblock=0;
00989     int thisblock;
00990     int eosflag;
00991 
00992     ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
00993     ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
00994                                    return from not necessarily
00995                                    starting from the beginning */
00996 
00997     while(1){
00998       if(vf->ready_state>=STREAMSET){
00999         /* snarf/scan a packet if we can */
01000         int result=ogg_stream_packetout(&work_os,&op);
01001       
01002         if(result>0){
01003 
01004           if(vf->vi[vf->current_link].codec_setup){
01005             thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
01006             if(thisblock<0){
01007               ogg_stream_packetout(&vf->os,NULL);
01008               thisblock=0;
01009             }else{
01010               
01011               if(eosflag)
01012               ogg_stream_packetout(&vf->os,NULL);
01013               else
01014                 if(lastblock)accblock+=(lastblock+thisblock)>>2;
01015             }       
01016 
01017             if(op.granulepos!=-1){
01018               int i,link=vf->current_link;
01019               ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
01020               if(granulepos<0)granulepos=0;
01021               
01022               for(i=0;i<link;i++)
01023                 granulepos+=vf->pcmlengths[i*2+1];
01024               vf->pcm_offset=granulepos-accblock;
01025               break;
01026             }
01027             lastblock=thisblock;
01028             continue;
01029           }else
01030             ogg_stream_packetout(&vf->os,NULL);
01031         }
01032       }
01033       
01034       if(!lastblock){
01035         if(_get_next_page(vf,&og,-1)<0){
01036           vf->pcm_offset=ov_pcm_total(vf,-1);
01037           break;
01038         }
01039       }else{
01040         /* huh?  Bogus stream with packets but no granulepos */
01041         vf->pcm_offset=-1;
01042         break;
01043       }
01044       
01045       /* has our decoding just traversed a bitstream boundary? */
01046       if(vf->ready_state>=STREAMSET)
01047         if(vf->current_serialno!=ogg_page_serialno(&og)){
01048           _decode_clear(vf); /* clear out stream state */
01049           ogg_stream_clear(&work_os);
01050         }
01051 
01052       if(vf->ready_state<STREAMSET){
01053         int link;
01054         
01055         vf->current_serialno=ogg_page_serialno(&og);
01056         for(link=0;link<vf->links;link++)
01057           if(vf->serialnos[link]==vf->current_serialno)break;
01058         if(link==vf->links)goto seek_error; /* sign of a bogus stream.
01059                                                error out, leave
01060                                                machine uninitialized */
01061         vf->current_link=link;
01062         
01063         ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
01064         ogg_stream_reset_serialno(&work_os,vf->current_serialno); 
01065         vf->ready_state=STREAMSET;
01066         
01067       }
01068     
01069       ogg_stream_pagein(&vf->os,&og);
01070       ogg_stream_pagein(&work_os,&og);
01071       eosflag=ogg_page_eos(&og);
01072     }
01073   }
01074 
01075   ogg_stream_clear(&work_os);
01076   vf->bittrack=0.f;
01077   vf->samptrack=0.f;
01078   return(0);
01079 
01080  seek_error:
01081   /* dump the machine so we're in a known state */
01082   vf->pcm_offset=-1;
01083   ogg_stream_clear(&work_os);
01084   _decode_clear(vf);
01085   return OV_EBADLINK;
01086 }
01087 
01088 /* Page granularity seek (faster than sample granularity because we
01089    don't do the last bit of decode to find a specific sample).
01090 
01091    Seek to the last [granule marked] page preceeding the specified pos
01092    location, such that decoding past the returned point will quickly
01093    arrive at the requested position. */
01094 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
01095   int link=-1;
01096   ogg_int64_t result=0;
01097   ogg_int64_t total=ov_pcm_total(vf,-1);
01098 
01099   if(vf->ready_state<OPENED)return(OV_EINVAL);
01100   if(!vf->seekable)return(OV_ENOSEEK);
01101 
01102   if(pos<0 || pos>total)return(OV_EINVAL);
01103  
01104   /* which bitstream section does this pcm offset occur in? */
01105   for(link=vf->links-1;link>=0;link--){
01106     total-=vf->pcmlengths[link*2+1];
01107     if(pos>=total)break;
01108   }
01109 
01110   /* search within the logical bitstream for the page with the highest
01111      pcm_pos preceeding (or equal to) pos.  There is a danger here;
01112      missing pages or incorrect frame number information in the
01113      bitstream could make our task impossible.  Account for that (it
01114      would be an error condition) */
01115 
01116   /* new search algorithm by HB (Nicholas Vinen) */
01117   {
01118     ogg_int64_t end=vf->offsets[link+1];
01119     ogg_int64_t begin=vf->offsets[link];
01120     ogg_int64_t begintime = vf->pcmlengths[link*2];
01121     ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
01122     ogg_int64_t target=pos-total+begintime;
01123     ogg_int64_t best=begin;
01124     
01125     ogg_page og;
01126     while(begin<end){
01127       ogg_int64_t bisect;
01128       
01129       if(end-begin<CHUNKSIZE){
01130         bisect=begin;
01131       }else{
01132         /* take a (pretty decent) guess. */
01133         bisect=begin + 
01134           (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
01135         if(bisect<=begin)
01136           bisect=begin+1;
01137       }
01138       
01139       _seek_helper(vf,bisect);
01140     
01141       while(begin<end){
01142         result=_get_next_page(vf,&og,end-vf->offset);
01143         if(result==OV_EREAD) goto seek_error;
01144         if(result<0){
01145           if(bisect<=begin+1)
01146             end=begin; /* found it */
01147           else{
01148             if(bisect==0) goto seek_error;
01149             bisect-=CHUNKSIZE;
01150             if(bisect<=begin)bisect=begin+1;
01151             _seek_helper(vf,bisect);
01152           }
01153         }else{
01154           ogg_int64_t granulepos=ogg_page_granulepos(&og);
01155           if(granulepos==-1)continue;
01156           if(granulepos<target){
01157             best=result;  /* raw offset of packet with granulepos */ 
01158             begin=vf->offset; /* raw offset of next page */
01159             begintime=granulepos;
01160             
01161             if(target-begintime>44100)break;
01162             bisect=begin; /* *not* begin + 1 */
01163           }else{
01164             if(bisect<=begin+1)
01165               end=begin;  /* found it */
01166             else{
01167               if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
01168                 end=result;
01169                 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
01170                 if(bisect<=begin)bisect=begin+1;
01171                 _seek_helper(vf,bisect);
01172               }else{
01173                 end=result;
01174                 endtime=granulepos;
01175                 break;
01176               }
01177             }
01178           }
01179         }
01180       }
01181     }
01182 
01183     /* found our page. seek to it, update pcm offset. Easier case than
01184        raw_seek, don't keep packets preceeding granulepos. */
01185     {
01186       ogg_page og;
01187       ogg_packet op;
01188       
01189       /* seek */
01190       _seek_helper(vf,best);
01191       vf->pcm_offset=-1;
01192       
01193       if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* shouldn't happen */
01194       
01195       if(link!=vf->current_link){
01196         /* Different link; dump entire decode machine */
01197         _decode_clear(vf);  
01198         
01199         vf->current_link=link;
01200         vf->current_serialno=ogg_page_serialno(&og);
01201         vf->ready_state=STREAMSET;
01202         
01203       }else{
01204         vorbis_synthesis_restart(&vf->vd);
01205       }
01206 
01207       ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
01208       ogg_stream_pagein(&vf->os,&og);
01209 
01210       /* pull out all but last packet; the one with granulepos */
01211       while(1){
01212         result=ogg_stream_packetpeek(&vf->os,&op);
01213         if(result==0){
01214           /* !!! the packet finishing this page originated on a
01215              preceeding page. Keep fetching previous pages until we
01216              get one with a granulepos or without the 'continued' flag
01217              set.  Then just use raw_seek for simplicity. */
01218           
01219           _seek_helper(vf,best);
01220           
01221           while(1){
01222             result=_get_prev_page(vf,&og);
01223             if(result<0) goto seek_error;
01224             if(ogg_page_granulepos(&og)>-1 ||
01225                !ogg_page_continued(&og)){
01226               return ov_raw_seek(vf,result);
01227             }
01228             vf->offset=result;
01229           }
01230         }
01231         if(result<0){
01232           result = OV_EBADPACKET; 
01233           goto seek_error;
01234         }
01235         if(op.granulepos!=-1){
01236           vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
01237           if(vf->pcm_offset<0)vf->pcm_offset=0;
01238           vf->pcm_offset+=total;
01239           break;
01240         }else
01241           result=ogg_stream_packetout(&vf->os,NULL);
01242       }
01243     }
01244   }
01245   
01246   /* verify result */
01247   if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
01248     result=OV_EFAULT;
01249     goto seek_error;
01250   }
01251   vf->bittrack=0.f;
01252   vf->samptrack=0.f;
01253   return(0);
01254   
01255  seek_error:
01256   /* dump machine so we're in a known state */
01257   vf->pcm_offset=-1;
01258   _decode_clear(vf);
01259   return (int)result;
01260 }
01261 
01262 /* seek to a sample offset relative to the decompressed pcm stream 
01263    returns zero on success, nonzero on failure */
01264 
01265 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
01266   int thisblock,lastblock=0;
01267   int ret=ov_pcm_seek_page(vf,pos);
01268   if(ret<0)return(ret);
01269   if((ret=_make_decode_ready(vf)))return ret;
01270 
01271   /* discard leading packets we don't need for the lapping of the
01272      position we want; don't decode them */
01273 
01274   while(1){
01275     ogg_packet op;
01276     ogg_page og;
01277 
01278     int ret=ogg_stream_packetpeek(&vf->os,&op);
01279     if(ret>0){
01280       thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
01281       if(thisblock<0){
01282         ogg_stream_packetout(&vf->os,NULL);
01283         continue; /* non audio packet */
01284       }
01285       if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
01286       
01287       if(vf->pcm_offset+((thisblock+
01288                           vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
01289       
01290       /* remove the packet from packet queue and track its granulepos */
01291       ogg_stream_packetout(&vf->os,NULL);
01292       vorbis_synthesis_trackonly(&vf->vb,&op);  /* set up a vb with
01293                                                    only tracking, no
01294                                                    pcm_decode */
01295       vorbis_synthesis_blockin(&vf->vd,&vf->vb); 
01296       
01297       /* end of logical stream case is hard, especially with exact
01298          length positioning. */
01299       
01300       if(op.granulepos>-1){
01301         int i;
01302         /* always believe the stream markers */
01303         vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
01304         if(vf->pcm_offset<0)vf->pcm_offset=0;
01305         for(i=0;i<vf->current_link;i++)
01306           vf->pcm_offset+=vf->pcmlengths[i*2+1];
01307       }
01308         
01309       lastblock=thisblock;
01310       
01311     }else{
01312       if(ret<0 && ret!=OV_HOLE)break;
01313       
01314       /* suck in a new page */
01315       if(_get_next_page(vf,&og,-1)<0)break;
01316       if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
01317       
01318       if(vf->ready_state<STREAMSET){
01319         int link;
01320         
01321         vf->current_serialno=ogg_page_serialno(&og);
01322         for(link=0;link<vf->links;link++)
01323           if(vf->serialnos[link]==vf->current_serialno)break;
01324         if(link==vf->links)return(OV_EBADLINK);
01325         vf->current_link=link;
01326         
01327         ogg_stream_reset_serialno(&vf->os,vf->current_serialno); 
01328         vf->ready_state=STREAMSET;      
01329         ret=_make_decode_ready(vf);
01330         if(ret)return ret;
01331         lastblock=0;
01332       }
01333 
01334       ogg_stream_pagein(&vf->os,&og);
01335     }
01336   }
01337 
01338   vf->bittrack=0.f;
01339   vf->samptrack=0.f;
01340   /* discard samples until we reach the desired position. Crossing a
01341      logical bitstream boundary with abandon is OK. */
01342   while(vf->pcm_offset<pos){
01343     ogg_int64_t target=pos-vf->pcm_offset;
01344     long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
01345 
01346     if(samples>target)samples=target;
01347     vorbis_synthesis_read(&vf->vd,samples);
01348     vf->pcm_offset+=samples;
01349     
01350     if(samples<target)
01351       if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
01352         vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
01353   }
01354   return 0;
01355 }
01356 
01357 /* seek to a playback time relative to the decompressed pcm stream 
01358    returns zero on success, nonzero on failure */
01359 int ov_time_seek(OggVorbis_File *vf,double seconds){
01360   /* translate time to PCM position and call ov_pcm_seek */
01361 
01362   int link=-1;
01363   ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
01364   double time_total=ov_time_total(vf,-1);
01365 
01366   if(vf->ready_state<OPENED)return(OV_EINVAL);
01367   if(!vf->seekable)return(OV_ENOSEEK);
01368   if(seconds<0 || seconds>time_total)return(OV_EINVAL);
01369   
01370   /* which bitstream section does this time offset occur in? */
01371   for(link=vf->links-1;link>=0;link--){
01372     pcm_total-=vf->pcmlengths[link*2+1];
01373     time_total-=ov_time_total(vf,link);
01374     if(seconds>=time_total)break;
01375   }
01376 
01377   /* enough information to convert time offset to pcm offset */
01378   {
01379     ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
01380     return(ov_pcm_seek(vf,target));
01381   }
01382 }
01383 
01384 /* page-granularity version of ov_time_seek 
01385    returns zero on success, nonzero on failure */
01386 int ov_time_seek_page(OggVorbis_File *vf,double seconds){
01387   /* translate time to PCM position and call ov_pcm_seek */
01388 
01389   int link=-1;
01390   ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
01391   double time_total=ov_time_total(vf,-1);
01392 
01393   if(vf->ready_state<OPENED)return(OV_EINVAL);
01394   if(!vf->seekable)return(OV_ENOSEEK);
01395   if(seconds<0 || seconds>time_total)return(OV_EINVAL);
01396   
01397   /* which bitstream section does this time offset occur in? */
01398   for(link=vf->links-1;link>=0;link--){
01399     pcm_total-=vf->pcmlengths[link*2+1];
01400     time_total-=ov_time_total(vf,link);
01401     if(seconds>=time_total)break;
01402   }
01403 
01404   /* enough information to convert time offset to pcm offset */
01405   {
01406     ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
01407     return(ov_pcm_seek_page(vf,target));
01408   }
01409 }
01410 
01411 /* tell the current stream offset cursor.  Note that seek followed by
01412    tell will likely not give the set offset due to caching */
01413 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
01414   if(vf->ready_state<OPENED)return(OV_EINVAL);
01415   return(vf->offset);
01416 }
01417 
01418 /* return PCM offset (sample) of next PCM sample to be read */
01419 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
01420   if(vf->ready_state<OPENED)return(OV_EINVAL);
01421   return(vf->pcm_offset);
01422 }
01423 
01424 /* return time offset (seconds) of next PCM sample to be read */
01425 double ov_time_tell(OggVorbis_File *vf){
01426   int link=0;
01427   ogg_int64_t pcm_total=0;
01428   double time_total=0.f;
01429   
01430   if(vf->ready_state<OPENED)return(OV_EINVAL);
01431   if(vf->seekable){
01432     pcm_total=ov_pcm_total(vf,-1);
01433     time_total=ov_time_total(vf,-1);
01434   
01435     /* which bitstream section does this time offset occur in? */
01436     for(link=vf->links-1;link>=0;link--){
01437       pcm_total-=vf->pcmlengths[link*2+1];
01438       time_total-=ov_time_total(vf,link);
01439       if(vf->pcm_offset>=pcm_total)break;
01440     }
01441   }
01442 
01443   return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
01444 }
01445 
01446 /*  link:   -1) return the vorbis_info struct for the bitstream section
01447                 currently being decoded
01448            0-n) to request information for a specific bitstream section
01449     
01450     In the case of a non-seekable bitstream, any call returns the
01451     current bitstream.  NULL in the case that the machine is not
01452     initialized */
01453 
01454 vorbis_info *ov_info(OggVorbis_File *vf,int link){
01455   if(vf->seekable){
01456     if(link<0)
01457       if(vf->ready_state>=STREAMSET)
01458         return vf->vi+vf->current_link;
01459       else
01460       return vf->vi;
01461     else
01462       if(link>=vf->links)
01463         return NULL;
01464       else
01465         return vf->vi+link;
01466   }else{
01467     return vf->vi;
01468   }
01469 }
01470 
01471 /* grr, strong typing, grr, no templates/inheritence, grr */
01472 vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
01473   if(vf->seekable){
01474     if(link<0)
01475       if(vf->ready_state>=STREAMSET)
01476         return vf->vc+vf->current_link;
01477       else
01478         return vf->vc;
01479     else
01480       if(link>=vf->links)
01481         return NULL;
01482       else
01483         return vf->vc+link;
01484   }else{
01485     return vf->vc;
01486   }
01487 }
01488 
01489 static int host_is_big_endian() {
01490   ogg_int32_t pattern = 0xfeedface; /* deadbeef */
01491   unsigned char *bytewise = (unsigned char *)&pattern;
01492   if (bytewise[0] == 0xfe) return 1;
01493   return 0;
01494 }
01495 
01496 /* up to this point, everything could more or less hide the multiple
01497    logical bitstream nature of chaining from the toplevel application
01498    if the toplevel application didn't particularly care.  However, at
01499    the point that we actually read audio back, the multiple-section
01500    nature must surface: Multiple bitstream sections do not necessarily
01501    have to have the same number of channels or sampling rate.
01502 
01503    ov_read returns the sequential logical bitstream number currently
01504    being decoded along with the PCM data in order that the toplevel
01505    application can take action on channel/sample rate changes.  This
01506    number will be incremented even for streamed (non-seekable) streams
01507    (for seekable streams, it represents the actual logical bitstream
01508    index within the physical bitstream.  Note that the accessor
01509    functions above are aware of this dichotomy).
01510 
01511    input values: buffer) a buffer to hold packed PCM data for return
01512                  length) the byte length requested to be placed into buffer
01513                  bigendianp) should the data be packed LSB first (0) or
01514                              MSB first (1)
01515                  word) word size for output.  currently 1 (byte) or 
01516                        2 (16 bit short)
01517 
01518    return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
01519                    0) EOF
01520                    n) number of bytes of PCM actually returned.  The
01521                    below works on a packet-by-packet basis, so the
01522                    return length is not related to the 'length' passed
01523                    in, just guaranteed to fit.
01524 
01525             *section) set to the logical bitstream number */
01526 
01527 long ov_read(OggVorbis_File *vf,char *buffer,int length,
01528                     int bigendianp,int word,int sgned,int *bitstream){
01529   int i,j;
01530   int host_endian = host_is_big_endian();
01531 
01532   float **pcm;
01533   long samples;
01534 
01535   if(vf->ready_state<OPENED)return(OV_EINVAL);
01536 
01537   while(1){
01538     if(vf->ready_state==INITSET){
01539       samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
01540       if(samples)break;
01541     }
01542 
01543     /* suck in another packet */
01544     {
01545       int ret=_fetch_and_process_packet(vf,NULL,1,1);
01546       if(ret==OV_EOF)
01547         return(0);
01548       if(ret<=0)
01549         return(ret);
01550     }
01551 
01552   }
01553 
01554   if(samples>0){
01555   
01556     /* yay! proceed to pack data into the byte buffer */
01557     
01558     long channels=ov_info(vf,-1)->channels;
01559     long bytespersample=word * channels;
01560     vorbis_fpu_control fpu;
01561     if(samples>length/bytespersample)samples=length/bytespersample;
01562 
01563     if(samples <= 0)
01564       return OV_EINVAL;
01565     
01566     /* a tight loop to pack each size */
01567     {
01568       int val;
01569       if(word==1){
01570         int off=(sgned?0:128);
01571         vorbis_fpu_setround(&fpu);
01572         for(j=0;j<samples;j++)
01573           for(i=0;i<channels;i++){
01574             val=vorbis_ftoi(pcm[i][j]*128.f);
01575             if(val>127)val=127;
01576             else if(val<-128)val=-128;
01577             *buffer++=val+off;
01578           }
01579         vorbis_fpu_restore(fpu);
01580       }else{
01581         int off=(sgned?0:32768);
01582         
01583         if(host_endian==bigendianp){
01584           if(sgned){
01585             
01586             vorbis_fpu_setround(&fpu);
01587             for(i=0;i<channels;i++) { /* It's faster in this order */
01588               float *src=pcm[i];
01589               short *dest=((short *)buffer)+i;
01590               for(j=0;j<samples;j++) {
01591                 val=vorbis_ftoi(src[j]*32768.f);
01592                 if(val>32767)val=32767;
01593                 else if(val<-32768)val=-32768;
01594                 *dest=val;
01595                 dest+=channels;
01596               }
01597             }
01598             vorbis_fpu_restore(fpu);
01599             
01600           }else{
01601             
01602             vorbis_fpu_setround(&fpu);
01603             for(i=0;i<channels;i++) {
01604               float *src=pcm[i];
01605               short *dest=((short *)buffer)+i;
01606               for(j=0;j<samples;j++) {
01607                 val=vorbis_ftoi(src[j]*32768.f);
01608                 if(val>32767)val=32767;
01609                 else if(val<-32768)val=-32768;
01610                 *dest=val+off;
01611                 dest+=channels;
01612               }
01613             }
01614             vorbis_fpu_restore(fpu);
01615             
01616           }
01617         }else if(bigendianp){
01618           
01619           vorbis_fpu_setround(&fpu);
01620           for(j=0;j<samples;j++)
01621             for(i=0;i<channels;i++){
01622               val=vorbis_ftoi(pcm[i][j]*32768.f);
01623               if(val>32767)val=32767;
01624               else if(val<-32768)val=-32768;
01625               val+=off;
01626               *buffer++=(val>>8);
01627               *buffer++=(val&0xff);
01628             }
01629           vorbis_fpu_restore(fpu);
01630           
01631         }else{
01632           int val;
01633           vorbis_fpu_setround(&fpu);
01634           for(j=0;j<samples;j++)
01635             for(i=0;i<channels;i++){
01636               val=vorbis_ftoi(pcm[i][j]*32768.f);
01637               if(val>32767)val=32767;
01638               else if(val<-32768)val=-32768;
01639               val+=off;
01640               *buffer++=(val&0xff);
01641               *buffer++=(val>>8);
01642                 }
01643           vorbis_fpu_restore(fpu);  
01644           
01645         }
01646       }
01647     }
01648     
01649     vorbis_synthesis_read(&vf->vd,samples);
01650     vf->pcm_offset+=samples;
01651     if(bitstream)*bitstream=vf->current_link;
01652     return(samples*bytespersample);
01653   }else{
01654     return(samples);
01655   }
01656 }
01657 
01658 /* input values: pcm_channels) a float vector per channel of output
01659                  length) the sample length being read by the app
01660 
01661    return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
01662                    0) EOF
01663                    n) number of samples of PCM actually returned.  The
01664                    below works on a packet-by-packet basis, so the
01665                    return length is not related to the 'length' passed
01666                    in, just guaranteed to fit.
01667 
01668             *section) set to the logical bitstream number */
01669 
01670 
01671 
01672 long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
01673                    int *bitstream){
01674 
01675   if(vf->ready_state<OPENED)return(OV_EINVAL);
01676 
01677   while(1){
01678     if(vf->ready_state==INITSET){
01679       float **pcm;
01680       long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
01681       if(samples){
01682         if(pcm_channels)*pcm_channels=pcm;
01683         if(samples>length)samples=length;
01684         vorbis_synthesis_read(&vf->vd,samples);
01685         vf->pcm_offset+=samples;
01686         if(bitstream)*bitstream=vf->current_link;
01687         return samples;
01688 
01689       }
01690     }
01691 
01692     /* suck in another packet */
01693     {
01694       int ret=_fetch_and_process_packet(vf,NULL,1,1);
01695       if(ret==OV_EOF)return(0);
01696       if(ret<=0)return(ret);
01697     }
01698 
01699   }
01700 }
01701 
01702 extern float *vorbis_window(vorbis_dsp_state *v,int W);
01703 extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,
01704                              ogg_int64_t off);
01705 
01706 static void _ov_splice(float **pcm,float **lappcm,
01707                        int n1, int n2,
01708                        int ch1, int ch2,
01709                        float *w1, float *w2){
01710   int i,j;
01711   float *w=w1;
01712   int n=n1;
01713 
01714   if(n1>n2){
01715     n=n2;
01716     w=w2;
01717   }
01718 
01719   /* splice */
01720   for(j=0;j<ch1 && j<ch2;j++){
01721     float *s=lappcm[j];
01722     float *d=pcm[j];
01723 
01724     for(i=0;i<n;i++){
01725       float wd=w[i]*w[i];
01726       float ws=1.-wd;
01727       d[i]=d[i]*wd + s[i]*ws;
01728     }
01729   }
01730   /* window from zero */
01731   for(;j<ch2;j++){
01732     float *d=pcm[j];
01733     for(i=0;i<n;i++){
01734       float wd=w[i]*w[i];
01735       d[i]=d[i]*wd;
01736     }
01737   }
01738 
01739 }
01740                 
01741 /* make sure vf is INITSET */
01742 static int _ov_initset(OggVorbis_File *vf){
01743   while(1){
01744     if(vf->ready_state==INITSET)break;
01745     /* suck in another packet */
01746     {
01747       int ret=_fetch_and_process_packet(vf,NULL,1,0);
01748       if(ret<0 && ret!=OV_HOLE)return(ret);
01749     }
01750   }
01751   return 0;
01752 }
01753 
01754 /* make sure vf is INITSET and that we have a primed buffer; if
01755    we're crosslapping at a stream section boundary, this also makes
01756    sure we're sanity checking against the right stream information */
01757 static int _ov_initprime(OggVorbis_File *vf){
01758   vorbis_dsp_state *vd=&vf->vd;
01759   while(1){
01760     if(vf->ready_state==INITSET)
01761       if(vorbis_synthesis_pcmout(vd,NULL))break;
01762     
01763     /* suck in another packet */
01764     {
01765       int ret=_fetch_and_process_packet(vf,NULL,1,0);
01766       if(ret<0 && ret!=OV_HOLE)return(ret);
01767     }
01768   }  
01769   return 0;
01770 }
01771 
01772 /* grab enough data for lapping from vf; this may be in the form of
01773    unreturned, already-decoded pcm, remaining PCM we will need to
01774    decode, or synthetic postextrapolation from last packets. */
01775 static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
01776                        float **lappcm,int lapsize){
01777   int lapcount=0,i;
01778   float **pcm;
01779 
01780   /* try first to decode the lapping data */
01781   while(lapcount<lapsize){
01782     int samples=vorbis_synthesis_pcmout(vd,&pcm);
01783     if(samples){
01784       if(samples>lapsize-lapcount)samples=lapsize-lapcount;
01785       for(i=0;i<vi->channels;i++)
01786         memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
01787       lapcount+=samples;
01788       vorbis_synthesis_read(vd,samples);
01789     }else{
01790     /* suck in another packet */
01791       int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
01792       if(ret==OV_EOF)break;
01793     }
01794   }
01795   if(lapcount<lapsize){
01796     /* failed to get lapping data from normal decode; pry it from the
01797        postextrapolation buffering, or the second half of the MDCT
01798        from the last packet */
01799     int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
01800     if(samples==0){
01801       for(i=0;i<vi->channels;i++)
01802         memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
01803       lapcount=lapsize;
01804     }else{
01805       if(samples>lapsize-lapcount)samples=lapsize-lapcount;
01806       for(i=0;i<vi->channels;i++)
01807         memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
01808       lapcount+=samples;
01809     }
01810   }
01811 }
01812 
01813 /* this sets up crosslapping of a sample by using trailing data from
01814    sample 1 and lapping it into the windowing buffer of sample 2 */
01815 int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
01816   vorbis_info *vi1,*vi2;
01817   float **lappcm;
01818   float **pcm;
01819   float *w1,*w2;
01820   int n1,n2,i,ret,hs1,hs2;
01821 
01822   if(vf1==vf2)return(0); /* degenerate case */
01823   if(vf1->ready_state<OPENED)return(OV_EINVAL);
01824   if(vf2->ready_state<OPENED)return(OV_EINVAL);
01825 
01826   /* the relevant overlap buffers must be pre-checked and pre-primed
01827      before looking at settings in the event that priming would cross
01828      a bitstream boundary.  So, do it now */
01829 
01830   ret=_ov_initset(vf1);
01831   if(ret)return(ret);
01832   ret=_ov_initprime(vf2);
01833   if(ret)return(ret);
01834 
01835   vi1=ov_info(vf1,-1);
01836   vi2=ov_info(vf2,-1);
01837   hs1=ov_halfrate_p(vf1);
01838   hs2=ov_halfrate_p(vf2);
01839 
01840   lappcm=alloca(sizeof(*lappcm)*vi1->channels);
01841   n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
01842   n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
01843   w1=vorbis_window(&vf1->vd,0);
01844   w2=vorbis_window(&vf2->vd,0);
01845 
01846   for(i=0;i<vi1->channels;i++)
01847     lappcm[i]=alloca(sizeof(**lappcm)*n1);
01848 
01849   _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
01850 
01851   /* have a lapping buffer from vf1; now to splice it into the lapping
01852      buffer of vf2 */
01853   /* consolidate and expose the buffer. */
01854   vorbis_synthesis_lapout(&vf2->vd,&pcm);
01855   _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
01856   _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
01857 
01858   /* splice */
01859   _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
01860   
01861   /* done */
01862   return(0);
01863 }
01864 
01865 static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
01866                            int (*localseek)(OggVorbis_File *,ogg_int64_t)){
01867   vorbis_info *vi;
01868   float **lappcm;
01869   float **pcm;
01870   float *w1,*w2;
01871   int n1,n2,ch1,ch2,hs;
01872   int i,ret;
01873 
01874   if(vf->ready_state<OPENED)return(OV_EINVAL);
01875   ret=_ov_initset(vf);
01876   if(ret)return(ret);
01877   vi=ov_info(vf,-1);
01878   hs=ov_halfrate_p(vf);
01879   
01880   ch1=vi->channels;
01881   n1=vorbis_info_blocksize(vi,0)>>(1+hs);
01882   w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
01883                                    persistent; even if the decode state
01884                                    from this link gets dumped, this
01885                                    window array continues to exist */
01886 
01887   lappcm=alloca(sizeof(*lappcm)*ch1);
01888   for(i=0;i<ch1;i++)
01889     lappcm[i]=alloca(sizeof(**lappcm)*n1);
01890   _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
01891 
01892   /* have lapping data; seek and prime the buffer */
01893   ret=localseek(vf,pos);
01894   if(ret)return ret;
01895   ret=_ov_initprime(vf);
01896   if(ret)return(ret);
01897 
01898  /* Guard against cross-link changes; they're perfectly legal */
01899   vi=ov_info(vf,-1);
01900   ch2=vi->channels;
01901   n2=vorbis_info_blocksize(vi,0)>>(1+hs);
01902   w2=vorbis_window(&vf->vd,0);
01903 
01904   /* consolidate and expose the buffer. */
01905   vorbis_synthesis_lapout(&vf->vd,&pcm);
01906 
01907   /* splice */
01908   _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
01909 
01910   /* done */
01911   return(0);
01912 }
01913 
01914 int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
01915   return _ov_64_seek_lap(vf,pos,ov_raw_seek);
01916 }
01917 
01918 int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
01919   return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
01920 }
01921 
01922 int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
01923   return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
01924 }
01925 
01926 static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
01927                            int (*localseek)(OggVorbis_File *,double)){
01928   vorbis_info *vi;
01929   float **lappcm;
01930   float **pcm;
01931   float *w1,*w2;
01932   int n1,n2,ch1,ch2,hs;
01933   int i,ret;
01934 
01935   if(vf->ready_state<OPENED)return(OV_EINVAL);
01936   ret=_ov_initset(vf);
01937   if(ret)return(ret);
01938   vi=ov_info(vf,-1);
01939   hs=ov_halfrate_p(vf);
01940 
01941   ch1=vi->channels;
01942   n1=vorbis_info_blocksize(vi,0)>>(1+hs);
01943   w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
01944                                    persistent; even if the decode state
01945                                    from this link gets dumped, this
01946                                    window array continues to exist */
01947 
01948   lappcm=alloca(sizeof(*lappcm)*ch1);
01949   for(i=0;i<ch1;i++)
01950     lappcm[i]=alloca(sizeof(**lappcm)*n1);
01951   _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
01952 
01953   /* have lapping data; seek and prime the buffer */
01954   ret=localseek(vf,pos);
01955   if(ret)return ret;
01956   ret=_ov_initprime(vf);
01957   if(ret)return(ret);
01958 
01959  /* Guard against cross-link changes; they're perfectly legal */
01960   vi=ov_info(vf,-1);
01961   ch2=vi->channels;
01962   n2=vorbis_info_blocksize(vi,0)>>(1+hs);
01963   w2=vorbis_window(&vf->vd,0);
01964 
01965   /* consolidate and expose the buffer. */
01966   vorbis_synthesis_lapout(&vf->vd,&pcm);
01967 
01968   /* splice */
01969   _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
01970 
01971   /* done */
01972   return(0);
01973 }
01974 
01975 int ov_time_seek_lap(OggVorbis_File *vf,double pos){
01976   return _ov_d_seek_lap(vf,pos,ov_time_seek);
01977 }
01978 
01979 int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
01980   return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
01981 }

Generated by  doxygen 1.6.2