examples/sfexamples/oggvorbiscodec/src/tremor/vorbisfile.c

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

Generated by  doxygen 1.6.2