]> git.jsancho.org Git - lugaru.git/blob - libvorbis-1.0.1/lib/vorbisfile.c
Simplified web browser launching on Linux.
[lugaru.git] / libvorbis-1.0.1 / lib / vorbisfile.c
1 /********************************************************************
2  *                                                                  *
3  * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
4  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
5  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
7  *                                                                  *
8  * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002             *
9  * by the XIPHOPHORUS Company http://www.xiph.org/                  *
10  *                                                                  *
11  ********************************************************************
12
13  function: stdio-based convenience library for opening/seeking/decoding
14  last mod: $Id: vorbisfile.c,v 1.75 2003/09/16 20:28:14 xiphmont Exp $
15
16  ********************************************************************/
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <math.h>
23
24 #include "vorbis/codec.h"
25 #include "vorbis/vorbisfile.h"
26
27 #include "os.h"
28 #include "misc.h"
29
30 /* A 'chained bitstream' is a Vorbis bitstream that contains more than
31    one logical bitstream arranged end to end (the only form of Ogg
32    multiplexing allowed in a Vorbis bitstream; grouping [parallel
33    multiplexing] is not allowed in Vorbis) */
34
35 /* A Vorbis file can be played beginning to end (streamed) without
36    worrying ahead of time about chaining (see decoder_example.c).  If
37    we have the whole file, however, and want random access
38    (seeking/scrubbing) or desire to know the total length/time of a
39    file, we need to account for the possibility of chaining. */
40
41 /* We can handle things a number of ways; we can determine the entire
42    bitstream structure right off the bat, or find pieces on demand.
43    This example determines and caches structure for the entire
44    bitstream, but builds a virtual decoder on the fly when moving
45    between links in the chain. */
46
47 /* There are also different ways to implement seeking.  Enough
48    information exists in an Ogg bitstream to seek to
49    sample-granularity positions in the output.  Or, one can seek by
50    picking some portion of the stream roughly in the desired area if
51    we only want coarse navigation through the stream. */
52
53 /*************************************************************************
54  * Many, many internal helpers.  The intention is not to be confusing; 
55  * rampant duplication and monolithic function implementation would be 
56  * harder to understand anyway.  The high level functions are last.  Begin
57  * grokking near the end of the file */
58
59 /* read a little more data from the file/pipe into the ogg_sync framer
60 */
61 #define CHUNKSIZE 8500 /* a shade over 8k; anyone using pages well
62                           over 8k gets what they deserve */
63 static long _get_data(OggVorbis_File *vf){
64   errno=0;
65   if(vf->datasource){
66     char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
67     long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
68     if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
69     if(bytes==0 && errno)return(-1);
70     return(bytes);
71   }else
72     return(0);
73 }
74
75 /* save a tiny smidge of verbosity to make the code more readable */
76 static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
77   if(vf->datasource){ 
78     (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
79     vf->offset=offset;
80     ogg_sync_reset(&vf->oy);
81   }else{
82     /* shouldn't happen unless someone writes a broken callback */
83     return;
84   }
85 }
86
87 /* The read/seek functions track absolute position within the stream */
88
89 /* from the head of the stream, get the next page.  boundary specifies
90    if the function is allowed to fetch more data from the stream (and
91    how much) or only use internally buffered data.
92
93    boundary: -1) unbounded search
94               0) read no additional data; use cached only
95               n) search for a new page beginning for n bytes
96
97    return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
98               n) found a page at absolute offset n */
99
100 static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
101                                   ogg_int64_t boundary){
102   if(boundary>0)boundary+=vf->offset;
103   while(1){
104     long more;
105
106     if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
107     more=ogg_sync_pageseek(&vf->oy,og);
108     
109     if(more<0){
110       /* skipped n bytes */
111       vf->offset-=more;
112     }else{
113       if(more==0){
114         /* send more paramedics */
115         if(!boundary)return(OV_FALSE);
116         {
117           long ret=_get_data(vf);
118           if(ret==0)return(OV_EOF);
119           if(ret<0)return(OV_EREAD);
120         }
121       }else{
122         /* got a page.  Return the offset at the page beginning,
123            advance the internal offset past the page end */
124         ogg_int64_t ret=vf->offset;
125         vf->offset+=more;
126         return(ret);
127         
128       }
129     }
130   }
131 }
132
133 /* find the latest page beginning before the current stream cursor
134    position. Much dirtier than the above as Ogg doesn't have any
135    backward search linkage.  no 'readp' as it will certainly have to
136    read. */
137 /* returns offset or OV_EREAD, OV_FAULT */
138 static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
139   ogg_int64_t begin=vf->offset;
140   ogg_int64_t end=begin;
141   ogg_int64_t ret;
142   ogg_int64_t offset=-1;
143
144   while(offset==-1){
145     begin-=CHUNKSIZE;
146     if(begin<0)
147       begin=0;
148     _seek_helper(vf,begin);
149     while(vf->offset<end){
150       ret=_get_next_page(vf,og,end-vf->offset);
151       if(ret==OV_EREAD)return(OV_EREAD);
152       if(ret<0){
153         break;
154       }else{
155         offset=ret;
156       }
157     }
158   }
159
160   /* we have the offset.  Actually snork and hold the page now */
161   _seek_helper(vf,offset);
162   ret=_get_next_page(vf,og,CHUNKSIZE);
163   if(ret<0)
164     /* this shouldn't be possible */
165     return(OV_EFAULT);
166
167   return(offset);
168 }
169
170 /* finds each bitstream link one at a time using a bisection search
171    (has to begin by knowing the offset of the lb's initial page).
172    Recurses for each link so it can alloc the link storage after
173    finding them all, then unroll and fill the cache at the same time */
174 static int _bisect_forward_serialno(OggVorbis_File *vf,
175                                     ogg_int64_t begin,
176                                     ogg_int64_t searched,
177                                     ogg_int64_t end,
178                                     long currentno,
179                                     long m){
180   ogg_int64_t endsearched=end;
181   ogg_int64_t next=end;
182   ogg_page og;
183   ogg_int64_t ret;
184   
185   /* the below guards against garbage seperating the last and
186      first pages of two links. */
187   while(searched<endsearched){
188     ogg_int64_t bisect;
189     
190     if(endsearched-searched<CHUNKSIZE){
191       bisect=searched;
192     }else{
193       bisect=(searched+endsearched)/2;
194     }
195     
196     _seek_helper(vf,bisect);
197     ret=_get_next_page(vf,&og,-1);
198     if(ret==OV_EREAD)return(OV_EREAD);
199     if(ret<0 || ogg_page_serialno(&og)!=currentno){
200       endsearched=bisect;
201       if(ret>=0)next=ret;
202     }else{
203       searched=ret+og.header_len+og.body_len;
204     }
205   }
206
207   _seek_helper(vf,next);
208   ret=_get_next_page(vf,&og,-1);
209   if(ret==OV_EREAD)return(OV_EREAD);
210   
211   if(searched>=end || ret<0){
212     vf->links=m+1;
213     vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
214     vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
215     vf->offsets[m+1]=searched;
216   }else{
217     ret=_bisect_forward_serialno(vf,next,vf->offset,
218                                  end,ogg_page_serialno(&og),m+1);
219     if(ret==OV_EREAD)return(OV_EREAD);
220   }
221   
222   vf->offsets[m]=begin;
223   vf->serialnos[m]=currentno;
224   return(0);
225 }
226
227 /* uses the local ogg_stream storage in vf; this is important for
228    non-streaming input sources */
229 static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
230                           long *serialno,ogg_page *og_ptr){
231   ogg_page og;
232   ogg_packet op;
233   int i,ret;
234   
235   if(!og_ptr){
236     ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
237     if(llret==OV_EREAD)return(OV_EREAD);
238     if(llret<0)return OV_ENOTVORBIS;
239     og_ptr=&og;
240   }
241
242   ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
243   if(serialno)*serialno=vf->os.serialno;
244   vf->ready_state=STREAMSET;
245   
246   /* extract the initial header from the first page and verify that the
247      Ogg bitstream is in fact Vorbis data */
248   
249   vorbis_info_init(vi);
250   vorbis_comment_init(vc);
251   
252   i=0;
253   while(i<3){
254     ogg_stream_pagein(&vf->os,og_ptr);
255     while(i<3){
256       int result=ogg_stream_packetout(&vf->os,&op);
257       if(result==0)break;
258       if(result==-1){
259         ret=OV_EBADHEADER;
260         goto bail_header;
261       }
262       if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
263         goto bail_header;
264       }
265       i++;
266     }
267     if(i<3)
268       if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
269         ret=OV_EBADHEADER;
270         goto bail_header;
271       }
272   }
273   return 0; 
274
275  bail_header:
276   vorbis_info_clear(vi);
277   vorbis_comment_clear(vc);
278   vf->ready_state=OPENED;
279
280   return ret;
281 }
282
283 /* last step of the OggVorbis_File initialization; get all the
284    vorbis_info structs and PCM positions.  Only called by the seekable
285    initialization (local stream storage is hacked slightly; pay
286    attention to how that's done) */
287
288 /* this is void and does not propogate errors up because we want to be
289    able to open and use damaged bitstreams as well as we can.  Just
290    watch out for missing information for links in the OggVorbis_File
291    struct */
292 static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){
293   ogg_page og;
294   int i;
295   ogg_int64_t ret;
296   
297   vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
298   vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
299   vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
300   vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
301   
302   for(i=0;i<vf->links;i++){
303     if(i==0){
304       /* we already grabbed the initial header earlier.  Just set the offset */
305       vf->dataoffsets[i]=dataoffset;
306       _seek_helper(vf,dataoffset);
307
308     }else{
309
310       /* seek to the location of the initial header */
311
312       _seek_helper(vf,vf->offsets[i]);
313       if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
314         vf->dataoffsets[i]=-1;
315       }else{
316         vf->dataoffsets[i]=vf->offset;
317       }
318     }
319
320     /* fetch beginning PCM offset */
321
322     if(vf->dataoffsets[i]!=-1){
323       ogg_int64_t accumulated=0;
324       long        lastblock=-1;
325       int         result;
326
327       ogg_stream_reset_serialno(&vf->os,vf->serialnos[i]);
328
329       while(1){
330         ogg_packet op;
331
332         ret=_get_next_page(vf,&og,-1);
333         if(ret<0)
334           /* this should not be possible unless the file is
335              truncated/mangled */
336           break;
337        
338         if(ogg_page_serialno(&og)!=vf->serialnos[i])
339           break;
340         
341         /* count blocksizes of all frames in the page */
342         ogg_stream_pagein(&vf->os,&og);
343         while((result=ogg_stream_packetout(&vf->os,&op))){
344           if(result>0){ /* ignore holes */
345             long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);
346             if(lastblock!=-1)
347               accumulated+=(lastblock+thisblock)>>2;
348             lastblock=thisblock;
349           }
350         }
351
352         if(ogg_page_granulepos(&og)!=-1){
353           /* pcm offset of last packet on the first audio page */
354           accumulated= ogg_page_granulepos(&og)-accumulated;
355           break;
356         }
357       }
358
359       /* less than zero?  This is a stream with samples trimmed off
360          the beginning, a normal occurrence; set the offset to zero */
361       if(accumulated<0)accumulated=0;
362
363       vf->pcmlengths[i*2]=accumulated;
364     }
365
366     /* get the PCM length of this link. To do this,
367        get the last page of the stream */
368     {
369       ogg_int64_t end=vf->offsets[i+1];
370       _seek_helper(vf,end);
371
372       while(1){
373         ret=_get_prev_page(vf,&og);
374         if(ret<0){
375           /* this should not be possible */
376           vorbis_info_clear(vf->vi+i);
377           vorbis_comment_clear(vf->vc+i);
378           break;
379         }
380         if(ogg_page_granulepos(&og)!=-1){
381           vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
382           break;
383         }
384         vf->offset=ret;
385       }
386     }
387   }
388 }
389
390 static int _make_decode_ready(OggVorbis_File *vf){
391   if(vf->ready_state>STREAMSET)return 0;
392   if(vf->ready_state<STREAMSET)return OV_EFAULT;
393   if(vf->seekable){
394     if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
395       return OV_EBADLINK;
396   }else{
397     if(vorbis_synthesis_init(&vf->vd,vf->vi))
398       return OV_EBADLINK;
399   }    
400   vorbis_block_init(&vf->vd,&vf->vb);
401   vf->ready_state=INITSET;
402   vf->bittrack=0.f;
403   vf->samptrack=0.f;
404   return 0;
405 }
406
407 static int _open_seekable2(OggVorbis_File *vf){
408   long serialno=vf->current_serialno;
409   ogg_int64_t dataoffset=vf->offset, end;
410   ogg_page og;
411
412   /* we're partially open and have a first link header state in
413      storage in vf */
414   /* we can seek, so set out learning all about this file */
415   (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
416   vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
417   
418   /* We get the offset for the last page of the physical bitstream.
419      Most OggVorbis files will contain a single logical bitstream */
420   end=_get_prev_page(vf,&og);
421   if(end<0)return(end);
422
423   /* more than one logical bitstream? */
424   if(ogg_page_serialno(&og)!=serialno){
425
426     /* Chained bitstream. Bisect-search each logical bitstream
427        section.  Do so based on serial number only */
428     if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
429
430   }else{
431
432     /* Only one logical bitstream */
433     if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
434
435   }
436
437   /* the initial header memory is referenced by vf after; don't free it */
438   _prefetch_all_headers(vf,dataoffset);
439   return(ov_raw_seek(vf,0));
440 }
441
442 /* clear out the current logical bitstream decoder */ 
443 static void _decode_clear(OggVorbis_File *vf){
444   vorbis_dsp_clear(&vf->vd);
445   vorbis_block_clear(&vf->vb);
446   vf->ready_state=OPENED;
447 }
448
449 /* fetch and process a packet.  Handles the case where we're at a
450    bitstream boundary and dumps the decoding machine.  If the decoding
451    machine is unloaded, it loads it.  It also keeps pcm_offset up to
452    date (seek and read both use this.  seek uses a special hack with
453    readp). 
454
455    return: <0) error, OV_HOLE (lost packet) or OV_EOF
456             0) need more data (only if readp==0)
457             1) got a packet 
458 */
459
460 static int _fetch_and_process_packet(OggVorbis_File *vf,
461                                      ogg_packet *op_in,
462                                      int readp,
463                                      int spanp){
464   ogg_page og;
465
466   /* handle one packet.  Try to fetch it from current stream state */
467   /* extract packets from page */
468   while(1){
469     
470     /* process a packet if we can.  If the machine isn't loaded,
471        neither is a page */
472     if(vf->ready_state==INITSET){
473       while(1) {
474         ogg_packet op;
475         ogg_packet *op_ptr=(op_in?op_in:&op);
476         int result=ogg_stream_packetout(&vf->os,op_ptr);
477         ogg_int64_t granulepos;
478
479         op_in=NULL;
480         if(result==-1)return(OV_HOLE); /* hole in the data. */
481         if(result>0){
482           /* got a packet.  process it */
483           granulepos=op_ptr->granulepos;
484           if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
485                                                     header handling.  The
486                                                     header packets aren't
487                                                     audio, so if/when we
488                                                     submit them,
489                                                     vorbis_synthesis will
490                                                     reject them */
491
492             /* suck in the synthesis data and track bitrate */
493             {
494               int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
495               /* for proper use of libvorbis within libvorbisfile,
496                  oldsamples will always be zero. */
497               if(oldsamples)return(OV_EFAULT);
498               
499               vorbis_synthesis_blockin(&vf->vd,&vf->vb);
500               vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
501               vf->bittrack+=op_ptr->bytes*8;
502             }
503           
504             /* update the pcm offset. */
505             if(granulepos!=-1 && !op_ptr->e_o_s){
506               int link=(vf->seekable?vf->current_link:0);
507               int i,samples;
508             
509               /* this packet has a pcm_offset on it (the last packet
510                  completed on a page carries the offset) After processing
511                  (above), we know the pcm position of the *last* sample
512                  ready to be returned. Find the offset of the *first*
513
514                  As an aside, this trick is inaccurate if we begin
515                  reading anew right at the last page; the end-of-stream
516                  granulepos declares the last frame in the stream, and the
517                  last packet of the last page may be a partial frame.
518                  So, we need a previous granulepos from an in-sequence page
519                  to have a reference point.  Thus the !op_ptr->e_o_s clause
520                  above */
521
522               if(vf->seekable && link>0)
523                 granulepos-=vf->pcmlengths[link*2];
524               if(granulepos<0)granulepos=0; /* actually, this
525                                                shouldn't be possible
526                                                here unless the stream
527                                                is very broken */
528
529               samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
530             
531               granulepos-=samples;
532               for(i=0;i<link;i++)
533                 granulepos+=vf->pcmlengths[i*2+1];
534               vf->pcm_offset=granulepos;
535             }
536             return(1);
537           }
538         }
539         else 
540           break;
541       }
542     }
543
544     if(vf->ready_state>=OPENED){
545       int ret;
546       if(!readp)return(0);
547       if((ret=_get_next_page(vf,&og,-1))<0){
548         return(OV_EOF); /* eof. 
549                            leave unitialized */
550       }
551
552         /* bitrate tracking; add the header's bytes here, the body bytes
553            are done by packet above */
554       vf->bittrack+=og.header_len*8;
555       
556       /* has our decoding just traversed a bitstream boundary? */
557       if(vf->ready_state==INITSET){
558         if(vf->current_serialno!=ogg_page_serialno(&og)){
559           if(!spanp)
560             return(OV_EOF);
561
562           _decode_clear(vf);
563           
564           if(!vf->seekable){
565             vorbis_info_clear(vf->vi);
566             vorbis_comment_clear(vf->vc);
567           }
568         }
569       }
570     }
571
572     /* Do we need to load a new machine before submitting the page? */
573     /* This is different in the seekable and non-seekable cases.  
574
575        In the seekable case, we already have all the header
576        information loaded and cached; we just initialize the machine
577        with it and continue on our merry way.
578
579        In the non-seekable (streaming) case, we'll only be at a
580        boundary if we just left the previous logical bitstream and
581        we're now nominally at the header of the next bitstream
582     */
583
584     if(vf->ready_state!=INITSET){ 
585       int link;
586
587       if(vf->ready_state<STREAMSET){
588         if(vf->seekable){
589           vf->current_serialno=ogg_page_serialno(&og);
590           
591           /* match the serialno to bitstream section.  We use this rather than
592              offset positions to avoid problems near logical bitstream
593              boundaries */
594           for(link=0;link<vf->links;link++)
595             if(vf->serialnos[link]==vf->current_serialno)break;
596           if(link==vf->links)return(OV_EBADLINK); /* sign of a bogus
597                                                      stream.  error out,
598                                                      leave machine
599                                                      uninitialized */
600           
601           vf->current_link=link;
602           
603           ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
604           vf->ready_state=STREAMSET;
605           
606         }else{
607           /* we're streaming */
608           /* fetch the three header packets, build the info struct */
609           
610           int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
611           if(ret)return(ret);
612           vf->current_link++;
613           link=0;
614         }
615       }
616       
617       {
618         int ret=_make_decode_ready(vf);
619         if(ret<0)return ret;
620       }
621     }
622     ogg_stream_pagein(&vf->os,&og);
623   }
624 }
625
626 /* if, eg, 64 bit stdio is configured by default, this will build with
627    fseek64 */
628 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
629   if(f==NULL)return(-1);
630   return fseek(f,off,whence);
631 }
632
633 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
634                      long ibytes, ov_callbacks callbacks){
635   int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
636   int ret;
637
638   memset(vf,0,sizeof(*vf));
639   vf->datasource=f;
640   vf->callbacks = callbacks;
641
642   /* init the framing state */
643   ogg_sync_init(&vf->oy);
644
645   /* perhaps some data was previously read into a buffer for testing
646      against other stream types.  Allow initialization from this
647      previously read data (as we may be reading from a non-seekable
648      stream) */
649   if(initial){
650     char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
651     memcpy(buffer,initial,ibytes);
652     ogg_sync_wrote(&vf->oy,ibytes);
653   }
654
655   /* can we seek? Stevens suggests the seek test was portable */
656   if(offsettest!=-1)vf->seekable=1;
657
658   /* No seeking yet; Set up a 'single' (current) logical bitstream
659      entry for partial open */
660   vf->links=1;
661   vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
662   vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
663   ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
664
665   /* Try to fetch the headers, maintaining all the storage */
666   if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
667     vf->datasource=NULL;
668     ov_clear(vf);
669   }else 
670     vf->ready_state=PARTOPEN;
671   return(ret);
672 }
673
674 static int _ov_open2(OggVorbis_File *vf){
675   if(vf->ready_state != PARTOPEN) return OV_EINVAL;
676   vf->ready_state=OPENED;
677   if(vf->seekable){
678     int ret=_open_seekable2(vf);
679     if(ret){
680       vf->datasource=NULL;
681       ov_clear(vf);
682     }
683     return(ret);
684   }else
685     vf->ready_state=STREAMSET;
686
687   return 0;
688 }
689
690
691 /* clear out the OggVorbis_File struct */
692 int ov_clear(OggVorbis_File *vf){
693   if(vf){
694     vorbis_block_clear(&vf->vb);
695     vorbis_dsp_clear(&vf->vd);
696     ogg_stream_clear(&vf->os);
697     
698     if(vf->vi && vf->links){
699       int i;
700       for(i=0;i<vf->links;i++){
701         vorbis_info_clear(vf->vi+i);
702         vorbis_comment_clear(vf->vc+i);
703       }
704       _ogg_free(vf->vi);
705       _ogg_free(vf->vc);
706     }
707     if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
708     if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
709     if(vf->serialnos)_ogg_free(vf->serialnos);
710     if(vf->offsets)_ogg_free(vf->offsets);
711     ogg_sync_clear(&vf->oy);
712     if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
713     memset(vf,0,sizeof(*vf));
714   }
715 #ifdef DEBUG_LEAKS
716   _VDBG_dump();
717 #endif
718   return(0);
719 }
720
721 /* inspects the OggVorbis file and finds/documents all the logical
722    bitstreams contained in it.  Tries to be tolerant of logical
723    bitstream sections that are truncated/woogie. 
724
725    return: -1) error
726             0) OK
727 */
728
729 int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
730     ov_callbacks callbacks){
731   int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
732   if(ret)return ret;
733   return _ov_open2(vf);
734 }
735
736 int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
737   ov_callbacks callbacks = {
738     (size_t (*)(void *, size_t, size_t, void *))  fread,
739     (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
740     (int (*)(void *))                             fclose,
741     (long (*)(void *))                            ftell
742   };
743
744   return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
745 }
746  
747 /* cheap hack for game usage where downsampling is desirable; there's
748    no need for SRC as we can just do it cheaply in libvorbis. */
749  
750 int ov_halfrate(OggVorbis_File *vf,int flag){
751   int i;
752   if(vf->vi==NULL)return OV_EINVAL;
753   if(!vf->seekable)return OV_EINVAL;
754   if(vf->ready_state>=STREAMSET)
755     _decode_clear(vf); /* clear out stream state; later on libvorbis
756                           will be able to swap this on the fly, but
757                           for now dumping the decode machine is needed
758                           to reinit the MDCT lookups.  1.1 libvorbis
759                           is planned to be able to switch on the fly */
760   
761   for(i=0;i<vf->links;i++){
762     if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
763       ov_halfrate(vf,0);
764       return OV_EINVAL;
765     }
766   }
767   return 0;
768 }
769
770 int ov_halfrate_p(OggVorbis_File *vf){
771   if(vf->vi==NULL)return OV_EINVAL;
772   return vorbis_synthesis_halfrate_p(vf->vi);
773 }
774
775 /* Only partially open the vorbis file; test for Vorbisness, and load
776    the headers for the first chain.  Do not seek (although test for
777    seekability).  Use ov_test_open to finish opening the file, else
778    ov_clear to close/free it. Same return codes as open. */
779
780 int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
781     ov_callbacks callbacks)
782 {
783   return _ov_open1(f,vf,initial,ibytes,callbacks);
784 }
785
786 int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
787   ov_callbacks callbacks = {
788     (size_t (*)(void *, size_t, size_t, void *))  fread,
789     (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
790     (int (*)(void *))                             fclose,
791     (long (*)(void *))                            ftell
792   };
793
794   return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
795 }
796   
797 int ov_test_open(OggVorbis_File *vf){
798   if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
799   return _ov_open2(vf);
800 }
801
802 /* How many logical bitstreams in this physical bitstream? */
803 long ov_streams(OggVorbis_File *vf){
804   return vf->links;
805 }
806
807 /* Is the FILE * associated with vf seekable? */
808 long ov_seekable(OggVorbis_File *vf){
809   return vf->seekable;
810 }
811
812 /* returns the bitrate for a given logical bitstream or the entire
813    physical bitstream.  If the file is open for random access, it will
814    find the *actual* average bitrate.  If the file is streaming, it
815    returns the nominal bitrate (if set) else the average of the
816    upper/lower bounds (if set) else -1 (unset).
817
818    If you want the actual bitrate field settings, get them from the
819    vorbis_info structs */
820
821 long ov_bitrate(OggVorbis_File *vf,int i){
822   if(vf->ready_state<OPENED)return(OV_EINVAL);
823   if(i>=vf->links)return(OV_EINVAL);
824   if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
825   if(i<0){
826     ogg_int64_t bits=0;
827     int i;
828     float br;
829     for(i=0;i<vf->links;i++)
830       bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
831     /* This once read: return(rint(bits/ov_time_total(vf,-1)));
832      * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
833      * so this is slightly transformed to make it work.
834      */
835     br = bits/ov_time_total(vf,-1);
836     return(rint(br));
837   }else{
838     if(vf->seekable){
839       /* return the actual bitrate */
840       return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
841     }else{
842       /* return nominal if set */
843       if(vf->vi[i].bitrate_nominal>0){
844         return vf->vi[i].bitrate_nominal;
845       }else{
846         if(vf->vi[i].bitrate_upper>0){
847           if(vf->vi[i].bitrate_lower>0){
848             return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
849           }else{
850             return vf->vi[i].bitrate_upper;
851           }
852         }
853         return(OV_FALSE);
854       }
855     }
856   }
857 }
858
859 /* returns the actual bitrate since last call.  returns -1 if no
860    additional data to offer since last call (or at beginning of stream),
861    EINVAL if stream is only partially open 
862 */
863 long ov_bitrate_instant(OggVorbis_File *vf){
864   int link=(vf->seekable?vf->current_link:0);
865   long ret;
866   if(vf->ready_state<OPENED)return(OV_EINVAL);
867   if(vf->samptrack==0)return(OV_FALSE);
868   ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
869   vf->bittrack=0.f;
870   vf->samptrack=0.f;
871   return(ret);
872 }
873
874 /* Guess */
875 long ov_serialnumber(OggVorbis_File *vf,int i){
876   if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
877   if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
878   if(i<0){
879     return(vf->current_serialno);
880   }else{
881     return(vf->serialnos[i]);
882   }
883 }
884
885 /* returns: total raw (compressed) length of content if i==-1
886             raw (compressed) length of that logical bitstream for i==0 to n
887             OV_EINVAL if the stream is not seekable (we can't know the length)
888             or if stream is only partially open
889 */
890 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
891   if(vf->ready_state<OPENED)return(OV_EINVAL);
892   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
893   if(i<0){
894     ogg_int64_t acc=0;
895     int i;
896     for(i=0;i<vf->links;i++)
897       acc+=ov_raw_total(vf,i);
898     return(acc);
899   }else{
900     return(vf->offsets[i+1]-vf->offsets[i]);
901   }
902 }
903
904 /* returns: total PCM length (samples) of content if i==-1 PCM length
905             (samples) of that logical bitstream for i==0 to n
906             OV_EINVAL if the stream is not seekable (we can't know the
907             length) or only partially open 
908 */
909 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
910   if(vf->ready_state<OPENED)return(OV_EINVAL);
911   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
912   if(i<0){
913     ogg_int64_t acc=0;
914     int i;
915     for(i=0;i<vf->links;i++)
916       acc+=ov_pcm_total(vf,i);
917     return(acc);
918   }else{
919     return(vf->pcmlengths[i*2+1]);
920   }
921 }
922
923 /* returns: total seconds of content if i==-1
924             seconds in that logical bitstream for i==0 to n
925             OV_EINVAL if the stream is not seekable (we can't know the
926             length) or only partially open 
927 */
928 double ov_time_total(OggVorbis_File *vf,int i){
929   if(vf->ready_state<OPENED)return(OV_EINVAL);
930   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
931   if(i<0){
932     double acc=0;
933     int i;
934     for(i=0;i<vf->links;i++)
935       acc+=ov_time_total(vf,i);
936     return(acc);
937   }else{
938     return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
939   }
940 }
941
942 /* seek to an offset relative to the *compressed* data. This also
943    scans packets to update the PCM cursor. It will cross a logical
944    bitstream boundary, but only if it can't get any packets out of the
945    tail of the bitstream we seek to (so no surprises).
946
947    returns zero on success, nonzero on failure */
948
949 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
950   ogg_stream_state work_os;
951
952   if(vf->ready_state<OPENED)return(OV_EINVAL);
953   if(!vf->seekable)
954     return(OV_ENOSEEK); /* don't dump machine if we can't seek */
955
956   if(pos<0 || pos>vf->end)return(OV_EINVAL);
957
958   /* don't yet clear out decoding machine (if it's initialized), in
959      the case we're in the same link.  Restart the decode lapping, and
960      let _fetch_and_process_packet deal with a potential bitstream
961      boundary */
962   vf->pcm_offset=-1;
963   ogg_stream_reset_serialno(&vf->os,
964                             vf->current_serialno); /* must set serialno */
965   vorbis_synthesis_restart(&vf->vd);
966     
967   _seek_helper(vf,pos);
968
969   /* we need to make sure the pcm_offset is set, but we don't want to
970      advance the raw cursor past good packets just to get to the first
971      with a granulepos.  That's not equivalent behavior to beginning
972      decoding as immediately after the seek position as possible.
973
974      So, a hack.  We use two stream states; a local scratch state and
975      the shared vf->os stream state.  We use the local state to
976      scan, and the shared state as a buffer for later decode. 
977
978      Unfortuantely, on the last page we still advance to last packet
979      because the granulepos on the last page is not necessarily on a
980      packet boundary, and we need to make sure the granpos is
981      correct. 
982   */
983
984   {
985     ogg_page og;
986     ogg_packet op;
987     int lastblock=0;
988     int accblock=0;
989     int thisblock;
990     int eosflag;
991
992     ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
993     ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
994                                    return from not necessarily
995                                    starting from the beginning */
996
997     while(1){
998       if(vf->ready_state>=STREAMSET){
999         /* snarf/scan a packet if we can */
1000         int result=ogg_stream_packetout(&work_os,&op);
1001       
1002         if(result>0){
1003
1004           if(vf->vi[vf->current_link].codec_setup){
1005             thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1006             if(thisblock<0){
1007               ogg_stream_packetout(&vf->os,NULL);
1008               thisblock=0;
1009             }else{
1010               
1011               if(eosflag)
1012               ogg_stream_packetout(&vf->os,NULL);
1013               else
1014                 if(lastblock)accblock+=(lastblock+thisblock)>>2;
1015             }       
1016
1017             if(op.granulepos!=-1){
1018               int i,link=vf->current_link;
1019               ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1020               if(granulepos<0)granulepos=0;
1021               
1022               for(i=0;i<link;i++)
1023                 granulepos+=vf->pcmlengths[i*2+1];
1024               vf->pcm_offset=granulepos-accblock;
1025               break;
1026             }
1027             lastblock=thisblock;
1028             continue;
1029           }else
1030             ogg_stream_packetout(&vf->os,NULL);
1031         }
1032       }
1033       
1034       if(!lastblock){
1035         if(_get_next_page(vf,&og,-1)<0){
1036           vf->pcm_offset=ov_pcm_total(vf,-1);
1037           break;
1038         }
1039       }else{
1040         /* huh?  Bogus stream with packets but no granulepos */
1041         vf->pcm_offset=-1;
1042         break;
1043       }
1044       
1045       /* has our decoding just traversed a bitstream boundary? */
1046       if(vf->ready_state>=STREAMSET)
1047         if(vf->current_serialno!=ogg_page_serialno(&og)){
1048           _decode_clear(vf); /* clear out stream state */
1049           ogg_stream_clear(&work_os);
1050         }
1051
1052       if(vf->ready_state<STREAMSET){
1053         int link;
1054         
1055         vf->current_serialno=ogg_page_serialno(&og);
1056         for(link=0;link<vf->links;link++)
1057           if(vf->serialnos[link]==vf->current_serialno)break;
1058         if(link==vf->links)goto seek_error; /* sign of a bogus stream.
1059                                                error out, leave
1060                                                machine uninitialized */
1061         vf->current_link=link;
1062         
1063         ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1064         ogg_stream_reset_serialno(&work_os,vf->current_serialno); 
1065         vf->ready_state=STREAMSET;
1066         
1067       }
1068     
1069       ogg_stream_pagein(&vf->os,&og);
1070       ogg_stream_pagein(&work_os,&og);
1071       eosflag=ogg_page_eos(&og);
1072     }
1073   }
1074
1075   ogg_stream_clear(&work_os);
1076   vf->bittrack=0.f;
1077   vf->samptrack=0.f;
1078   return(0);
1079
1080  seek_error:
1081   /* dump the machine so we're in a known state */
1082   vf->pcm_offset=-1;
1083   ogg_stream_clear(&work_os);
1084   _decode_clear(vf);
1085   return OV_EBADLINK;
1086 }
1087
1088 /* Page granularity seek (faster than sample granularity because we
1089    don't do the last bit of decode to find a specific sample).
1090
1091    Seek to the last [granule marked] page preceeding the specified pos
1092    location, such that decoding past the returned point will quickly
1093    arrive at the requested position. */
1094 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1095   int link=-1;
1096   ogg_int64_t result=0;
1097   ogg_int64_t total=ov_pcm_total(vf,-1);
1098
1099   if(vf->ready_state<OPENED)return(OV_EINVAL);
1100   if(!vf->seekable)return(OV_ENOSEEK);
1101
1102   if(pos<0 || pos>total)return(OV_EINVAL);
1103  
1104   /* which bitstream section does this pcm offset occur in? */
1105   for(link=vf->links-1;link>=0;link--){
1106     total-=vf->pcmlengths[link*2+1];
1107     if(pos>=total)break;
1108   }
1109
1110   /* search within the logical bitstream for the page with the highest
1111      pcm_pos preceeding (or equal to) pos.  There is a danger here;
1112      missing pages or incorrect frame number information in the
1113      bitstream could make our task impossible.  Account for that (it
1114      would be an error condition) */
1115
1116   /* new search algorithm by HB (Nicholas Vinen) */
1117   {
1118     ogg_int64_t end=vf->offsets[link+1];
1119     ogg_int64_t begin=vf->offsets[link];
1120     ogg_int64_t begintime = vf->pcmlengths[link*2];
1121     ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1122     ogg_int64_t target=pos-total+begintime;
1123     ogg_int64_t best=begin;
1124     
1125     ogg_page og;
1126     while(begin<end){
1127       ogg_int64_t bisect;
1128       
1129       if(end-begin<CHUNKSIZE){
1130         bisect=begin;
1131       }else{
1132         /* take a (pretty decent) guess. */
1133         bisect=begin + 
1134           (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
1135         if(bisect<=begin)
1136           bisect=begin+1;
1137       }
1138       
1139       _seek_helper(vf,bisect);
1140     
1141       while(begin<end){
1142         result=_get_next_page(vf,&og,end-vf->offset);
1143         if(result==OV_EREAD) goto seek_error;
1144         if(result<0){
1145           if(bisect<=begin+1)
1146             end=begin; /* found it */
1147           else{
1148             if(bisect==0) goto seek_error;
1149             bisect-=CHUNKSIZE;
1150             if(bisect<=begin)bisect=begin+1;
1151             _seek_helper(vf,bisect);
1152           }
1153         }else{
1154           ogg_int64_t granulepos=ogg_page_granulepos(&og);
1155           if(granulepos==-1)continue;
1156           if(granulepos<target){
1157             best=result;  /* raw offset of packet with granulepos */ 
1158             begin=vf->offset; /* raw offset of next page */
1159             begintime=granulepos;
1160             
1161             if(target-begintime>44100)break;
1162             bisect=begin; /* *not* begin + 1 */
1163           }else{
1164             if(bisect<=begin+1)
1165               end=begin;  /* found it */
1166             else{
1167               if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1168                 end=result;
1169                 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1170                 if(bisect<=begin)bisect=begin+1;
1171                 _seek_helper(vf,bisect);
1172               }else{
1173                 end=result;
1174                 endtime=granulepos;
1175                 break;
1176               }
1177             }
1178           }
1179         }
1180       }
1181     }
1182
1183     /* found our page. seek to it, update pcm offset. Easier case than
1184        raw_seek, don't keep packets preceeding granulepos. */
1185     {
1186       ogg_page og;
1187       ogg_packet op;
1188       
1189       /* seek */
1190       _seek_helper(vf,best);
1191       vf->pcm_offset=-1;
1192       
1193       if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* shouldn't happen */
1194       
1195       if(link!=vf->current_link){
1196         /* Different link; dump entire decode machine */
1197         _decode_clear(vf);  
1198         
1199         vf->current_link=link;
1200         vf->current_serialno=ogg_page_serialno(&og);
1201         vf->ready_state=STREAMSET;
1202         
1203       }else{
1204         vorbis_synthesis_restart(&vf->vd);
1205       }
1206
1207       ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1208       ogg_stream_pagein(&vf->os,&og);
1209
1210       /* pull out all but last packet; the one with granulepos */
1211       while(1){
1212         result=ogg_stream_packetpeek(&vf->os,&op);
1213         if(result==0){
1214           /* !!! the packet finishing this page originated on a
1215              preceeding page. Keep fetching previous pages until we
1216              get one with a granulepos or without the 'continued' flag
1217              set.  Then just use raw_seek for simplicity. */
1218           
1219           _seek_helper(vf,best);
1220           
1221           while(1){
1222             result=_get_prev_page(vf,&og);
1223             if(result<0) goto seek_error;
1224             if(ogg_page_granulepos(&og)>-1 ||
1225                !ogg_page_continued(&og)){
1226               return ov_raw_seek(vf,result);
1227             }
1228             vf->offset=result;
1229           }
1230         }
1231         if(result<0){
1232           result = OV_EBADPACKET; 
1233           goto seek_error;
1234         }
1235         if(op.granulepos!=-1){
1236           vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1237           if(vf->pcm_offset<0)vf->pcm_offset=0;
1238           vf->pcm_offset+=total;
1239           break;
1240         }else
1241           result=ogg_stream_packetout(&vf->os,NULL);
1242       }
1243     }
1244   }
1245   
1246   /* verify result */
1247   if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1248     result=OV_EFAULT;
1249     goto seek_error;
1250   }
1251   vf->bittrack=0.f;
1252   vf->samptrack=0.f;
1253   return(0);
1254   
1255  seek_error:
1256   /* dump machine so we're in a known state */
1257   vf->pcm_offset=-1;
1258   _decode_clear(vf);
1259   return (int)result;
1260 }
1261
1262 /* seek to a sample offset relative to the decompressed pcm stream 
1263    returns zero on success, nonzero on failure */
1264
1265 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1266   int thisblock,lastblock=0;
1267   int ret=ov_pcm_seek_page(vf,pos);
1268   if(ret<0)return(ret);
1269   if((ret=_make_decode_ready(vf)))return ret;
1270
1271   /* discard leading packets we don't need for the lapping of the
1272      position we want; don't decode them */
1273
1274   while(1){
1275     ogg_packet op;
1276     ogg_page og;
1277
1278     int ret=ogg_stream_packetpeek(&vf->os,&op);
1279     if(ret>0){
1280       thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1281       if(thisblock<0){
1282         ogg_stream_packetout(&vf->os,NULL);
1283         continue; /* non audio packet */
1284       }
1285       if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1286       
1287       if(vf->pcm_offset+((thisblock+
1288                           vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1289       
1290       /* remove the packet from packet queue and track its granulepos */
1291       ogg_stream_packetout(&vf->os,NULL);
1292       vorbis_synthesis_trackonly(&vf->vb,&op);  /* set up a vb with
1293                                                    only tracking, no
1294                                                    pcm_decode */
1295       vorbis_synthesis_blockin(&vf->vd,&vf->vb); 
1296       
1297       /* end of logical stream case is hard, especially with exact
1298          length positioning. */
1299       
1300       if(op.granulepos>-1){
1301         int i;
1302         /* always believe the stream markers */
1303         vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1304         if(vf->pcm_offset<0)vf->pcm_offset=0;
1305         for(i=0;i<vf->current_link;i++)
1306           vf->pcm_offset+=vf->pcmlengths[i*2+1];
1307       }
1308         
1309       lastblock=thisblock;
1310       
1311     }else{
1312       if(ret<0 && ret!=OV_HOLE)break;
1313       
1314       /* suck in a new page */
1315       if(_get_next_page(vf,&og,-1)<0)break;
1316       if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
1317       
1318       if(vf->ready_state<STREAMSET){
1319         int link;
1320         
1321         vf->current_serialno=ogg_page_serialno(&og);
1322         for(link=0;link<vf->links;link++)
1323           if(vf->serialnos[link]==vf->current_serialno)break;
1324         if(link==vf->links)return(OV_EBADLINK);
1325         vf->current_link=link;
1326         
1327         ogg_stream_reset_serialno(&vf->os,vf->current_serialno); 
1328         vf->ready_state=STREAMSET;      
1329         ret=_make_decode_ready(vf);
1330         if(ret)return ret;
1331         lastblock=0;
1332       }
1333
1334       ogg_stream_pagein(&vf->os,&og);
1335     }
1336   }
1337
1338   vf->bittrack=0.f;
1339   vf->samptrack=0.f;
1340   /* discard samples until we reach the desired position. Crossing a
1341      logical bitstream boundary with abandon is OK. */
1342   while(vf->pcm_offset<pos){
1343     ogg_int64_t target=pos-vf->pcm_offset;
1344     long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1345
1346     if(samples>target)samples=target;
1347     vorbis_synthesis_read(&vf->vd,samples);
1348     vf->pcm_offset+=samples;
1349     
1350     if(samples<target)
1351       if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
1352         vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1353   }
1354   return 0;
1355 }
1356
1357 /* seek to a playback time relative to the decompressed pcm stream 
1358    returns zero on success, nonzero on failure */
1359 int ov_time_seek(OggVorbis_File *vf,double seconds){
1360   /* translate time to PCM position and call ov_pcm_seek */
1361
1362   int link=-1;
1363   ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
1364   double time_total=ov_time_total(vf,-1);
1365
1366   if(vf->ready_state<OPENED)return(OV_EINVAL);
1367   if(!vf->seekable)return(OV_ENOSEEK);
1368   if(seconds<0 || seconds>time_total)return(OV_EINVAL);
1369   
1370   /* which bitstream section does this time offset occur in? */
1371   for(link=vf->links-1;link>=0;link--){
1372     pcm_total-=vf->pcmlengths[link*2+1];
1373     time_total-=ov_time_total(vf,link);
1374     if(seconds>=time_total)break;
1375   }
1376
1377   /* enough information to convert time offset to pcm offset */
1378   {
1379     ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1380     return(ov_pcm_seek(vf,target));
1381   }
1382 }
1383
1384 /* page-granularity version of ov_time_seek 
1385    returns zero on success, nonzero on failure */
1386 int ov_time_seek_page(OggVorbis_File *vf,double seconds){
1387   /* translate time to PCM position and call ov_pcm_seek */
1388
1389   int link=-1;
1390   ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
1391   double time_total=ov_time_total(vf,-1);
1392
1393   if(vf->ready_state<OPENED)return(OV_EINVAL);
1394   if(!vf->seekable)return(OV_ENOSEEK);
1395   if(seconds<0 || seconds>time_total)return(OV_EINVAL);
1396   
1397   /* which bitstream section does this time offset occur in? */
1398   for(link=vf->links-1;link>=0;link--){
1399     pcm_total-=vf->pcmlengths[link*2+1];
1400     time_total-=ov_time_total(vf,link);
1401     if(seconds>=time_total)break;
1402   }
1403
1404   /* enough information to convert time offset to pcm offset */
1405   {
1406     ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1407     return(ov_pcm_seek_page(vf,target));
1408   }
1409 }
1410
1411 /* tell the current stream offset cursor.  Note that seek followed by
1412    tell will likely not give the set offset due to caching */
1413 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1414   if(vf->ready_state<OPENED)return(OV_EINVAL);
1415   return(vf->offset);
1416 }
1417
1418 /* return PCM offset (sample) of next PCM sample to be read */
1419 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
1420   if(vf->ready_state<OPENED)return(OV_EINVAL);
1421   return(vf->pcm_offset);
1422 }
1423
1424 /* return time offset (seconds) of next PCM sample to be read */
1425 double ov_time_tell(OggVorbis_File *vf){
1426   int link=0;
1427   ogg_int64_t pcm_total=0;
1428   double time_total=0.f;
1429   
1430   if(vf->ready_state<OPENED)return(OV_EINVAL);
1431   if(vf->seekable){
1432     pcm_total=ov_pcm_total(vf,-1);
1433     time_total=ov_time_total(vf,-1);
1434   
1435     /* which bitstream section does this time offset occur in? */
1436     for(link=vf->links-1;link>=0;link--){
1437       pcm_total-=vf->pcmlengths[link*2+1];
1438       time_total-=ov_time_total(vf,link);
1439       if(vf->pcm_offset>=pcm_total)break;
1440     }
1441   }
1442
1443   return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1444 }
1445
1446 /*  link:   -1) return the vorbis_info struct for the bitstream section
1447                 currently being decoded
1448            0-n) to request information for a specific bitstream section
1449     
1450     In the case of a non-seekable bitstream, any call returns the
1451     current bitstream.  NULL in the case that the machine is not
1452     initialized */
1453
1454 vorbis_info *ov_info(OggVorbis_File *vf,int link){
1455   if(vf->seekable){
1456     if(link<0)
1457       if(vf->ready_state>=STREAMSET)
1458         return vf->vi+vf->current_link;
1459       else
1460       return vf->vi;
1461     else
1462       if(link>=vf->links)
1463         return NULL;
1464       else
1465         return vf->vi+link;
1466   }else{
1467     return vf->vi;
1468   }
1469 }
1470
1471 /* grr, strong typing, grr, no templates/inheritence, grr */
1472 vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
1473   if(vf->seekable){
1474     if(link<0)
1475       if(vf->ready_state>=STREAMSET)
1476         return vf->vc+vf->current_link;
1477       else
1478         return vf->vc;
1479     else
1480       if(link>=vf->links)
1481         return NULL;
1482       else
1483         return vf->vc+link;
1484   }else{
1485     return vf->vc;
1486   }
1487 }
1488
1489 static int host_is_big_endian() {
1490   ogg_int32_t pattern = 0xfeedface; /* deadbeef */
1491   unsigned char *bytewise = (unsigned char *)&pattern;
1492   if (bytewise[0] == 0xfe) return 1;
1493   return 0;
1494 }
1495
1496 /* up to this point, everything could more or less hide the multiple
1497    logical bitstream nature of chaining from the toplevel application
1498    if the toplevel application didn't particularly care.  However, at
1499    the point that we actually read audio back, the multiple-section
1500    nature must surface: Multiple bitstream sections do not necessarily
1501    have to have the same number of channels or sampling rate.
1502
1503    ov_read returns the sequential logical bitstream number currently
1504    being decoded along with the PCM data in order that the toplevel
1505    application can take action on channel/sample rate changes.  This
1506    number will be incremented even for streamed (non-seekable) streams
1507    (for seekable streams, it represents the actual logical bitstream
1508    index within the physical bitstream.  Note that the accessor
1509    functions above are aware of this dichotomy).
1510
1511    input values: buffer) a buffer to hold packed PCM data for return
1512                  length) the byte length requested to be placed into buffer
1513                  bigendianp) should the data be packed LSB first (0) or
1514                              MSB first (1)
1515                  word) word size for output.  currently 1 (byte) or 
1516                        2 (16 bit short)
1517
1518    return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1519                    0) EOF
1520                    n) number of bytes of PCM actually returned.  The
1521                    below works on a packet-by-packet basis, so the
1522                    return length is not related to the 'length' passed
1523                    in, just guaranteed to fit.
1524
1525             *section) set to the logical bitstream number */
1526
1527 long ov_read(OggVorbis_File *vf,char *buffer,int length,
1528                     int bigendianp,int word,int sgned,int *bitstream){
1529   int i,j;
1530   int host_endian = host_is_big_endian();
1531
1532   float **pcm;
1533   long samples;
1534
1535   if(vf->ready_state<OPENED)return(OV_EINVAL);
1536
1537   while(1){
1538     if(vf->ready_state==INITSET){
1539       samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1540       if(samples)break;
1541     }
1542
1543     /* suck in another packet */
1544     {
1545       int ret=_fetch_and_process_packet(vf,NULL,1,1);
1546       if(ret==OV_EOF)
1547         return(0);
1548       if(ret<=0)
1549         return(ret);
1550     }
1551
1552   }
1553
1554   if(samples>0){
1555   
1556     /* yay! proceed to pack data into the byte buffer */
1557     
1558     long channels=ov_info(vf,-1)->channels;
1559     long bytespersample=word * channels;
1560     vorbis_fpu_control fpu;
1561     if(samples>length/bytespersample)samples=length/bytespersample;
1562
1563     if(samples <= 0)
1564       return OV_EINVAL;
1565     
1566     /* a tight loop to pack each size */
1567     {
1568       int val;
1569       if(word==1){
1570         int off=(sgned?0:128);
1571         vorbis_fpu_setround(&fpu);
1572         for(j=0;j<samples;j++)
1573           for(i=0;i<channels;i++){
1574             val=vorbis_ftoi(pcm[i][j]*128.f);
1575             if(val>127)val=127;
1576             else if(val<-128)val=-128;
1577             *buffer++=val+off;
1578           }
1579         vorbis_fpu_restore(fpu);
1580       }else{
1581         int off=(sgned?0:32768);
1582         
1583         if(host_endian==bigendianp){
1584           if(sgned){
1585             
1586             vorbis_fpu_setround(&fpu);
1587             for(i=0;i<channels;i++) { /* It's faster in this order */
1588               float *src=pcm[i];
1589               short *dest=((short *)buffer)+i;
1590               for(j=0;j<samples;j++) {
1591                 val=vorbis_ftoi(src[j]*32768.f);
1592                 if(val>32767)val=32767;
1593                 else if(val<-32768)val=-32768;
1594                 *dest=val;
1595                 dest+=channels;
1596               }
1597             }
1598             vorbis_fpu_restore(fpu);
1599             
1600           }else{
1601             
1602             vorbis_fpu_setround(&fpu);
1603             for(i=0;i<channels;i++) {
1604               float *src=pcm[i];
1605               short *dest=((short *)buffer)+i;
1606               for(j=0;j<samples;j++) {
1607                 val=vorbis_ftoi(src[j]*32768.f);
1608                 if(val>32767)val=32767;
1609                 else if(val<-32768)val=-32768;
1610                 *dest=val+off;
1611                 dest+=channels;
1612               }
1613             }
1614             vorbis_fpu_restore(fpu);
1615             
1616           }
1617         }else if(bigendianp){
1618           
1619           vorbis_fpu_setround(&fpu);
1620           for(j=0;j<samples;j++)
1621             for(i=0;i<channels;i++){
1622               val=vorbis_ftoi(pcm[i][j]*32768.f);
1623               if(val>32767)val=32767;
1624               else if(val<-32768)val=-32768;
1625               val+=off;
1626               *buffer++=(val>>8);
1627               *buffer++=(val&0xff);
1628             }
1629           vorbis_fpu_restore(fpu);
1630           
1631         }else{
1632           int val;
1633           vorbis_fpu_setround(&fpu);
1634           for(j=0;j<samples;j++)
1635             for(i=0;i<channels;i++){
1636               val=vorbis_ftoi(pcm[i][j]*32768.f);
1637               if(val>32767)val=32767;
1638               else if(val<-32768)val=-32768;
1639               val+=off;
1640               *buffer++=(val&0xff);
1641               *buffer++=(val>>8);
1642                 }
1643           vorbis_fpu_restore(fpu);  
1644           
1645         }
1646       }
1647     }
1648     
1649     vorbis_synthesis_read(&vf->vd,samples);
1650     vf->pcm_offset+=samples;
1651     if(bitstream)*bitstream=vf->current_link;
1652     return(samples*bytespersample);
1653   }else{
1654     return(samples);
1655   }
1656 }
1657
1658 /* input values: pcm_channels) a float vector per channel of output
1659                  length) the sample length being read by the app
1660
1661    return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1662                    0) EOF
1663                    n) number of samples of PCM actually returned.  The
1664                    below works on a packet-by-packet basis, so the
1665                    return length is not related to the 'length' passed
1666                    in, just guaranteed to fit.
1667
1668             *section) set to the logical bitstream number */
1669
1670
1671
1672 long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
1673                    int *bitstream){
1674
1675   if(vf->ready_state<OPENED)return(OV_EINVAL);
1676
1677   while(1){
1678     if(vf->ready_state==INITSET){
1679       float **pcm;
1680       long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1681       if(samples){
1682         if(pcm_channels)*pcm_channels=pcm;
1683         if(samples>length)samples=length;
1684         vorbis_synthesis_read(&vf->vd,samples);
1685         vf->pcm_offset+=samples;
1686         if(bitstream)*bitstream=vf->current_link;
1687         return samples;
1688
1689       }
1690     }
1691
1692     /* suck in another packet */
1693     {
1694       int ret=_fetch_and_process_packet(vf,NULL,1,1);
1695       if(ret==OV_EOF)return(0);
1696       if(ret<=0)return(ret);
1697     }
1698
1699   }
1700 }
1701
1702 extern float *vorbis_window(vorbis_dsp_state *v,int W);
1703 extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,
1704                              ogg_int64_t off);
1705
1706 static void _ov_splice(float **pcm,float **lappcm,
1707                        int n1, int n2,
1708                        int ch1, int ch2,
1709                        float *w1, float *w2){
1710   int i,j;
1711   float *w=w1;
1712   int n=n1;
1713
1714   if(n1>n2){
1715     n=n2;
1716     w=w2;
1717   }
1718
1719   /* splice */
1720   for(j=0;j<ch1 && j<ch2;j++){
1721     float *s=lappcm[j];
1722     float *d=pcm[j];
1723
1724     for(i=0;i<n;i++){
1725       float wd=w[i]*w[i];
1726       float ws=1.-wd;
1727       d[i]=d[i]*wd + s[i]*ws;
1728     }
1729   }
1730   /* window from zero */
1731   for(;j<ch2;j++){
1732     float *d=pcm[j];
1733     for(i=0;i<n;i++){
1734       float wd=w[i]*w[i];
1735       d[i]=d[i]*wd;
1736     }
1737   }
1738
1739 }
1740                 
1741 /* make sure vf is INITSET */
1742 static int _ov_initset(OggVorbis_File *vf){
1743   while(1){
1744     if(vf->ready_state==INITSET)break;
1745     /* suck in another packet */
1746     {
1747       int ret=_fetch_and_process_packet(vf,NULL,1,0);
1748       if(ret<0 && ret!=OV_HOLE)return(ret);
1749     }
1750   }
1751   return 0;
1752 }
1753
1754 /* make sure vf is INITSET and that we have a primed buffer; if
1755    we're crosslapping at a stream section boundary, this also makes
1756    sure we're sanity checking against the right stream information */
1757 static int _ov_initprime(OggVorbis_File *vf){
1758   vorbis_dsp_state *vd=&vf->vd;
1759   while(1){
1760     if(vf->ready_state==INITSET)
1761       if(vorbis_synthesis_pcmout(vd,NULL))break;
1762     
1763     /* suck in another packet */
1764     {
1765       int ret=_fetch_and_process_packet(vf,NULL,1,0);
1766       if(ret<0 && ret!=OV_HOLE)return(ret);
1767     }
1768   }  
1769   return 0;
1770 }
1771
1772 /* grab enough data for lapping from vf; this may be in the form of
1773    unreturned, already-decoded pcm, remaining PCM we will need to
1774    decode, or synthetic postextrapolation from last packets. */
1775 static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
1776                        float **lappcm,int lapsize){
1777   int lapcount=0,i;
1778   float **pcm;
1779
1780   /* try first to decode the lapping data */
1781   while(lapcount<lapsize){
1782     int samples=vorbis_synthesis_pcmout(vd,&pcm);
1783     if(samples){
1784       if(samples>lapsize-lapcount)samples=lapsize-lapcount;
1785       for(i=0;i<vi->channels;i++)
1786         memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
1787       lapcount+=samples;
1788       vorbis_synthesis_read(vd,samples);
1789     }else{
1790     /* suck in another packet */
1791       int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
1792       if(ret==OV_EOF)break;
1793     }
1794   }
1795   if(lapcount<lapsize){
1796     /* failed to get lapping data from normal decode; pry it from the
1797        postextrapolation buffering, or the second half of the MDCT
1798        from the last packet */
1799     int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
1800     if(samples==0){
1801       for(i=0;i<vi->channels;i++)
1802         memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
1803       lapcount=lapsize;
1804     }else{
1805       if(samples>lapsize-lapcount)samples=lapsize-lapcount;
1806       for(i=0;i<vi->channels;i++)
1807         memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
1808       lapcount+=samples;
1809     }
1810   }
1811 }
1812
1813 /* this sets up crosslapping of a sample by using trailing data from
1814    sample 1 and lapping it into the windowing buffer of sample 2 */
1815 int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
1816   vorbis_info *vi1,*vi2;
1817   float **lappcm;
1818   float **pcm;
1819   float *w1,*w2;
1820   int n1,n2,i,ret,hs1,hs2;
1821
1822   if(vf1==vf2)return(0); /* degenerate case */
1823   if(vf1->ready_state<OPENED)return(OV_EINVAL);
1824   if(vf2->ready_state<OPENED)return(OV_EINVAL);
1825
1826   /* the relevant overlap buffers must be pre-checked and pre-primed
1827      before looking at settings in the event that priming would cross
1828      a bitstream boundary.  So, do it now */
1829
1830   ret=_ov_initset(vf1);
1831   if(ret)return(ret);
1832   ret=_ov_initprime(vf2);
1833   if(ret)return(ret);
1834
1835   vi1=ov_info(vf1,-1);
1836   vi2=ov_info(vf2,-1);
1837   hs1=ov_halfrate_p(vf1);
1838   hs2=ov_halfrate_p(vf2);
1839
1840   lappcm=alloca(sizeof(*lappcm)*vi1->channels);
1841   n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
1842   n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
1843   w1=vorbis_window(&vf1->vd,0);
1844   w2=vorbis_window(&vf2->vd,0);
1845
1846   for(i=0;i<vi1->channels;i++)
1847     lappcm[i]=alloca(sizeof(**lappcm)*n1);
1848
1849   _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
1850
1851   /* have a lapping buffer from vf1; now to splice it into the lapping
1852      buffer of vf2 */
1853   /* consolidate and expose the buffer. */
1854   vorbis_synthesis_lapout(&vf2->vd,&pcm);
1855   _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
1856   _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
1857
1858   /* splice */
1859   _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
1860   
1861   /* done */
1862   return(0);
1863 }
1864
1865 static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
1866                            int (*localseek)(OggVorbis_File *,ogg_int64_t)){
1867   vorbis_info *vi;
1868   float **lappcm;
1869   float **pcm;
1870   float *w1,*w2;
1871   int n1,n2,ch1,ch2,hs;
1872   int i,ret;
1873
1874   if(vf->ready_state<OPENED)return(OV_EINVAL);
1875   ret=_ov_initset(vf);
1876   if(ret)return(ret);
1877   vi=ov_info(vf,-1);
1878   hs=ov_halfrate_p(vf);
1879   
1880   ch1=vi->channels;
1881   n1=vorbis_info_blocksize(vi,0)>>(1+hs);
1882   w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
1883                                    persistent; even if the decode state
1884                                    from this link gets dumped, this
1885                                    window array continues to exist */
1886
1887   lappcm=alloca(sizeof(*lappcm)*ch1);
1888   for(i=0;i<ch1;i++)
1889     lappcm[i]=alloca(sizeof(**lappcm)*n1);
1890   _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
1891
1892   /* have lapping data; seek and prime the buffer */
1893   ret=localseek(vf,pos);
1894   if(ret)return ret;
1895   ret=_ov_initprime(vf);
1896   if(ret)return(ret);
1897
1898  /* Guard against cross-link changes; they're perfectly legal */
1899   vi=ov_info(vf,-1);
1900   ch2=vi->channels;
1901   n2=vorbis_info_blocksize(vi,0)>>(1+hs);
1902   w2=vorbis_window(&vf->vd,0);
1903
1904   /* consolidate and expose the buffer. */
1905   vorbis_synthesis_lapout(&vf->vd,&pcm);
1906
1907   /* splice */
1908   _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
1909
1910   /* done */
1911   return(0);
1912 }
1913
1914 int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
1915   return _ov_64_seek_lap(vf,pos,ov_raw_seek);
1916 }
1917
1918 int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
1919   return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
1920 }
1921
1922 int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
1923   return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
1924 }
1925
1926 static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
1927                            int (*localseek)(OggVorbis_File *,double)){
1928   vorbis_info *vi;
1929   float **lappcm;
1930   float **pcm;
1931   float *w1,*w2;
1932   int n1,n2,ch1,ch2,hs;
1933   int i,ret;
1934
1935   if(vf->ready_state<OPENED)return(OV_EINVAL);
1936   ret=_ov_initset(vf);
1937   if(ret)return(ret);
1938   vi=ov_info(vf,-1);
1939   hs=ov_halfrate_p(vf);
1940
1941   ch1=vi->channels;
1942   n1=vorbis_info_blocksize(vi,0)>>(1+hs);
1943   w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
1944                                    persistent; even if the decode state
1945                                    from this link gets dumped, this
1946                                    window array continues to exist */
1947
1948   lappcm=alloca(sizeof(*lappcm)*ch1);
1949   for(i=0;i<ch1;i++)
1950     lappcm[i]=alloca(sizeof(**lappcm)*n1);
1951   _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
1952
1953   /* have lapping data; seek and prime the buffer */
1954   ret=localseek(vf,pos);
1955   if(ret)return ret;
1956   ret=_ov_initprime(vf);
1957   if(ret)return(ret);
1958
1959  /* Guard against cross-link changes; they're perfectly legal */
1960   vi=ov_info(vf,-1);
1961   ch2=vi->channels;
1962   n2=vorbis_info_blocksize(vi,0)>>(1+hs);
1963   w2=vorbis_window(&vf->vd,0);
1964
1965   /* consolidate and expose the buffer. */
1966   vorbis_synthesis_lapout(&vf->vd,&pcm);
1967
1968   /* splice */
1969   _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
1970
1971   /* done */
1972   return(0);
1973 }
1974
1975 int ov_time_seek_lap(OggVorbis_File *vf,double pos){
1976   return _ov_d_seek_lap(vf,pos,ov_time_seek);
1977 }
1978
1979 int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
1980   return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
1981 }