Although bug 552 was complaining about behavior that was illegal
[platform/upstream/libvorbis.git] / 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$
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   /* If seek_func is implemented, tell_func must also be implemented */
419   if(vf->end==-1) return(OV_EINVAL);
420
421   /* We get the offset for the last page of the physical bitstream.
422      Most OggVorbis files will contain a single logical bitstream */
423   end=_get_prev_page(vf,&og);
424   if(end<0)return(end);
425
426   /* more than one logical bitstream? */
427   if(ogg_page_serialno(&og)!=serialno){
428
429     /* Chained bitstream. Bisect-search each logical bitstream
430        section.  Do so based on serial number only */
431     if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
432
433   }else{
434
435     /* Only one logical bitstream */
436     if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
437
438   }
439
440   /* the initial header memory is referenced by vf after; don't free it */
441   _prefetch_all_headers(vf,dataoffset);
442   return(ov_raw_seek(vf,0));
443 }
444
445 /* clear out the current logical bitstream decoder */ 
446 static void _decode_clear(OggVorbis_File *vf){
447   vorbis_dsp_clear(&vf->vd);
448   vorbis_block_clear(&vf->vb);
449   vf->ready_state=OPENED;
450 }
451
452 /* fetch and process a packet.  Handles the case where we're at a
453    bitstream boundary and dumps the decoding machine.  If the decoding
454    machine is unloaded, it loads it.  It also keeps pcm_offset up to
455    date (seek and read both use this.  seek uses a special hack with
456    readp). 
457
458    return: <0) error, OV_HOLE (lost packet) or OV_EOF
459             0) need more data (only if readp==0)
460             1) got a packet 
461 */
462
463 static int _fetch_and_process_packet(OggVorbis_File *vf,
464                                      ogg_packet *op_in,
465                                      int readp,
466                                      int spanp){
467   ogg_page og;
468
469   /* handle one packet.  Try to fetch it from current stream state */
470   /* extract packets from page */
471   while(1){
472     
473     /* process a packet if we can.  If the machine isn't loaded,
474        neither is a page */
475     if(vf->ready_state==INITSET){
476       while(1) {
477         ogg_packet op;
478         ogg_packet *op_ptr=(op_in?op_in:&op);
479         int result=ogg_stream_packetout(&vf->os,op_ptr);
480         ogg_int64_t granulepos;
481
482         op_in=NULL;
483         if(result==-1)return(OV_HOLE); /* hole in the data. */
484         if(result>0){
485           /* got a packet.  process it */
486           granulepos=op_ptr->granulepos;
487           if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
488                                                     header handling.  The
489                                                     header packets aren't
490                                                     audio, so if/when we
491                                                     submit them,
492                                                     vorbis_synthesis will
493                                                     reject them */
494
495             /* suck in the synthesis data and track bitrate */
496             {
497               int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
498               /* for proper use of libvorbis within libvorbisfile,
499                  oldsamples will always be zero. */
500               if(oldsamples)return(OV_EFAULT);
501               
502               vorbis_synthesis_blockin(&vf->vd,&vf->vb);
503               vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
504               vf->bittrack+=op_ptr->bytes*8;
505             }
506           
507             /* update the pcm offset. */
508             if(granulepos!=-1 && !op_ptr->e_o_s){
509               int link=(vf->seekable?vf->current_link:0);
510               int i,samples;
511             
512               /* this packet has a pcm_offset on it (the last packet
513                  completed on a page carries the offset) After processing
514                  (above), we know the pcm position of the *last* sample
515                  ready to be returned. Find the offset of the *first*
516
517                  As an aside, this trick is inaccurate if we begin
518                  reading anew right at the last page; the end-of-stream
519                  granulepos declares the last frame in the stream, and the
520                  last packet of the last page may be a partial frame.
521                  So, we need a previous granulepos from an in-sequence page
522                  to have a reference point.  Thus the !op_ptr->e_o_s clause
523                  above */
524
525               if(vf->seekable && link>0)
526                 granulepos-=vf->pcmlengths[link*2];
527               if(granulepos<0)granulepos=0; /* actually, this
528                                                shouldn't be possible
529                                                here unless the stream
530                                                is very broken */
531
532               samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
533             
534               granulepos-=samples;
535               for(i=0;i<link;i++)
536                 granulepos+=vf->pcmlengths[i*2+1];
537               vf->pcm_offset=granulepos;
538             }
539             return(1);
540           }
541         }
542         else 
543           break;
544       }
545     }
546
547     if(vf->ready_state>=OPENED){
548       ogg_int64_t ret;
549       if(!readp)return(0);
550       if((ret=_get_next_page(vf,&og,-1))<0){
551         return(OV_EOF); /* eof. 
552                            leave unitialized */
553       }
554
555         /* bitrate tracking; add the header's bytes here, the body bytes
556            are done by packet above */
557       vf->bittrack+=og.header_len*8;
558       
559       /* has our decoding just traversed a bitstream boundary? */
560       if(vf->ready_state==INITSET){
561         if(vf->current_serialno!=ogg_page_serialno(&og)){
562           if(!spanp)
563             return(OV_EOF);
564
565           _decode_clear(vf);
566           
567           if(!vf->seekable){
568             vorbis_info_clear(vf->vi);
569             vorbis_comment_clear(vf->vc);
570           }
571         }
572       }
573     }
574
575     /* Do we need to load a new machine before submitting the page? */
576     /* This is different in the seekable and non-seekable cases.  
577
578        In the seekable case, we already have all the header
579        information loaded and cached; we just initialize the machine
580        with it and continue on our merry way.
581
582        In the non-seekable (streaming) case, we'll only be at a
583        boundary if we just left the previous logical bitstream and
584        we're now nominally at the header of the next bitstream
585     */
586
587     if(vf->ready_state!=INITSET){ 
588       int link;
589
590       if(vf->ready_state<STREAMSET){
591         if(vf->seekable){
592           vf->current_serialno=ogg_page_serialno(&og);
593           
594           /* match the serialno to bitstream section.  We use this rather than
595              offset positions to avoid problems near logical bitstream
596              boundaries */
597           for(link=0;link<vf->links;link++)
598             if(vf->serialnos[link]==vf->current_serialno)break;
599           if(link==vf->links)return(OV_EBADLINK); /* sign of a bogus
600                                                      stream.  error out,
601                                                      leave machine
602                                                      uninitialized */
603           
604           vf->current_link=link;
605           
606           ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
607           vf->ready_state=STREAMSET;
608           
609         }else{
610           /* we're streaming */
611           /* fetch the three header packets, build the info struct */
612           
613           int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
614           if(ret)return(ret);
615           vf->current_link++;
616           link=0;
617         }
618       }
619       
620       {
621         int ret=_make_decode_ready(vf);
622         if(ret<0)return ret;
623       }
624     }
625     ogg_stream_pagein(&vf->os,&og);
626   }
627 }
628
629 /* if, eg, 64 bit stdio is configured by default, this will build with
630    fseek64 */
631 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
632   if(f==NULL)return(-1);
633   return fseek(f,off,whence);
634 }
635
636 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
637                      long ibytes, ov_callbacks callbacks){
638   int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
639   int ret;
640
641   memset(vf,0,sizeof(*vf));
642   vf->datasource=f;
643   vf->callbacks = callbacks;
644
645   /* init the framing state */
646   ogg_sync_init(&vf->oy);
647
648   /* perhaps some data was previously read into a buffer for testing
649      against other stream types.  Allow initialization from this
650      previously read data (as we may be reading from a non-seekable
651      stream) */
652   if(initial){
653     char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
654     memcpy(buffer,initial,ibytes);
655     ogg_sync_wrote(&vf->oy,ibytes);
656   }
657
658   /* can we seek? Stevens suggests the seek test was portable */
659   if(offsettest!=-1)vf->seekable=1;
660
661   /* No seeking yet; Set up a 'single' (current) logical bitstream
662      entry for partial open */
663   vf->links=1;
664   vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
665   vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
666   ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
667
668   /* Try to fetch the headers, maintaining all the storage */
669   if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
670     vf->datasource=NULL;
671     ov_clear(vf);
672   }else 
673     vf->ready_state=PARTOPEN;
674   return(ret);
675 }
676
677 static int _ov_open2(OggVorbis_File *vf){
678   if(vf->ready_state != PARTOPEN) return OV_EINVAL;
679   vf->ready_state=OPENED;
680   if(vf->seekable){
681     int ret=_open_seekable2(vf);
682     if(ret){
683       vf->datasource=NULL;
684       ov_clear(vf);
685     }
686     return(ret);
687   }else
688     vf->ready_state=STREAMSET;
689
690   return 0;
691 }
692
693
694 /* clear out the OggVorbis_File struct */
695 int ov_clear(OggVorbis_File *vf){
696   if(vf){
697     vorbis_block_clear(&vf->vb);
698     vorbis_dsp_clear(&vf->vd);
699     ogg_stream_clear(&vf->os);
700     
701     if(vf->vi && vf->links){
702       int i;
703       for(i=0;i<vf->links;i++){
704         vorbis_info_clear(vf->vi+i);
705         vorbis_comment_clear(vf->vc+i);
706       }
707       _ogg_free(vf->vi);
708       _ogg_free(vf->vc);
709     }
710     if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
711     if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
712     if(vf->serialnos)_ogg_free(vf->serialnos);
713     if(vf->offsets)_ogg_free(vf->offsets);
714     ogg_sync_clear(&vf->oy);
715     if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
716     memset(vf,0,sizeof(*vf));
717   }
718 #ifdef DEBUG_LEAKS
719   _VDBG_dump();
720 #endif
721   return(0);
722 }
723
724 /* inspects the OggVorbis file and finds/documents all the logical
725    bitstreams contained in it.  Tries to be tolerant of logical
726    bitstream sections that are truncated/woogie. 
727
728    return: -1) error
729             0) OK
730 */
731
732 int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
733     ov_callbacks callbacks){
734   int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
735   if(ret)return ret;
736   return _ov_open2(vf);
737 }
738
739 int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
740   ov_callbacks callbacks = {
741     (size_t (*)(void *, size_t, size_t, void *))  fread,
742     (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
743     (int (*)(void *))                             fclose,
744     (long (*)(void *))                            ftell
745   };
746
747   return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
748 }
749  
750 /* cheap hack for game usage where downsampling is desirable; there's
751    no need for SRC as we can just do it cheaply in libvorbis. */
752  
753 int ov_halfrate(OggVorbis_File *vf,int flag){
754   int i;
755   if(vf->vi==NULL)return OV_EINVAL;
756   if(!vf->seekable)return OV_EINVAL;
757   if(vf->ready_state>=STREAMSET)
758     _decode_clear(vf); /* clear out stream state; later on libvorbis
759                           will be able to swap this on the fly, but
760                           for now dumping the decode machine is needed
761                           to reinit the MDCT lookups.  1.1 libvorbis
762                           is planned to be able to switch on the fly */
763   
764   for(i=0;i<vf->links;i++){
765     if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
766       ov_halfrate(vf,0);
767       return OV_EINVAL;
768     }
769   }
770   return 0;
771 }
772
773 int ov_halfrate_p(OggVorbis_File *vf){
774   if(vf->vi==NULL)return OV_EINVAL;
775   return vorbis_synthesis_halfrate_p(vf->vi);
776 }
777
778 /* Only partially open the vorbis file; test for Vorbisness, and load
779    the headers for the first chain.  Do not seek (although test for
780    seekability).  Use ov_test_open to finish opening the file, else
781    ov_clear to close/free it. Same return codes as open. */
782
783 int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
784     ov_callbacks callbacks)
785 {
786   return _ov_open1(f,vf,initial,ibytes,callbacks);
787 }
788
789 int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
790   ov_callbacks callbacks = {
791     (size_t (*)(void *, size_t, size_t, void *))  fread,
792     (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
793     (int (*)(void *))                             fclose,
794     (long (*)(void *))                            ftell
795   };
796
797   return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
798 }
799   
800 int ov_test_open(OggVorbis_File *vf){
801   if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
802   return _ov_open2(vf);
803 }
804
805 /* How many logical bitstreams in this physical bitstream? */
806 long ov_streams(OggVorbis_File *vf){
807   return vf->links;
808 }
809
810 /* Is the FILE * associated with vf seekable? */
811 long ov_seekable(OggVorbis_File *vf){
812   return vf->seekable;
813 }
814
815 /* returns the bitrate for a given logical bitstream or the entire
816    physical bitstream.  If the file is open for random access, it will
817    find the *actual* average bitrate.  If the file is streaming, it
818    returns the nominal bitrate (if set) else the average of the
819    upper/lower bounds (if set) else -1 (unset).
820
821    If you want the actual bitrate field settings, get them from the
822    vorbis_info structs */
823
824 long ov_bitrate(OggVorbis_File *vf,int i){
825   if(vf->ready_state<OPENED)return(OV_EINVAL);
826   if(i>=vf->links)return(OV_EINVAL);
827   if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
828   if(i<0){
829     ogg_int64_t bits=0;
830     int i;
831     float br;
832     for(i=0;i<vf->links;i++)
833       bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
834     /* This once read: return(rint(bits/ov_time_total(vf,-1)));
835      * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
836      * so this is slightly transformed to make it work.
837      */
838     br = bits/ov_time_total(vf,-1);
839     return(rint(br));
840   }else{
841     if(vf->seekable){
842       /* return the actual bitrate */
843       return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
844     }else{
845       /* return nominal if set */
846       if(vf->vi[i].bitrate_nominal>0){
847         return vf->vi[i].bitrate_nominal;
848       }else{
849         if(vf->vi[i].bitrate_upper>0){
850           if(vf->vi[i].bitrate_lower>0){
851             return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
852           }else{
853             return vf->vi[i].bitrate_upper;
854           }
855         }
856         return(OV_FALSE);
857       }
858     }
859   }
860 }
861
862 /* returns the actual bitrate since last call.  returns -1 if no
863    additional data to offer since last call (or at beginning of stream),
864    EINVAL if stream is only partially open 
865 */
866 long ov_bitrate_instant(OggVorbis_File *vf){
867   int link=(vf->seekable?vf->current_link:0);
868   long ret;
869   if(vf->ready_state<OPENED)return(OV_EINVAL);
870   if(vf->samptrack==0)return(OV_FALSE);
871   ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
872   vf->bittrack=0.f;
873   vf->samptrack=0.f;
874   return(ret);
875 }
876
877 /* Guess */
878 long ov_serialnumber(OggVorbis_File *vf,int i){
879   if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
880   if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
881   if(i<0){
882     return(vf->current_serialno);
883   }else{
884     return(vf->serialnos[i]);
885   }
886 }
887
888 /* returns: total raw (compressed) length of content if i==-1
889             raw (compressed) length of that logical bitstream for i==0 to n
890             OV_EINVAL if the stream is not seekable (we can't know the length)
891             or if stream is only partially open
892 */
893 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
894   if(vf->ready_state<OPENED)return(OV_EINVAL);
895   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
896   if(i<0){
897     ogg_int64_t acc=0;
898     int i;
899     for(i=0;i<vf->links;i++)
900       acc+=ov_raw_total(vf,i);
901     return(acc);
902   }else{
903     return(vf->offsets[i+1]-vf->offsets[i]);
904   }
905 }
906
907 /* returns: total PCM length (samples) of content if i==-1 PCM length
908             (samples) of that logical bitstream for i==0 to n
909             OV_EINVAL if the stream is not seekable (we can't know the
910             length) or only partially open 
911 */
912 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
913   if(vf->ready_state<OPENED)return(OV_EINVAL);
914   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
915   if(i<0){
916     ogg_int64_t acc=0;
917     int i;
918     for(i=0;i<vf->links;i++)
919       acc+=ov_pcm_total(vf,i);
920     return(acc);
921   }else{
922     return(vf->pcmlengths[i*2+1]);
923   }
924 }
925
926 /* returns: total seconds of content if i==-1
927             seconds in that logical bitstream for i==0 to n
928             OV_EINVAL if the stream is not seekable (we can't know the
929             length) or only partially open 
930 */
931 double ov_time_total(OggVorbis_File *vf,int i){
932   if(vf->ready_state<OPENED)return(OV_EINVAL);
933   if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
934   if(i<0){
935     double acc=0;
936     int i;
937     for(i=0;i<vf->links;i++)
938       acc+=ov_time_total(vf,i);
939     return(acc);
940   }else{
941     return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
942   }
943 }
944
945 /* seek to an offset relative to the *compressed* data. This also
946    scans packets to update the PCM cursor. It will cross a logical
947    bitstream boundary, but only if it can't get any packets out of the
948    tail of the bitstream we seek to (so no surprises).
949
950    returns zero on success, nonzero on failure */
951
952 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
953   ogg_stream_state work_os;
954
955   if(vf->ready_state<OPENED)return(OV_EINVAL);
956   if(!vf->seekable)
957     return(OV_ENOSEEK); /* don't dump machine if we can't seek */
958
959   if(pos<0 || pos>vf->end)return(OV_EINVAL);
960
961   /* don't yet clear out decoding machine (if it's initialized), in
962      the case we're in the same link.  Restart the decode lapping, and
963      let _fetch_and_process_packet deal with a potential bitstream
964      boundary */
965   vf->pcm_offset=-1;
966   ogg_stream_reset_serialno(&vf->os,
967                             vf->current_serialno); /* must set serialno */
968   vorbis_synthesis_restart(&vf->vd);
969     
970   _seek_helper(vf,pos);
971
972   /* we need to make sure the pcm_offset is set, but we don't want to
973      advance the raw cursor past good packets just to get to the first
974      with a granulepos.  That's not equivalent behavior to beginning
975      decoding as immediately after the seek position as possible.
976
977      So, a hack.  We use two stream states; a local scratch state and
978      the shared vf->os stream state.  We use the local state to
979      scan, and the shared state as a buffer for later decode. 
980
981      Unfortuantely, on the last page we still advance to last packet
982      because the granulepos on the last page is not necessarily on a
983      packet boundary, and we need to make sure the granpos is
984      correct. 
985   */
986
987   {
988     ogg_page og;
989     ogg_packet op;
990     int lastblock=0;
991     int accblock=0;
992     int thisblock=0;
993     int eosflag=0; 
994
995     ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
996     ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
997                                    return from not necessarily
998                                    starting from the beginning */
999
1000     while(1){
1001       if(vf->ready_state>=STREAMSET){
1002         /* snarf/scan a packet if we can */
1003         int result=ogg_stream_packetout(&work_os,&op);
1004       
1005         if(result>0){
1006
1007           if(vf->vi[vf->current_link].codec_setup){
1008             thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1009             if(thisblock<0){
1010               ogg_stream_packetout(&vf->os,NULL);
1011               thisblock=0;
1012             }else{
1013               
1014               if(eosflag)
1015                 ogg_stream_packetout(&vf->os,NULL);
1016               else
1017                 if(lastblock)accblock+=(lastblock+thisblock)>>2;
1018             }       
1019
1020             if(op.granulepos!=-1){
1021               int i,link=vf->current_link;
1022               ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1023               if(granulepos<0)granulepos=0;
1024               
1025               for(i=0;i<link;i++)
1026                 granulepos+=vf->pcmlengths[i*2+1];
1027               vf->pcm_offset=granulepos-accblock;
1028               break;
1029             }
1030             lastblock=thisblock;
1031             continue;
1032           }else
1033             ogg_stream_packetout(&vf->os,NULL);
1034         }
1035       }
1036       
1037       if(!lastblock){
1038         if(_get_next_page(vf,&og,-1)<0){
1039           vf->pcm_offset=ov_pcm_total(vf,-1);
1040           break;
1041         }
1042       }else{
1043         /* huh?  Bogus stream with packets but no granulepos */
1044         vf->pcm_offset=-1;
1045         break;
1046       }
1047       
1048       /* has our decoding just traversed a bitstream boundary? */
1049       if(vf->ready_state>=STREAMSET)
1050         if(vf->current_serialno!=ogg_page_serialno(&og)){
1051           _decode_clear(vf); /* clear out stream state */
1052           ogg_stream_clear(&work_os);
1053         }
1054
1055       if(vf->ready_state<STREAMSET){
1056         int link;
1057         
1058         vf->current_serialno=ogg_page_serialno(&og);
1059         for(link=0;link<vf->links;link++)
1060           if(vf->serialnos[link]==vf->current_serialno)break;
1061         if(link==vf->links)goto seek_error; /* sign of a bogus stream.
1062                                                error out, leave
1063                                                machine uninitialized */
1064         vf->current_link=link;
1065         
1066         ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1067         ogg_stream_reset_serialno(&work_os,vf->current_serialno); 
1068         vf->ready_state=STREAMSET;
1069         
1070       }
1071     
1072       ogg_stream_pagein(&vf->os,&og);
1073       ogg_stream_pagein(&work_os,&og);
1074       eosflag=ogg_page_eos(&og);
1075     }
1076   }
1077
1078   ogg_stream_clear(&work_os);
1079   vf->bittrack=0.f;
1080   vf->samptrack=0.f;
1081   return(0);
1082
1083  seek_error:
1084   /* dump the machine so we're in a known state */
1085   vf->pcm_offset=-1;
1086   ogg_stream_clear(&work_os);
1087   _decode_clear(vf);
1088   return OV_EBADLINK;
1089 }
1090
1091 /* Page granularity seek (faster than sample granularity because we
1092    don't do the last bit of decode to find a specific sample).
1093
1094    Seek to the last [granule marked] page preceeding the specified pos
1095    location, such that decoding past the returned point will quickly
1096    arrive at the requested position. */
1097 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1098   int link=-1;
1099   ogg_int64_t result=0;
1100   ogg_int64_t total=ov_pcm_total(vf,-1);
1101
1102   if(vf->ready_state<OPENED)return(OV_EINVAL);
1103   if(!vf->seekable)return(OV_ENOSEEK);
1104
1105   if(pos<0 || pos>total)return(OV_EINVAL);
1106  
1107   /* which bitstream section does this pcm offset occur in? */
1108   for(link=vf->links-1;link>=0;link--){
1109     total-=vf->pcmlengths[link*2+1];
1110     if(pos>=total)break;
1111   }
1112
1113   /* search within the logical bitstream for the page with the highest
1114      pcm_pos preceeding (or equal to) pos.  There is a danger here;
1115      missing pages or incorrect frame number information in the
1116      bitstream could make our task impossible.  Account for that (it
1117      would be an error condition) */
1118
1119   /* new search algorithm by HB (Nicholas Vinen) */
1120   {
1121     ogg_int64_t end=vf->offsets[link+1];
1122     ogg_int64_t begin=vf->offsets[link];
1123     ogg_int64_t begintime = vf->pcmlengths[link*2];
1124     ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1125     ogg_int64_t target=pos-total+begintime;
1126     ogg_int64_t best=begin;
1127     
1128     ogg_page og;
1129     while(begin<end){
1130       ogg_int64_t bisect;
1131       
1132       if(end-begin<CHUNKSIZE){
1133         bisect=begin;
1134       }else{
1135         /* take a (pretty decent) guess. */
1136         bisect=begin + 
1137           (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
1138         if(bisect<=begin)
1139           bisect=begin+1;
1140       }
1141       
1142       _seek_helper(vf,bisect);
1143     
1144       while(begin<end){
1145         result=_get_next_page(vf,&og,end-vf->offset);
1146         if(result==OV_EREAD) goto seek_error;
1147         if(result<0){
1148           if(bisect<=begin+1)
1149             end=begin; /* found it */
1150           else{
1151             if(bisect==0) goto seek_error;
1152             bisect-=CHUNKSIZE;
1153             if(bisect<=begin)bisect=begin+1;
1154             _seek_helper(vf,bisect);
1155           }
1156         }else{
1157           ogg_int64_t granulepos=ogg_page_granulepos(&og);
1158           if(granulepos==-1)continue;
1159           if(granulepos<target){
1160             best=result;  /* raw offset of packet with granulepos */ 
1161             begin=vf->offset; /* raw offset of next page */
1162             begintime=granulepos;
1163             
1164             if(target-begintime>44100)break;
1165             bisect=begin; /* *not* begin + 1 */
1166           }else{
1167             if(bisect<=begin+1)
1168               end=begin;  /* found it */
1169             else{
1170               if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1171                 end=result;
1172                 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1173                 if(bisect<=begin)bisect=begin+1;
1174                 _seek_helper(vf,bisect);
1175               }else{
1176                 end=result;
1177                 endtime=granulepos;
1178                 break;
1179               }
1180             }
1181           }
1182         }
1183       }
1184     }
1185
1186     /* found our page. seek to it, update pcm offset. Easier case than
1187        raw_seek, don't keep packets preceeding granulepos. */
1188     {
1189       ogg_page og;
1190       ogg_packet op;
1191       
1192       /* seek */
1193       _seek_helper(vf,best);
1194       vf->pcm_offset=-1;
1195       
1196       if(_get_next_page(vf,&og,-1)<0)return(OV_EOF); /* shouldn't happen */
1197       
1198       if(link!=vf->current_link){
1199         /* Different link; dump entire decode machine */
1200         _decode_clear(vf);  
1201         
1202         vf->current_link=link;
1203         vf->current_serialno=ogg_page_serialno(&og);
1204         vf->ready_state=STREAMSET;
1205         
1206       }else{
1207         vorbis_synthesis_restart(&vf->vd);
1208       }
1209
1210       ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1211       ogg_stream_pagein(&vf->os,&og);
1212
1213       /* pull out all but last packet; the one with granulepos */
1214       while(1){
1215         result=ogg_stream_packetpeek(&vf->os,&op);
1216         if(result==0){
1217           /* !!! the packet finishing this page originated on a
1218              preceeding page. Keep fetching previous pages until we
1219              get one with a granulepos or without the 'continued' flag
1220              set.  Then just use raw_seek for simplicity. */
1221           
1222           _seek_helper(vf,best);
1223           
1224           while(1){
1225             result=_get_prev_page(vf,&og);
1226             if(result<0) goto seek_error;
1227             if(ogg_page_granulepos(&og)>-1 ||
1228                !ogg_page_continued(&og)){
1229               return ov_raw_seek(vf,result);
1230             }
1231             vf->offset=result;
1232           }
1233         }
1234         if(result<0){
1235           result = OV_EBADPACKET; 
1236           goto seek_error;
1237         }
1238         if(op.granulepos!=-1){
1239           vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1240           if(vf->pcm_offset<0)vf->pcm_offset=0;
1241           vf->pcm_offset+=total;
1242           break;
1243         }else
1244           result=ogg_stream_packetout(&vf->os,NULL);
1245       }
1246     }
1247   }
1248   
1249   /* verify result */
1250   if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1251     result=OV_EFAULT;
1252     goto seek_error;
1253   }
1254   vf->bittrack=0.f;
1255   vf->samptrack=0.f;
1256   return(0);
1257   
1258  seek_error:
1259   /* dump machine so we're in a known state */
1260   vf->pcm_offset=-1;
1261   _decode_clear(vf);
1262   return (int)result;
1263 }
1264
1265 /* seek to a sample offset relative to the decompressed pcm stream 
1266    returns zero on success, nonzero on failure */
1267
1268 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1269   int thisblock,lastblock=0;
1270   int ret=ov_pcm_seek_page(vf,pos);
1271   if(ret<0)return(ret);
1272   if((ret=_make_decode_ready(vf)))return ret;
1273
1274   /* discard leading packets we don't need for the lapping of the
1275      position we want; don't decode them */
1276
1277   while(1){
1278     ogg_packet op;
1279     ogg_page og;
1280
1281     int ret=ogg_stream_packetpeek(&vf->os,&op);
1282     if(ret>0){
1283       thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1284       if(thisblock<0){
1285         ogg_stream_packetout(&vf->os,NULL);
1286         continue; /* non audio packet */
1287       }
1288       if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1289       
1290       if(vf->pcm_offset+((thisblock+
1291                           vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1292       
1293       /* remove the packet from packet queue and track its granulepos */
1294       ogg_stream_packetout(&vf->os,NULL);
1295       vorbis_synthesis_trackonly(&vf->vb,&op);  /* set up a vb with
1296                                                    only tracking, no
1297                                                    pcm_decode */
1298       vorbis_synthesis_blockin(&vf->vd,&vf->vb); 
1299       
1300       /* end of logical stream case is hard, especially with exact
1301          length positioning. */
1302       
1303       if(op.granulepos>-1){
1304         int i;
1305         /* always believe the stream markers */
1306         vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1307         if(vf->pcm_offset<0)vf->pcm_offset=0;
1308         for(i=0;i<vf->current_link;i++)
1309           vf->pcm_offset+=vf->pcmlengths[i*2+1];
1310       }
1311         
1312       lastblock=thisblock;
1313       
1314     }else{
1315       if(ret<0 && ret!=OV_HOLE)break;
1316       
1317       /* suck in a new page */
1318       if(_get_next_page(vf,&og,-1)<0)break;
1319       if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
1320       
1321       if(vf->ready_state<STREAMSET){
1322         int link;
1323         
1324         vf->current_serialno=ogg_page_serialno(&og);
1325         for(link=0;link<vf->links;link++)
1326           if(vf->serialnos[link]==vf->current_serialno)break;
1327         if(link==vf->links)return(OV_EBADLINK);
1328         vf->current_link=link;
1329         
1330         ogg_stream_reset_serialno(&vf->os,vf->current_serialno); 
1331         vf->ready_state=STREAMSET;      
1332         ret=_make_decode_ready(vf);
1333         if(ret)return ret;
1334         lastblock=0;
1335       }
1336
1337       ogg_stream_pagein(&vf->os,&og);
1338     }
1339   }
1340
1341   vf->bittrack=0.f;
1342   vf->samptrack=0.f;
1343   /* discard samples until we reach the desired position. Crossing a
1344      logical bitstream boundary with abandon is OK. */
1345   while(vf->pcm_offset<pos){
1346     ogg_int64_t target=pos-vf->pcm_offset;
1347     long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1348
1349     if(samples>target)samples=target;
1350     vorbis_synthesis_read(&vf->vd,samples);
1351     vf->pcm_offset+=samples;
1352     
1353     if(samples<target)
1354       if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
1355         vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1356   }
1357   return 0;
1358 }
1359
1360 /* seek to a playback time relative to the decompressed pcm stream 
1361    returns zero on success, nonzero on failure */
1362 int ov_time_seek(OggVorbis_File *vf,double seconds){
1363   /* translate time to PCM position and call ov_pcm_seek */
1364
1365   int link=-1;
1366   ogg_int64_t pcm_total=0;
1367   double time_total=0.;
1368
1369   if(vf->ready_state<OPENED)return(OV_EINVAL);
1370   if(!vf->seekable)return(OV_ENOSEEK);
1371   if(seconds<0)return(OV_EINVAL);
1372   
1373   /* which bitstream section does this time offset occur in? */
1374   for(link=0;link<vf->links;link++){
1375     double addsec = ov_time_total(vf,link);
1376     if(seconds<time_total+addsec)break;
1377     time_total+=addsec;
1378     pcm_total+=vf->pcmlengths[link*2+1];
1379   }
1380
1381   if(link==vf->links)return(OV_EINVAL);
1382
1383   /* enough information to convert time offset to pcm offset */
1384   {
1385     ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1386     return(ov_pcm_seek(vf,target));
1387   }
1388 }
1389
1390 /* page-granularity version of ov_time_seek 
1391    returns zero on success, nonzero on failure */
1392 int ov_time_seek_page(OggVorbis_File *vf,double seconds){
1393   /* translate time to PCM position and call ov_pcm_seek */
1394
1395   int link=-1;
1396   ogg_int64_t pcm_total=0;
1397   double time_total=0.;
1398
1399   if(vf->ready_state<OPENED)return(OV_EINVAL);
1400   if(!vf->seekable)return(OV_ENOSEEK);
1401   if(seconds<0)return(OV_EINVAL);
1402   
1403   /* which bitstream section does this time offset occur in? */
1404   for(link=0;link<vf->links;link++){
1405     double addsec = ov_time_total(vf,link);
1406     if(seconds<time_total+addsec)break;
1407     time_total+=addsec;
1408     pcm_total+=vf->pcmlengths[link*2+1];
1409   }
1410
1411   if(link==vf->links)return(OV_EINVAL);
1412
1413   /* enough information to convert time offset to pcm offset */
1414   {
1415     ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
1416     return(ov_pcm_seek_page(vf,target));
1417   }
1418 }
1419
1420 /* tell the current stream offset cursor.  Note that seek followed by
1421    tell will likely not give the set offset due to caching */
1422 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1423   if(vf->ready_state<OPENED)return(OV_EINVAL);
1424   return(vf->offset);
1425 }
1426
1427 /* return PCM offset (sample) of next PCM sample to be read */
1428 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
1429   if(vf->ready_state<OPENED)return(OV_EINVAL);
1430   return(vf->pcm_offset);
1431 }
1432
1433 /* return time offset (seconds) of next PCM sample to be read */
1434 double ov_time_tell(OggVorbis_File *vf){
1435   int link=0;
1436   ogg_int64_t pcm_total=0;
1437   double time_total=0.f;
1438   
1439   if(vf->ready_state<OPENED)return(OV_EINVAL);
1440   if(vf->seekable){
1441     pcm_total=ov_pcm_total(vf,-1);
1442     time_total=ov_time_total(vf,-1);
1443   
1444     /* which bitstream section does this time offset occur in? */
1445     for(link=vf->links-1;link>=0;link--){
1446       pcm_total-=vf->pcmlengths[link*2+1];
1447       time_total-=ov_time_total(vf,link);
1448       if(vf->pcm_offset>=pcm_total)break;
1449     }
1450   }
1451
1452   return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
1453 }
1454
1455 /*  link:   -1) return the vorbis_info struct for the bitstream section
1456                 currently being decoded
1457            0-n) to request information for a specific bitstream section
1458     
1459     In the case of a non-seekable bitstream, any call returns the
1460     current bitstream.  NULL in the case that the machine is not
1461     initialized */
1462
1463 vorbis_info *ov_info(OggVorbis_File *vf,int link){
1464   if(vf->seekable){
1465     if(link<0)
1466       if(vf->ready_state>=STREAMSET)
1467         return vf->vi+vf->current_link;
1468       else
1469       return vf->vi;
1470     else
1471       if(link>=vf->links)
1472         return NULL;
1473       else
1474         return vf->vi+link;
1475   }else{
1476     return vf->vi;
1477   }
1478 }
1479
1480 /* grr, strong typing, grr, no templates/inheritence, grr */
1481 vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
1482   if(vf->seekable){
1483     if(link<0)
1484       if(vf->ready_state>=STREAMSET)
1485         return vf->vc+vf->current_link;
1486       else
1487         return vf->vc;
1488     else
1489       if(link>=vf->links)
1490         return NULL;
1491       else
1492         return vf->vc+link;
1493   }else{
1494     return vf->vc;
1495   }
1496 }
1497
1498 static int host_is_big_endian() {
1499   ogg_int32_t pattern = 0xfeedface; /* deadbeef */
1500   unsigned char *bytewise = (unsigned char *)&pattern;
1501   if (bytewise[0] == 0xfe) return 1;
1502   return 0;
1503 }
1504
1505 /* up to this point, everything could more or less hide the multiple
1506    logical bitstream nature of chaining from the toplevel application
1507    if the toplevel application didn't particularly care.  However, at
1508    the point that we actually read audio back, the multiple-section
1509    nature must surface: Multiple bitstream sections do not necessarily
1510    have to have the same number of channels or sampling rate.
1511
1512    ov_read returns the sequential logical bitstream number currently
1513    being decoded along with the PCM data in order that the toplevel
1514    application can take action on channel/sample rate changes.  This
1515    number will be incremented even for streamed (non-seekable) streams
1516    (for seekable streams, it represents the actual logical bitstream
1517    index within the physical bitstream.  Note that the accessor
1518    functions above are aware of this dichotomy).
1519
1520    input values: buffer) a buffer to hold packed PCM data for return
1521                  length) the byte length requested to be placed into buffer
1522                  bigendianp) should the data be packed LSB first (0) or
1523                              MSB first (1)
1524                  word) word size for output.  currently 1 (byte) or 
1525                        2 (16 bit short)
1526
1527    return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1528                    0) EOF
1529                    n) number of bytes of PCM actually returned.  The
1530                    below works on a packet-by-packet basis, so the
1531                    return length is not related to the 'length' passed
1532                    in, just guaranteed to fit.
1533
1534             *section) set to the logical bitstream number */
1535
1536 long ov_read(OggVorbis_File *vf,char *buffer,int length,
1537                     int bigendianp,int word,int sgned,int *bitstream){
1538   int i,j;
1539   int host_endian = host_is_big_endian();
1540
1541   float **pcm;
1542   long samples;
1543
1544   if(vf->ready_state<OPENED)return(OV_EINVAL);
1545
1546   while(1){
1547     if(vf->ready_state==INITSET){
1548       samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1549       if(samples)break;
1550     }
1551
1552     /* suck in another packet */
1553     {
1554       int ret=_fetch_and_process_packet(vf,NULL,1,1);
1555       if(ret==OV_EOF)
1556         return(0);
1557       if(ret<=0)
1558         return(ret);
1559     }
1560
1561   }
1562
1563   if(samples>0){
1564   
1565     /* yay! proceed to pack data into the byte buffer */
1566     
1567     long channels=ov_info(vf,-1)->channels;
1568     long bytespersample=word * channels;
1569     vorbis_fpu_control fpu;
1570     if(samples>length/bytespersample)samples=length/bytespersample;
1571
1572     if(samples <= 0)
1573       return OV_EINVAL;
1574     
1575     /* a tight loop to pack each size */
1576     {
1577       int val;
1578       if(word==1){
1579         int off=(sgned?0:128);
1580         vorbis_fpu_setround(&fpu);
1581         for(j=0;j<samples;j++)
1582           for(i=0;i<channels;i++){
1583             val=vorbis_ftoi(pcm[i][j]*128.f);
1584             if(val>127)val=127;
1585             else if(val<-128)val=-128;
1586             *buffer++=val+off;
1587           }
1588         vorbis_fpu_restore(fpu);
1589       }else{
1590         int off=(sgned?0:32768);
1591         
1592         if(host_endian==bigendianp){
1593           if(sgned){
1594             
1595             vorbis_fpu_setround(&fpu);
1596             for(i=0;i<channels;i++) { /* It's faster in this order */
1597               float *src=pcm[i];
1598               short *dest=((short *)buffer)+i;
1599               for(j=0;j<samples;j++) {
1600                 val=vorbis_ftoi(src[j]*32768.f);
1601                 if(val>32767)val=32767;
1602                 else if(val<-32768)val=-32768;
1603                 *dest=val;
1604                 dest+=channels;
1605               }
1606             }
1607             vorbis_fpu_restore(fpu);
1608             
1609           }else{
1610             
1611             vorbis_fpu_setround(&fpu);
1612             for(i=0;i<channels;i++) {
1613               float *src=pcm[i];
1614               short *dest=((short *)buffer)+i;
1615               for(j=0;j<samples;j++) {
1616                 val=vorbis_ftoi(src[j]*32768.f);
1617                 if(val>32767)val=32767;
1618                 else if(val<-32768)val=-32768;
1619                 *dest=val+off;
1620                 dest+=channels;
1621               }
1622             }
1623             vorbis_fpu_restore(fpu);
1624             
1625           }
1626         }else if(bigendianp){
1627           
1628           vorbis_fpu_setround(&fpu);
1629           for(j=0;j<samples;j++)
1630             for(i=0;i<channels;i++){
1631               val=vorbis_ftoi(pcm[i][j]*32768.f);
1632               if(val>32767)val=32767;
1633               else if(val<-32768)val=-32768;
1634               val+=off;
1635               *buffer++=(val>>8);
1636               *buffer++=(val&0xff);
1637             }
1638           vorbis_fpu_restore(fpu);
1639           
1640         }else{
1641           int val;
1642           vorbis_fpu_setround(&fpu);
1643           for(j=0;j<samples;j++)
1644             for(i=0;i<channels;i++){
1645               val=vorbis_ftoi(pcm[i][j]*32768.f);
1646               if(val>32767)val=32767;
1647               else if(val<-32768)val=-32768;
1648               val+=off;
1649               *buffer++=(val&0xff);
1650               *buffer++=(val>>8);
1651                 }
1652           vorbis_fpu_restore(fpu);  
1653           
1654         }
1655       }
1656     }
1657     
1658     vorbis_synthesis_read(&vf->vd,samples);
1659     vf->pcm_offset+=samples;
1660     if(bitstream)*bitstream=vf->current_link;
1661     return(samples*bytespersample);
1662   }else{
1663     return(samples);
1664   }
1665 }
1666
1667 /* input values: pcm_channels) a float vector per channel of output
1668                  length) the sample length being read by the app
1669
1670    return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1671                    0) EOF
1672                    n) number of samples of PCM actually returned.  The
1673                    below works on a packet-by-packet basis, so the
1674                    return length is not related to the 'length' passed
1675                    in, just guaranteed to fit.
1676
1677             *section) set to the logical bitstream number */
1678
1679
1680
1681 long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
1682                    int *bitstream){
1683
1684   if(vf->ready_state<OPENED)return(OV_EINVAL);
1685
1686   while(1){
1687     if(vf->ready_state==INITSET){
1688       float **pcm;
1689       long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1690       if(samples){
1691         if(pcm_channels)*pcm_channels=pcm;
1692         if(samples>length)samples=length;
1693         vorbis_synthesis_read(&vf->vd,samples);
1694         vf->pcm_offset+=samples;
1695         if(bitstream)*bitstream=vf->current_link;
1696         return samples;
1697
1698       }
1699     }
1700
1701     /* suck in another packet */
1702     {
1703       int ret=_fetch_and_process_packet(vf,NULL,1,1);
1704       if(ret==OV_EOF)return(0);
1705       if(ret<=0)return(ret);
1706     }
1707
1708   }
1709 }
1710
1711 extern float *vorbis_window(vorbis_dsp_state *v,int W);
1712 extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,
1713                              ogg_int64_t off);
1714
1715 static void _ov_splice(float **pcm,float **lappcm,
1716                        int n1, int n2,
1717                        int ch1, int ch2,
1718                        float *w1, float *w2){
1719   int i,j;
1720   float *w=w1;
1721   int n=n1;
1722
1723   if(n1>n2){
1724     n=n2;
1725     w=w2;
1726   }
1727
1728   /* splice */
1729   for(j=0;j<ch1 && j<ch2;j++){
1730     float *s=lappcm[j];
1731     float *d=pcm[j];
1732
1733     for(i=0;i<n;i++){
1734       float wd=w[i]*w[i];
1735       float ws=1.-wd;
1736       d[i]=d[i]*wd + s[i]*ws;
1737     }
1738   }
1739   /* window from zero */
1740   for(;j<ch2;j++){
1741     float *d=pcm[j];
1742     for(i=0;i<n;i++){
1743       float wd=w[i]*w[i];
1744       d[i]=d[i]*wd;
1745     }
1746   }
1747
1748 }
1749                 
1750 /* make sure vf is INITSET */
1751 static int _ov_initset(OggVorbis_File *vf){
1752   while(1){
1753     if(vf->ready_state==INITSET)break;
1754     /* suck in another packet */
1755     {
1756       int ret=_fetch_and_process_packet(vf,NULL,1,0);
1757       if(ret<0 && ret!=OV_HOLE)return(ret);
1758     }
1759   }
1760   return 0;
1761 }
1762
1763 /* make sure vf is INITSET and that we have a primed buffer; if
1764    we're crosslapping at a stream section boundary, this also makes
1765    sure we're sanity checking against the right stream information */
1766 static int _ov_initprime(OggVorbis_File *vf){
1767   vorbis_dsp_state *vd=&vf->vd;
1768   while(1){
1769     if(vf->ready_state==INITSET)
1770       if(vorbis_synthesis_pcmout(vd,NULL))break;
1771     
1772     /* suck in another packet */
1773     {
1774       int ret=_fetch_and_process_packet(vf,NULL,1,0);
1775       if(ret<0 && ret!=OV_HOLE)return(ret);
1776     }
1777   }  
1778   return 0;
1779 }
1780
1781 /* grab enough data for lapping from vf; this may be in the form of
1782    unreturned, already-decoded pcm, remaining PCM we will need to
1783    decode, or synthetic postextrapolation from last packets. */
1784 static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
1785                        float **lappcm,int lapsize){
1786   int lapcount=0,i;
1787   float **pcm;
1788
1789   /* try first to decode the lapping data */
1790   while(lapcount<lapsize){
1791     int samples=vorbis_synthesis_pcmout(vd,&pcm);
1792     if(samples){
1793       if(samples>lapsize-lapcount)samples=lapsize-lapcount;
1794       for(i=0;i<vi->channels;i++)
1795         memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
1796       lapcount+=samples;
1797       vorbis_synthesis_read(vd,samples);
1798     }else{
1799     /* suck in another packet */
1800       int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
1801       if(ret==OV_EOF)break;
1802     }
1803   }
1804   if(lapcount<lapsize){
1805     /* failed to get lapping data from normal decode; pry it from the
1806        postextrapolation buffering, or the second half of the MDCT
1807        from the last packet */
1808     int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
1809     if(samples==0){
1810       for(i=0;i<vi->channels;i++)
1811         memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
1812       lapcount=lapsize;
1813     }else{
1814       if(samples>lapsize-lapcount)samples=lapsize-lapcount;
1815       for(i=0;i<vi->channels;i++)
1816         memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
1817       lapcount+=samples;
1818     }
1819   }
1820 }
1821
1822 /* this sets up crosslapping of a sample by using trailing data from
1823    sample 1 and lapping it into the windowing buffer of sample 2 */
1824 int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
1825   vorbis_info *vi1,*vi2;
1826   float **lappcm;
1827   float **pcm;
1828   float *w1,*w2;
1829   int n1,n2,i,ret,hs1,hs2;
1830
1831   if(vf1==vf2)return(0); /* degenerate case */
1832   if(vf1->ready_state<OPENED)return(OV_EINVAL);
1833   if(vf2->ready_state<OPENED)return(OV_EINVAL);
1834
1835   /* the relevant overlap buffers must be pre-checked and pre-primed
1836      before looking at settings in the event that priming would cross
1837      a bitstream boundary.  So, do it now */
1838
1839   ret=_ov_initset(vf1);
1840   if(ret)return(ret);
1841   ret=_ov_initprime(vf2);
1842   if(ret)return(ret);
1843
1844   vi1=ov_info(vf1,-1);
1845   vi2=ov_info(vf2,-1);
1846   hs1=ov_halfrate_p(vf1);
1847   hs2=ov_halfrate_p(vf2);
1848
1849   lappcm=alloca(sizeof(*lappcm)*vi1->channels);
1850   n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
1851   n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
1852   w1=vorbis_window(&vf1->vd,0);
1853   w2=vorbis_window(&vf2->vd,0);
1854
1855   for(i=0;i<vi1->channels;i++)
1856     lappcm[i]=alloca(sizeof(**lappcm)*n1);
1857
1858   _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
1859
1860   /* have a lapping buffer from vf1; now to splice it into the lapping
1861      buffer of vf2 */
1862   /* consolidate and expose the buffer. */
1863   vorbis_synthesis_lapout(&vf2->vd,&pcm);
1864   _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
1865   _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
1866
1867   /* splice */
1868   _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
1869   
1870   /* done */
1871   return(0);
1872 }
1873
1874 static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
1875                            int (*localseek)(OggVorbis_File *,ogg_int64_t)){
1876   vorbis_info *vi;
1877   float **lappcm;
1878   float **pcm;
1879   float *w1,*w2;
1880   int n1,n2,ch1,ch2,hs;
1881   int i,ret;
1882
1883   if(vf->ready_state<OPENED)return(OV_EINVAL);
1884   ret=_ov_initset(vf);
1885   if(ret)return(ret);
1886   vi=ov_info(vf,-1);
1887   hs=ov_halfrate_p(vf);
1888   
1889   ch1=vi->channels;
1890   n1=vorbis_info_blocksize(vi,0)>>(1+hs);
1891   w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
1892                                    persistent; even if the decode state
1893                                    from this link gets dumped, this
1894                                    window array continues to exist */
1895
1896   lappcm=alloca(sizeof(*lappcm)*ch1);
1897   for(i=0;i<ch1;i++)
1898     lappcm[i]=alloca(sizeof(**lappcm)*n1);
1899   _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
1900
1901   /* have lapping data; seek and prime the buffer */
1902   ret=localseek(vf,pos);
1903   if(ret)return ret;
1904   ret=_ov_initprime(vf);
1905   if(ret)return(ret);
1906
1907  /* Guard against cross-link changes; they're perfectly legal */
1908   vi=ov_info(vf,-1);
1909   ch2=vi->channels;
1910   n2=vorbis_info_blocksize(vi,0)>>(1+hs);
1911   w2=vorbis_window(&vf->vd,0);
1912
1913   /* consolidate and expose the buffer. */
1914   vorbis_synthesis_lapout(&vf->vd,&pcm);
1915
1916   /* splice */
1917   _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
1918
1919   /* done */
1920   return(0);
1921 }
1922
1923 int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
1924   return _ov_64_seek_lap(vf,pos,ov_raw_seek);
1925 }
1926
1927 int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
1928   return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
1929 }
1930
1931 int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
1932   return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
1933 }
1934
1935 static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
1936                            int (*localseek)(OggVorbis_File *,double)){
1937   vorbis_info *vi;
1938   float **lappcm;
1939   float **pcm;
1940   float *w1,*w2;
1941   int n1,n2,ch1,ch2,hs;
1942   int i,ret;
1943
1944   if(vf->ready_state<OPENED)return(OV_EINVAL);
1945   ret=_ov_initset(vf);
1946   if(ret)return(ret);
1947   vi=ov_info(vf,-1);
1948   hs=ov_halfrate_p(vf);
1949
1950   ch1=vi->channels;
1951   n1=vorbis_info_blocksize(vi,0)>>(1+hs);
1952   w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
1953                                    persistent; even if the decode state
1954                                    from this link gets dumped, this
1955                                    window array continues to exist */
1956
1957   lappcm=alloca(sizeof(*lappcm)*ch1);
1958   for(i=0;i<ch1;i++)
1959     lappcm[i]=alloca(sizeof(**lappcm)*n1);
1960   _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
1961
1962   /* have lapping data; seek and prime the buffer */
1963   ret=localseek(vf,pos);
1964   if(ret)return ret;
1965   ret=_ov_initprime(vf);
1966   if(ret)return(ret);
1967
1968  /* Guard against cross-link changes; they're perfectly legal */
1969   vi=ov_info(vf,-1);
1970   ch2=vi->channels;
1971   n2=vorbis_info_blocksize(vi,0)>>(1+hs);
1972   w2=vorbis_window(&vf->vd,0);
1973
1974   /* consolidate and expose the buffer. */
1975   vorbis_synthesis_lapout(&vf->vd,&pcm);
1976
1977   /* splice */
1978   _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
1979
1980   /* done */
1981   return(0);
1982 }
1983
1984 int ov_time_seek_lap(OggVorbis_File *vf,double pos){
1985   return _ov_d_seek_lap(vf,pos,ov_time_seek);
1986 }
1987
1988 int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
1989   return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
1990 }