vrshoot

diff libs/vorbis/vorbisfile.c @ 0:b2f14e535253

initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 01 Feb 2014 19:58:19 +0200
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/libs/vorbis/vorbisfile.c	Sat Feb 01 19:58:19 2014 +0200
     1.3 @@ -0,0 +1,2337 @@
     1.4 +/********************************************************************
     1.5 + *                                                                  *
     1.6 + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE.   *
     1.7 + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
     1.8 + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
     1.9 + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
    1.10 + *                                                                  *
    1.11 + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009             *
    1.12 + * by the Xiph.Org Foundation http://www.xiph.org/                  *
    1.13 + *                                                                  *
    1.14 + ********************************************************************
    1.15 +
    1.16 + function: stdio-based convenience library for opening/seeking/decoding
    1.17 + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
    1.18 +
    1.19 + ********************************************************************/
    1.20 +
    1.21 +#include <stdlib.h>
    1.22 +#include <stdio.h>
    1.23 +#include <errno.h>
    1.24 +#include <string.h>
    1.25 +#include <math.h>
    1.26 +
    1.27 +#include "vorbis/codec.h"
    1.28 +
    1.29 +/* we don't need or want the static callback symbols here */
    1.30 +#define OV_EXCLUDE_STATIC_CALLBACKS
    1.31 +#include "vorbis/vorbisfile.h"
    1.32 +
    1.33 +#include "os.h"
    1.34 +#include "misc.h"
    1.35 +
    1.36 +/* A 'chained bitstream' is a Vorbis bitstream that contains more than
    1.37 +   one logical bitstream arranged end to end (the only form of Ogg
    1.38 +   multiplexing allowed in a Vorbis bitstream; grouping [parallel
    1.39 +   multiplexing] is not allowed in Vorbis) */
    1.40 +
    1.41 +/* A Vorbis file can be played beginning to end (streamed) without
    1.42 +   worrying ahead of time about chaining (see decoder_example.c).  If
    1.43 +   we have the whole file, however, and want random access
    1.44 +   (seeking/scrubbing) or desire to know the total length/time of a
    1.45 +   file, we need to account for the possibility of chaining. */
    1.46 +
    1.47 +/* We can handle things a number of ways; we can determine the entire
    1.48 +   bitstream structure right off the bat, or find pieces on demand.
    1.49 +   This example determines and caches structure for the entire
    1.50 +   bitstream, but builds a virtual decoder on the fly when moving
    1.51 +   between links in the chain. */
    1.52 +
    1.53 +/* There are also different ways to implement seeking.  Enough
    1.54 +   information exists in an Ogg bitstream to seek to
    1.55 +   sample-granularity positions in the output.  Or, one can seek by
    1.56 +   picking some portion of the stream roughly in the desired area if
    1.57 +   we only want coarse navigation through the stream. */
    1.58 +
    1.59 +/*************************************************************************
    1.60 + * Many, many internal helpers.  The intention is not to be confusing;
    1.61 + * rampant duplication and monolithic function implementation would be
    1.62 + * harder to understand anyway.  The high level functions are last.  Begin
    1.63 + * grokking near the end of the file */
    1.64 +
    1.65 +/* read a little more data from the file/pipe into the ogg_sync framer
    1.66 +*/
    1.67 +#define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */
    1.68 +#define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */
    1.69 +
    1.70 +static long _get_data(OggVorbis_File *vf){
    1.71 +  errno=0;
    1.72 +  if(!(vf->callbacks.read_func))return(-1);
    1.73 +  if(vf->datasource){
    1.74 +    char *buffer=ogg_sync_buffer(&vf->oy,READSIZE);
    1.75 +    long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource);
    1.76 +    if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
    1.77 +    if(bytes==0 && errno)return(-1);
    1.78 +    return(bytes);
    1.79 +  }else
    1.80 +    return(0);
    1.81 +}
    1.82 +
    1.83 +/* save a tiny smidge of verbosity to make the code more readable */
    1.84 +static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
    1.85 +  if(vf->datasource){
    1.86 +    if(!(vf->callbacks.seek_func)||
    1.87 +       (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
    1.88 +      return OV_EREAD;
    1.89 +    vf->offset=offset;
    1.90 +    ogg_sync_reset(&vf->oy);
    1.91 +  }else{
    1.92 +    /* shouldn't happen unless someone writes a broken callback */
    1.93 +    return OV_EFAULT;
    1.94 +  }
    1.95 +  return 0;
    1.96 +}
    1.97 +
    1.98 +/* The read/seek functions track absolute position within the stream */
    1.99 +
   1.100 +/* from the head of the stream, get the next page.  boundary specifies
   1.101 +   if the function is allowed to fetch more data from the stream (and
   1.102 +   how much) or only use internally buffered data.
   1.103 +
   1.104 +   boundary: -1) unbounded search
   1.105 +              0) read no additional data; use cached only
   1.106 +              n) search for a new page beginning for n bytes
   1.107 +
   1.108 +   return:   <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
   1.109 +              n) found a page at absolute offset n */
   1.110 +
   1.111 +static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
   1.112 +                                  ogg_int64_t boundary){
   1.113 +  if(boundary>0)boundary+=vf->offset;
   1.114 +  while(1){
   1.115 +    long more;
   1.116 +
   1.117 +    if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
   1.118 +    more=ogg_sync_pageseek(&vf->oy,og);
   1.119 +
   1.120 +    if(more<0){
   1.121 +      /* skipped n bytes */
   1.122 +      vf->offset-=more;
   1.123 +    }else{
   1.124 +      if(more==0){
   1.125 +        /* send more paramedics */
   1.126 +        if(!boundary)return(OV_FALSE);
   1.127 +        {
   1.128 +          long ret=_get_data(vf);
   1.129 +          if(ret==0)return(OV_EOF);
   1.130 +          if(ret<0)return(OV_EREAD);
   1.131 +        }
   1.132 +      }else{
   1.133 +        /* got a page.  Return the offset at the page beginning,
   1.134 +           advance the internal offset past the page end */
   1.135 +        ogg_int64_t ret=vf->offset;
   1.136 +        vf->offset+=more;
   1.137 +        return(ret);
   1.138 +
   1.139 +      }
   1.140 +    }
   1.141 +  }
   1.142 +}
   1.143 +
   1.144 +/* find the latest page beginning before the current stream cursor
   1.145 +   position. Much dirtier than the above as Ogg doesn't have any
   1.146 +   backward search linkage.  no 'readp' as it will certainly have to
   1.147 +   read. */
   1.148 +/* returns offset or OV_EREAD, OV_FAULT */
   1.149 +static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
   1.150 +  ogg_int64_t begin=vf->offset;
   1.151 +  ogg_int64_t end=begin;
   1.152 +  ogg_int64_t ret;
   1.153 +  ogg_int64_t offset=-1;
   1.154 +
   1.155 +  while(offset==-1){
   1.156 +    begin-=CHUNKSIZE;
   1.157 +    if(begin<0)
   1.158 +      begin=0;
   1.159 +
   1.160 +    ret=_seek_helper(vf,begin);
   1.161 +    if(ret)return(ret);
   1.162 +
   1.163 +    while(vf->offset<end){
   1.164 +      memset(og,0,sizeof(*og));
   1.165 +      ret=_get_next_page(vf,og,end-vf->offset);
   1.166 +      if(ret==OV_EREAD)return(OV_EREAD);
   1.167 +      if(ret<0){
   1.168 +        break;
   1.169 +      }else{
   1.170 +        offset=ret;
   1.171 +      }
   1.172 +    }
   1.173 +  }
   1.174 +
   1.175 +  /* In a fully compliant, non-multiplexed stream, we'll still be
   1.176 +     holding the last page.  In multiplexed (or noncompliant streams),
   1.177 +     we will probably have to re-read the last page we saw */
   1.178 +  if(og->header_len==0){
   1.179 +    ret=_seek_helper(vf,offset);
   1.180 +    if(ret)return(ret);
   1.181 +
   1.182 +    ret=_get_next_page(vf,og,CHUNKSIZE);
   1.183 +    if(ret<0)
   1.184 +      /* this shouldn't be possible */
   1.185 +      return(OV_EFAULT);
   1.186 +  }
   1.187 +
   1.188 +  return(offset);
   1.189 +}
   1.190 +
   1.191 +static void _add_serialno(ogg_page *og,long **serialno_list, int *n){
   1.192 +  long s = ogg_page_serialno(og);
   1.193 +  (*n)++;
   1.194 +
   1.195 +  if(*serialno_list){
   1.196 +    *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
   1.197 +  }else{
   1.198 +    *serialno_list = _ogg_malloc(sizeof(**serialno_list));
   1.199 +  }
   1.200 +
   1.201 +  (*serialno_list)[(*n)-1] = s;
   1.202 +}
   1.203 +
   1.204 +/* returns nonzero if found */
   1.205 +static int _lookup_serialno(long s, long *serialno_list, int n){
   1.206 +  if(serialno_list){
   1.207 +    while(n--){
   1.208 +      if(*serialno_list == s) return 1;
   1.209 +      serialno_list++;
   1.210 +    }
   1.211 +  }
   1.212 +  return 0;
   1.213 +}
   1.214 +
   1.215 +static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){
   1.216 +  long s = ogg_page_serialno(og);
   1.217 +  return _lookup_serialno(s,serialno_list,n);
   1.218 +}
   1.219 +
   1.220 +/* performs the same search as _get_prev_page, but prefers pages of
   1.221 +   the specified serial number. If a page of the specified serialno is
   1.222 +   spotted during the seek-back-and-read-forward, it will return the
   1.223 +   info of last page of the matching serial number instead of the very
   1.224 +   last page.  If no page of the specified serialno is seen, it will
   1.225 +   return the info of last page and alter *serialno.  */
   1.226 +static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf,
   1.227 +                                         long *serial_list, int serial_n,
   1.228 +                                         int *serialno, ogg_int64_t *granpos){
   1.229 +  ogg_page og;
   1.230 +  ogg_int64_t begin=vf->offset;
   1.231 +  ogg_int64_t end=begin;
   1.232 +  ogg_int64_t ret;
   1.233 +
   1.234 +  ogg_int64_t prefoffset=-1;
   1.235 +  ogg_int64_t offset=-1;
   1.236 +  ogg_int64_t ret_serialno=-1;
   1.237 +  ogg_int64_t ret_gran=-1;
   1.238 +
   1.239 +  while(offset==-1){
   1.240 +    begin-=CHUNKSIZE;
   1.241 +    if(begin<0)
   1.242 +      begin=0;
   1.243 +
   1.244 +    ret=_seek_helper(vf,begin);
   1.245 +    if(ret)return(ret);
   1.246 +
   1.247 +    while(vf->offset<end){
   1.248 +      ret=_get_next_page(vf,&og,end-vf->offset);
   1.249 +      if(ret==OV_EREAD)return(OV_EREAD);
   1.250 +      if(ret<0){
   1.251 +        break;
   1.252 +      }else{
   1.253 +        ret_serialno=ogg_page_serialno(&og);
   1.254 +        ret_gran=ogg_page_granulepos(&og);
   1.255 +        offset=ret;
   1.256 +
   1.257 +        if(ret_serialno == *serialno){
   1.258 +          prefoffset=ret;
   1.259 +          *granpos=ret_gran;
   1.260 +        }
   1.261 +
   1.262 +        if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){
   1.263 +          /* we fell off the end of the link, which means we seeked
   1.264 +             back too far and shouldn't have been looking in that link
   1.265 +             to begin with.  If we found the preferred serial number,
   1.266 +             forget that we saw it. */
   1.267 +          prefoffset=-1;
   1.268 +        }
   1.269 +      }
   1.270 +    }
   1.271 +  }
   1.272 +
   1.273 +  /* we're not interested in the page... just the serialno and granpos. */
   1.274 +  if(prefoffset>=0)return(prefoffset);
   1.275 +
   1.276 +  *serialno = ret_serialno;
   1.277 +  *granpos = ret_gran;
   1.278 +  return(offset);
   1.279 +
   1.280 +}
   1.281 +
   1.282 +/* uses the local ogg_stream storage in vf; this is important for
   1.283 +   non-streaming input sources */
   1.284 +static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
   1.285 +                          long **serialno_list, int *serialno_n,
   1.286 +                          ogg_page *og_ptr){
   1.287 +  ogg_page og;
   1.288 +  ogg_packet op;
   1.289 +  int i,ret;
   1.290 +  int allbos=0;
   1.291 +
   1.292 +  if(!og_ptr){
   1.293 +    ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
   1.294 +    if(llret==OV_EREAD)return(OV_EREAD);
   1.295 +    if(llret<0)return(OV_ENOTVORBIS);
   1.296 +    og_ptr=&og;
   1.297 +  }
   1.298 +
   1.299 +  vorbis_info_init(vi);
   1.300 +  vorbis_comment_init(vc);
   1.301 +  vf->ready_state=OPENED;
   1.302 +
   1.303 +  /* extract the serialnos of all BOS pages + the first set of vorbis
   1.304 +     headers we see in the link */
   1.305 +
   1.306 +  while(ogg_page_bos(og_ptr)){
   1.307 +    if(serialno_list){
   1.308 +      if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
   1.309 +        /* a dupe serialnumber in an initial header packet set == invalid stream */
   1.310 +        if(*serialno_list)_ogg_free(*serialno_list);
   1.311 +        *serialno_list=0;
   1.312 +        *serialno_n=0;
   1.313 +        ret=OV_EBADHEADER;
   1.314 +        goto bail_header;
   1.315 +      }
   1.316 +
   1.317 +      _add_serialno(og_ptr,serialno_list,serialno_n);
   1.318 +    }
   1.319 +
   1.320 +    if(vf->ready_state<STREAMSET){
   1.321 +      /* we don't have a vorbis stream in this link yet, so begin
   1.322 +         prospective stream setup. We need a stream to get packets */
   1.323 +      ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
   1.324 +      ogg_stream_pagein(&vf->os,og_ptr);
   1.325 +
   1.326 +      if(ogg_stream_packetout(&vf->os,&op) > 0 &&
   1.327 +         vorbis_synthesis_idheader(&op)){
   1.328 +        /* vorbis header; continue setup */
   1.329 +        vf->ready_state=STREAMSET;
   1.330 +        if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
   1.331 +          ret=OV_EBADHEADER;
   1.332 +          goto bail_header;
   1.333 +        }
   1.334 +      }
   1.335 +    }
   1.336 +
   1.337 +    /* get next page */
   1.338 +    {
   1.339 +      ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
   1.340 +      if(llret==OV_EREAD){
   1.341 +        ret=OV_EREAD;
   1.342 +        goto bail_header;
   1.343 +      }
   1.344 +      if(llret<0){
   1.345 +        ret=OV_ENOTVORBIS;
   1.346 +        goto bail_header;
   1.347 +      }
   1.348 +
   1.349 +      /* if this page also belongs to our vorbis stream, submit it and break */
   1.350 +      if(vf->ready_state==STREAMSET &&
   1.351 +         vf->os.serialno == ogg_page_serialno(og_ptr)){
   1.352 +        ogg_stream_pagein(&vf->os,og_ptr);
   1.353 +        break;
   1.354 +      }
   1.355 +    }
   1.356 +  }
   1.357 +
   1.358 +  if(vf->ready_state!=STREAMSET){
   1.359 +    ret = OV_ENOTVORBIS;
   1.360 +    goto bail_header;
   1.361 +  }
   1.362 +
   1.363 +  while(1){
   1.364 +
   1.365 +    i=0;
   1.366 +    while(i<2){ /* get a page loop */
   1.367 +
   1.368 +      while(i<2){ /* get a packet loop */
   1.369 +
   1.370 +        int result=ogg_stream_packetout(&vf->os,&op);
   1.371 +        if(result==0)break;
   1.372 +        if(result==-1){
   1.373 +          ret=OV_EBADHEADER;
   1.374 +          goto bail_header;
   1.375 +        }
   1.376 +
   1.377 +        if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
   1.378 +          goto bail_header;
   1.379 +
   1.380 +        i++;
   1.381 +      }
   1.382 +
   1.383 +      while(i<2){
   1.384 +        if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
   1.385 +          ret=OV_EBADHEADER;
   1.386 +          goto bail_header;
   1.387 +        }
   1.388 +
   1.389 +        /* if this page belongs to the correct stream, go parse it */
   1.390 +        if(vf->os.serialno == ogg_page_serialno(og_ptr)){
   1.391 +          ogg_stream_pagein(&vf->os,og_ptr);
   1.392 +          break;
   1.393 +        }
   1.394 +
   1.395 +        /* if we never see the final vorbis headers before the link
   1.396 +           ends, abort */
   1.397 +        if(ogg_page_bos(og_ptr)){
   1.398 +          if(allbos){
   1.399 +            ret = OV_EBADHEADER;
   1.400 +            goto bail_header;
   1.401 +          }else
   1.402 +            allbos=1;
   1.403 +        }
   1.404 +
   1.405 +        /* otherwise, keep looking */
   1.406 +      }
   1.407 +    }
   1.408 +
   1.409 +    return 0;
   1.410 +  }
   1.411 +
   1.412 + bail_header:
   1.413 +  vorbis_info_clear(vi);
   1.414 +  vorbis_comment_clear(vc);
   1.415 +  vf->ready_state=OPENED;
   1.416 +
   1.417 +  return ret;
   1.418 +}
   1.419 +
   1.420 +/* Starting from current cursor position, get initial PCM offset of
   1.421 +   next page.  Consumes the page in the process without decoding
   1.422 +   audio, however this is only called during stream parsing upon
   1.423 +   seekable open. */
   1.424 +static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
   1.425 +  ogg_page    og;
   1.426 +  ogg_int64_t accumulated=0;
   1.427 +  long        lastblock=-1;
   1.428 +  int         result;
   1.429 +  int         serialno = vf->os.serialno;
   1.430 +
   1.431 +  while(1){
   1.432 +    ogg_packet op;
   1.433 +    if(_get_next_page(vf,&og,-1)<0)
   1.434 +      break; /* should not be possible unless the file is truncated/mangled */
   1.435 +
   1.436 +    if(ogg_page_bos(&og)) break;
   1.437 +    if(ogg_page_serialno(&og)!=serialno) continue;
   1.438 +
   1.439 +    /* count blocksizes of all frames in the page */
   1.440 +    ogg_stream_pagein(&vf->os,&og);
   1.441 +    while((result=ogg_stream_packetout(&vf->os,&op))){
   1.442 +      if(result>0){ /* ignore holes */
   1.443 +        long thisblock=vorbis_packet_blocksize(vi,&op);
   1.444 +        if(lastblock!=-1)
   1.445 +          accumulated+=(lastblock+thisblock)>>2;
   1.446 +        lastblock=thisblock;
   1.447 +      }
   1.448 +    }
   1.449 +
   1.450 +    if(ogg_page_granulepos(&og)!=-1){
   1.451 +      /* pcm offset of last packet on the first audio page */
   1.452 +      accumulated= ogg_page_granulepos(&og)-accumulated;
   1.453 +      break;
   1.454 +    }
   1.455 +  }
   1.456 +
   1.457 +  /* less than zero?  Either a corrupt file or a stream with samples
   1.458 +     trimmed off the beginning, a normal occurrence; in both cases set
   1.459 +     the offset to zero */
   1.460 +  if(accumulated<0)accumulated=0;
   1.461 +
   1.462 +  return accumulated;
   1.463 +}
   1.464 +
   1.465 +/* finds each bitstream link one at a time using a bisection search
   1.466 +   (has to begin by knowing the offset of the lb's initial page).
   1.467 +   Recurses for each link so it can alloc the link storage after
   1.468 +   finding them all, then unroll and fill the cache at the same time */
   1.469 +static int _bisect_forward_serialno(OggVorbis_File *vf,
   1.470 +                                    ogg_int64_t begin,
   1.471 +                                    ogg_int64_t searched,
   1.472 +                                    ogg_int64_t end,
   1.473 +                                    ogg_int64_t endgran,
   1.474 +                                    int endserial,
   1.475 +                                    long *currentno_list,
   1.476 +                                    int  currentnos,
   1.477 +                                    long m){
   1.478 +  ogg_int64_t pcmoffset;
   1.479 +  ogg_int64_t dataoffset=searched;
   1.480 +  ogg_int64_t endsearched=end;
   1.481 +  ogg_int64_t next=end;
   1.482 +  ogg_int64_t searchgran=-1;
   1.483 +  ogg_page og;
   1.484 +  ogg_int64_t ret,last;
   1.485 +  int serialno = vf->os.serialno;
   1.486 +
   1.487 +  /* invariants:
   1.488 +     we have the headers and serialnos for the link beginning at 'begin'
   1.489 +     we have the offset and granpos of the last page in the file (potentially
   1.490 +       not a page we care about)
   1.491 +  */
   1.492 +
   1.493 +  /* Is the last page in our list of current serialnumbers? */
   1.494 +  if(_lookup_serialno(endserial,currentno_list,currentnos)){
   1.495 +
   1.496 +    /* last page is in the starting serialno list, so we've bisected
   1.497 +       down to (or just started with) a single link.  Now we need to
   1.498 +       find the last vorbis page belonging to the first vorbis stream
   1.499 +       for this link. */
   1.500 +
   1.501 +    while(endserial != serialno){
   1.502 +      endserial = serialno;
   1.503 +      vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&endserial,&endgran);
   1.504 +    }
   1.505 +
   1.506 +    vf->links=m+1;
   1.507 +    if(vf->offsets)_ogg_free(vf->offsets);
   1.508 +    if(vf->serialnos)_ogg_free(vf->serialnos);
   1.509 +    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
   1.510 +
   1.511 +    vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
   1.512 +    vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
   1.513 +    vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
   1.514 +    vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
   1.515 +    vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
   1.516 +    vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
   1.517 +
   1.518 +    vf->offsets[m+1]=end;
   1.519 +    vf->offsets[m]=begin;
   1.520 +    vf->pcmlengths[m*2+1]=(endgran<0?0:endgran);
   1.521 +
   1.522 +  }else{
   1.523 +
   1.524 +    long *next_serialno_list=NULL;
   1.525 +    int next_serialnos=0;
   1.526 +    vorbis_info vi;
   1.527 +    vorbis_comment vc;
   1.528 +
   1.529 +    /* the below guards against garbage seperating the last and
   1.530 +       first pages of two links. */
   1.531 +    while(searched<endsearched){
   1.532 +      ogg_int64_t bisect;
   1.533 +
   1.534 +      if(endsearched-searched<CHUNKSIZE){
   1.535 +        bisect=searched;
   1.536 +      }else{
   1.537 +        bisect=(searched+endsearched)/2;
   1.538 +      }
   1.539 +
   1.540 +      if(bisect != vf->offset){
   1.541 +        ret=_seek_helper(vf,bisect);
   1.542 +        if(ret)return(ret);
   1.543 +      }
   1.544 +
   1.545 +      last=_get_next_page(vf,&og,-1);
   1.546 +      if(last==OV_EREAD)return(OV_EREAD);
   1.547 +      if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
   1.548 +        endsearched=bisect;
   1.549 +        if(last>=0)next=last;
   1.550 +      }else{
   1.551 +        searched=vf->offset;
   1.552 +      }
   1.553 +    }
   1.554 +
   1.555 +    /* Bisection point found */
   1.556 +
   1.557 +    /* for the time being, fetch end PCM offset the simple way */
   1.558 +    {
   1.559 +      int testserial = serialno+1;
   1.560 +      vf->offset = next;
   1.561 +      while(testserial != serialno){
   1.562 +        testserial = serialno;
   1.563 +        vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&testserial,&searchgran);
   1.564 +      }
   1.565 +    }
   1.566 +
   1.567 +    if(vf->offset!=next){
   1.568 +      ret=_seek_helper(vf,next);
   1.569 +      if(ret)return(ret);
   1.570 +    }
   1.571 +
   1.572 +    ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
   1.573 +    if(ret)return(ret);
   1.574 +    serialno = vf->os.serialno;
   1.575 +    dataoffset = vf->offset;
   1.576 +
   1.577 +    /* this will consume a page, however the next bistection always
   1.578 +       starts with a raw seek */
   1.579 +    pcmoffset = _initial_pcmoffset(vf,&vi);
   1.580 +
   1.581 +    ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
   1.582 +                                 next_serialno_list,next_serialnos,m+1);
   1.583 +    if(ret)return(ret);
   1.584 +
   1.585 +    if(next_serialno_list)_ogg_free(next_serialno_list);
   1.586 +
   1.587 +    vf->offsets[m+1]=next;
   1.588 +    vf->serialnos[m+1]=serialno;
   1.589 +    vf->dataoffsets[m+1]=dataoffset;
   1.590 +
   1.591 +    vf->vi[m+1]=vi;
   1.592 +    vf->vc[m+1]=vc;
   1.593 +
   1.594 +    vf->pcmlengths[m*2+1]=searchgran;
   1.595 +    vf->pcmlengths[m*2+2]=pcmoffset;
   1.596 +    vf->pcmlengths[m*2+3]-=pcmoffset;
   1.597 +    if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0;
   1.598 +  }
   1.599 +  return(0);
   1.600 +}
   1.601 +
   1.602 +static int _make_decode_ready(OggVorbis_File *vf){
   1.603 +  if(vf->ready_state>STREAMSET)return 0;
   1.604 +  if(vf->ready_state<STREAMSET)return OV_EFAULT;
   1.605 +  if(vf->seekable){
   1.606 +    if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
   1.607 +      return OV_EBADLINK;
   1.608 +  }else{
   1.609 +    if(vorbis_synthesis_init(&vf->vd,vf->vi))
   1.610 +      return OV_EBADLINK;
   1.611 +  }
   1.612 +  vorbis_block_init(&vf->vd,&vf->vb);
   1.613 +  vf->ready_state=INITSET;
   1.614 +  vf->bittrack=0.f;
   1.615 +  vf->samptrack=0.f;
   1.616 +  return 0;
   1.617 +}
   1.618 +
   1.619 +static int _open_seekable2(OggVorbis_File *vf){
   1.620 +  ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1;
   1.621 +  int endserial=vf->os.serialno;
   1.622 +  int serialno=vf->os.serialno;
   1.623 +
   1.624 +  /* we're partially open and have a first link header state in
   1.625 +     storage in vf */
   1.626 +
   1.627 +  /* fetch initial PCM offset */
   1.628 +  ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
   1.629 +
   1.630 +  /* we can seek, so set out learning all about this file */
   1.631 +  if(vf->callbacks.seek_func && vf->callbacks.tell_func){
   1.632 +    (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
   1.633 +    vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
   1.634 +  }else{
   1.635 +    vf->offset=vf->end=-1;
   1.636 +  }
   1.637 +
   1.638 +  /* If seek_func is implemented, tell_func must also be implemented */
   1.639 +  if(vf->end==-1) return(OV_EINVAL);
   1.640 +
   1.641 +  /* Get the offset of the last page of the physical bitstream, or, if
   1.642 +     we're lucky the last vorbis page of this link as most OggVorbis
   1.643 +     files will contain a single logical bitstream */
   1.644 +  end=_get_prev_page_serial(vf,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
   1.645 +  if(end<0)return(end);
   1.646 +
   1.647 +  /* now determine bitstream structure recursively */
   1.648 +  if(_bisect_forward_serialno(vf,0,dataoffset,vf->offset,endgran,endserial,
   1.649 +                              vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
   1.650 +
   1.651 +  vf->offsets[0]=0;
   1.652 +  vf->serialnos[0]=serialno;
   1.653 +  vf->dataoffsets[0]=dataoffset;
   1.654 +  vf->pcmlengths[0]=pcmoffset;
   1.655 +  vf->pcmlengths[1]-=pcmoffset;
   1.656 +  if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0;
   1.657 +
   1.658 +  return(ov_raw_seek(vf,dataoffset));
   1.659 +}
   1.660 +
   1.661 +/* clear out the current logical bitstream decoder */
   1.662 +static void _decode_clear(OggVorbis_File *vf){
   1.663 +  vorbis_dsp_clear(&vf->vd);
   1.664 +  vorbis_block_clear(&vf->vb);
   1.665 +  vf->ready_state=OPENED;
   1.666 +}
   1.667 +
   1.668 +/* fetch and process a packet.  Handles the case where we're at a
   1.669 +   bitstream boundary and dumps the decoding machine.  If the decoding
   1.670 +   machine is unloaded, it loads it.  It also keeps pcm_offset up to
   1.671 +   date (seek and read both use this.  seek uses a special hack with
   1.672 +   readp).
   1.673 +
   1.674 +   return: <0) error, OV_HOLE (lost packet) or OV_EOF
   1.675 +            0) need more data (only if readp==0)
   1.676 +            1) got a packet
   1.677 +*/
   1.678 +
   1.679 +static int _fetch_and_process_packet(OggVorbis_File *vf,
   1.680 +                                     ogg_packet *op_in,
   1.681 +                                     int readp,
   1.682 +                                     int spanp){
   1.683 +  ogg_page og;
   1.684 +
   1.685 +  /* handle one packet.  Try to fetch it from current stream state */
   1.686 +  /* extract packets from page */
   1.687 +  while(1){
   1.688 +
   1.689 +    if(vf->ready_state==STREAMSET){
   1.690 +      int ret=_make_decode_ready(vf);
   1.691 +      if(ret<0)return ret;
   1.692 +    }
   1.693 +
   1.694 +    /* process a packet if we can. */
   1.695 +
   1.696 +    if(vf->ready_state==INITSET){
   1.697 +      int hs=vorbis_synthesis_halfrate_p(vf->vi);
   1.698 +
   1.699 +      while(1) {
   1.700 +              ogg_packet op;
   1.701 +              ogg_packet *op_ptr=(op_in?op_in:&op);
   1.702 +        int result=ogg_stream_packetout(&vf->os,op_ptr);
   1.703 +        ogg_int64_t granulepos;
   1.704 +
   1.705 +        op_in=NULL;
   1.706 +        if(result==-1)return(OV_HOLE); /* hole in the data. */
   1.707 +        if(result>0){
   1.708 +          /* got a packet.  process it */
   1.709 +          granulepos=op_ptr->granulepos;
   1.710 +          if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
   1.711 +                                                    header handling.  The
   1.712 +                                                    header packets aren't
   1.713 +                                                    audio, so if/when we
   1.714 +                                                    submit them,
   1.715 +                                                    vorbis_synthesis will
   1.716 +                                                    reject them */
   1.717 +
   1.718 +            /* suck in the synthesis data and track bitrate */
   1.719 +            {
   1.720 +              int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
   1.721 +              /* for proper use of libvorbis within libvorbisfile,
   1.722 +                 oldsamples will always be zero. */
   1.723 +              if(oldsamples)return(OV_EFAULT);
   1.724 +
   1.725 +              vorbis_synthesis_blockin(&vf->vd,&vf->vb);
   1.726 +              vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
   1.727 +              vf->bittrack+=op_ptr->bytes*8;
   1.728 +            }
   1.729 +
   1.730 +            /* update the pcm offset. */
   1.731 +            if(granulepos!=-1 && !op_ptr->e_o_s){
   1.732 +              int link=(vf->seekable?vf->current_link:0);
   1.733 +              int i,samples;
   1.734 +
   1.735 +              /* this packet has a pcm_offset on it (the last packet
   1.736 +                 completed on a page carries the offset) After processing
   1.737 +                 (above), we know the pcm position of the *last* sample
   1.738 +                 ready to be returned. Find the offset of the *first*
   1.739 +
   1.740 +                 As an aside, this trick is inaccurate if we begin
   1.741 +                 reading anew right at the last page; the end-of-stream
   1.742 +                 granulepos declares the last frame in the stream, and the
   1.743 +                 last packet of the last page may be a partial frame.
   1.744 +                 So, we need a previous granulepos from an in-sequence page
   1.745 +                 to have a reference point.  Thus the !op_ptr->e_o_s clause
   1.746 +                 above */
   1.747 +
   1.748 +              if(vf->seekable && link>0)
   1.749 +                granulepos-=vf->pcmlengths[link*2];
   1.750 +              if(granulepos<0)granulepos=0; /* actually, this
   1.751 +                                               shouldn't be possible
   1.752 +                                               here unless the stream
   1.753 +                                               is very broken */
   1.754 +
   1.755 +              samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
   1.756 +
   1.757 +              granulepos-=samples;
   1.758 +              for(i=0;i<link;i++)
   1.759 +                granulepos+=vf->pcmlengths[i*2+1];
   1.760 +              vf->pcm_offset=granulepos;
   1.761 +            }
   1.762 +            return(1);
   1.763 +          }
   1.764 +        }
   1.765 +        else
   1.766 +          break;
   1.767 +      }
   1.768 +    }
   1.769 +
   1.770 +    if(vf->ready_state>=OPENED){
   1.771 +      ogg_int64_t ret;
   1.772 +
   1.773 +      while(1){
   1.774 +        /* the loop is not strictly necessary, but there's no sense in
   1.775 +           doing the extra checks of the larger loop for the common
   1.776 +           case in a multiplexed bistream where the page is simply
   1.777 +           part of a different logical bitstream; keep reading until
   1.778 +           we get one with the correct serialno */
   1.779 +
   1.780 +        if(!readp)return(0);
   1.781 +        if((ret=_get_next_page(vf,&og,-1))<0){
   1.782 +          return(OV_EOF); /* eof. leave unitialized */
   1.783 +        }
   1.784 +
   1.785 +        /* bitrate tracking; add the header's bytes here, the body bytes
   1.786 +           are done by packet above */
   1.787 +        vf->bittrack+=og.header_len*8;
   1.788 +
   1.789 +        if(vf->ready_state==INITSET){
   1.790 +          if(vf->current_serialno!=ogg_page_serialno(&og)){
   1.791 +
   1.792 +            /* two possibilities:
   1.793 +               1) our decoding just traversed a bitstream boundary
   1.794 +               2) another stream is multiplexed into this logical section */
   1.795 +
   1.796 +            if(ogg_page_bos(&og)){
   1.797 +              /* boundary case */
   1.798 +              if(!spanp)
   1.799 +                return(OV_EOF);
   1.800 +
   1.801 +              _decode_clear(vf);
   1.802 +
   1.803 +              if(!vf->seekable){
   1.804 +                vorbis_info_clear(vf->vi);
   1.805 +                vorbis_comment_clear(vf->vc);
   1.806 +              }
   1.807 +              break;
   1.808 +
   1.809 +            }else
   1.810 +              continue; /* possibility #2 */
   1.811 +          }
   1.812 +        }
   1.813 +
   1.814 +        break;
   1.815 +      }
   1.816 +    }
   1.817 +
   1.818 +    /* Do we need to load a new machine before submitting the page? */
   1.819 +    /* This is different in the seekable and non-seekable cases.
   1.820 +
   1.821 +       In the seekable case, we already have all the header
   1.822 +       information loaded and cached; we just initialize the machine
   1.823 +       with it and continue on our merry way.
   1.824 +
   1.825 +       In the non-seekable (streaming) case, we'll only be at a
   1.826 +       boundary if we just left the previous logical bitstream and
   1.827 +       we're now nominally at the header of the next bitstream
   1.828 +    */
   1.829 +
   1.830 +    if(vf->ready_state!=INITSET){
   1.831 +      int link;
   1.832 +
   1.833 +      if(vf->ready_state<STREAMSET){
   1.834 +        if(vf->seekable){
   1.835 +          long serialno = ogg_page_serialno(&og);
   1.836 +
   1.837 +          /* match the serialno to bitstream section.  We use this rather than
   1.838 +             offset positions to avoid problems near logical bitstream
   1.839 +             boundaries */
   1.840 +
   1.841 +          for(link=0;link<vf->links;link++)
   1.842 +            if(vf->serialnos[link]==serialno)break;
   1.843 +
   1.844 +          if(link==vf->links) continue; /* not the desired Vorbis
   1.845 +                                           bitstream section; keep
   1.846 +                                           trying */
   1.847 +
   1.848 +          vf->current_serialno=serialno;
   1.849 +          vf->current_link=link;
   1.850 +
   1.851 +          ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
   1.852 +          vf->ready_state=STREAMSET;
   1.853 +
   1.854 +        }else{
   1.855 +          /* we're streaming */
   1.856 +          /* fetch the three header packets, build the info struct */
   1.857 +
   1.858 +          int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og);
   1.859 +          if(ret)return(ret);
   1.860 +          vf->current_serialno=vf->os.serialno;
   1.861 +          vf->current_link++;
   1.862 +          link=0;
   1.863 +        }
   1.864 +      }
   1.865 +    }
   1.866 +
   1.867 +    /* the buffered page is the data we want, and we're ready for it;
   1.868 +       add it to the stream state */
   1.869 +    ogg_stream_pagein(&vf->os,&og);
   1.870 +
   1.871 +  }
   1.872 +}
   1.873 +
   1.874 +/* if, eg, 64 bit stdio is configured by default, this will build with
   1.875 +   fseek64 */
   1.876 +static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
   1.877 +  if(f==NULL)return(-1);
   1.878 +  return fseek(f,off,whence);
   1.879 +}
   1.880 +
   1.881 +static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
   1.882 +                     long ibytes, ov_callbacks callbacks){
   1.883 +  int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
   1.884 +  long *serialno_list=NULL;
   1.885 +  int serialno_list_size=0;
   1.886 +  int ret;
   1.887 +
   1.888 +  memset(vf,0,sizeof(*vf));
   1.889 +  vf->datasource=f;
   1.890 +  vf->callbacks = callbacks;
   1.891 +
   1.892 +  /* init the framing state */
   1.893 +  ogg_sync_init(&vf->oy);
   1.894 +
   1.895 +  /* perhaps some data was previously read into a buffer for testing
   1.896 +     against other stream types.  Allow initialization from this
   1.897 +     previously read data (especially as we may be reading from a
   1.898 +     non-seekable stream) */
   1.899 +  if(initial){
   1.900 +    char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
   1.901 +    memcpy(buffer,initial,ibytes);
   1.902 +    ogg_sync_wrote(&vf->oy,ibytes);
   1.903 +  }
   1.904 +
   1.905 +  /* can we seek? Stevens suggests the seek test was portable */
   1.906 +  if(offsettest!=-1)vf->seekable=1;
   1.907 +
   1.908 +  /* No seeking yet; Set up a 'single' (current) logical bitstream
   1.909 +     entry for partial open */
   1.910 +  vf->links=1;
   1.911 +  vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
   1.912 +  vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
   1.913 +  ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
   1.914 +
   1.915 +  /* Fetch all BOS pages, store the vorbis header and all seen serial
   1.916 +     numbers, load subsequent vorbis setup headers */
   1.917 +  if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
   1.918 +    vf->datasource=NULL;
   1.919 +    ov_clear(vf);
   1.920 +  }else{
   1.921 +    /* serial number list for first link needs to be held somewhere
   1.922 +       for second stage of seekable stream open; this saves having to
   1.923 +       seek/reread first link's serialnumber data then. */
   1.924 +    vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
   1.925 +    vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
   1.926 +    vf->serialnos[1]=serialno_list_size;
   1.927 +    memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
   1.928 +
   1.929 +    vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
   1.930 +    vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
   1.931 +    vf->offsets[0]=0;
   1.932 +    vf->dataoffsets[0]=vf->offset;
   1.933 +
   1.934 +    vf->ready_state=PARTOPEN;
   1.935 +  }
   1.936 +  if(serialno_list)_ogg_free(serialno_list);
   1.937 +  return(ret);
   1.938 +}
   1.939 +
   1.940 +static int _ov_open2(OggVorbis_File *vf){
   1.941 +  if(vf->ready_state != PARTOPEN) return OV_EINVAL;
   1.942 +  vf->ready_state=OPENED;
   1.943 +  if(vf->seekable){
   1.944 +    int ret=_open_seekable2(vf);
   1.945 +    if(ret){
   1.946 +      vf->datasource=NULL;
   1.947 +      ov_clear(vf);
   1.948 +    }
   1.949 +    return(ret);
   1.950 +  }else
   1.951 +    vf->ready_state=STREAMSET;
   1.952 +
   1.953 +  return 0;
   1.954 +}
   1.955 +
   1.956 +
   1.957 +/* clear out the OggVorbis_File struct */
   1.958 +int ov_clear(OggVorbis_File *vf){
   1.959 +  if(vf){
   1.960 +    vorbis_block_clear(&vf->vb);
   1.961 +    vorbis_dsp_clear(&vf->vd);
   1.962 +    ogg_stream_clear(&vf->os);
   1.963 +
   1.964 +    if(vf->vi && vf->links){
   1.965 +      int i;
   1.966 +      for(i=0;i<vf->links;i++){
   1.967 +        vorbis_info_clear(vf->vi+i);
   1.968 +        vorbis_comment_clear(vf->vc+i);
   1.969 +      }
   1.970 +      _ogg_free(vf->vi);
   1.971 +      _ogg_free(vf->vc);
   1.972 +    }
   1.973 +    if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
   1.974 +    if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
   1.975 +    if(vf->serialnos)_ogg_free(vf->serialnos);
   1.976 +    if(vf->offsets)_ogg_free(vf->offsets);
   1.977 +    ogg_sync_clear(&vf->oy);
   1.978 +    if(vf->datasource && vf->callbacks.close_func)
   1.979 +      (vf->callbacks.close_func)(vf->datasource);
   1.980 +    memset(vf,0,sizeof(*vf));
   1.981 +  }
   1.982 +#ifdef DEBUG_LEAKS
   1.983 +  _VDBG_dump();
   1.984 +#endif
   1.985 +  return(0);
   1.986 +}
   1.987 +
   1.988 +/* inspects the OggVorbis file and finds/documents all the logical
   1.989 +   bitstreams contained in it.  Tries to be tolerant of logical
   1.990 +   bitstream sections that are truncated/woogie.
   1.991 +
   1.992 +   return: -1) error
   1.993 +            0) OK
   1.994 +*/
   1.995 +
   1.996 +int ov_open_callbacks(void *f,OggVorbis_File *vf,
   1.997 +    const char *initial,long ibytes,ov_callbacks callbacks){
   1.998 +  int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
   1.999 +  if(ret)return ret;
  1.1000 +  return _ov_open2(vf);
  1.1001 +}
  1.1002 +
  1.1003 +int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
  1.1004 +  ov_callbacks callbacks = {
  1.1005 +    (size_t (*)(void *, size_t, size_t, void *))  fread,
  1.1006 +    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
  1.1007 +    (int (*)(void *))                             fclose,
  1.1008 +    (long (*)(void *))                            ftell
  1.1009 +  };
  1.1010 +
  1.1011 +  return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
  1.1012 +}
  1.1013 +
  1.1014 +int ov_fopen(const char *path,OggVorbis_File *vf){
  1.1015 +  int ret;
  1.1016 +  FILE *f = fopen(path,"rb");
  1.1017 +  if(!f) return -1;
  1.1018 +
  1.1019 +  ret = ov_open(f,vf,NULL,0);
  1.1020 +  if(ret) fclose(f);
  1.1021 +  return ret;
  1.1022 +}
  1.1023 +
  1.1024 +
  1.1025 +/* cheap hack for game usage where downsampling is desirable; there's
  1.1026 +   no need for SRC as we can just do it cheaply in libvorbis. */
  1.1027 +
  1.1028 +int ov_halfrate(OggVorbis_File *vf,int flag){
  1.1029 +  int i;
  1.1030 +  if(vf->vi==NULL)return OV_EINVAL;
  1.1031 +  if(vf->ready_state>STREAMSET){
  1.1032 +    /* clear out stream state; dumping the decode machine is needed to
  1.1033 +       reinit the MDCT lookups. */
  1.1034 +    vorbis_dsp_clear(&vf->vd);
  1.1035 +    vorbis_block_clear(&vf->vb);
  1.1036 +    vf->ready_state=STREAMSET;
  1.1037 +    if(vf->pcm_offset>=0){
  1.1038 +      ogg_int64_t pos=vf->pcm_offset;
  1.1039 +      vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */
  1.1040 +      ov_pcm_seek(vf,pos);
  1.1041 +    }
  1.1042 +  }
  1.1043 +
  1.1044 +  for(i=0;i<vf->links;i++){
  1.1045 +    if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
  1.1046 +      if(flag) ov_halfrate(vf,0);
  1.1047 +      return OV_EINVAL;
  1.1048 +    }
  1.1049 +  }
  1.1050 +  return 0;
  1.1051 +}
  1.1052 +
  1.1053 +int ov_halfrate_p(OggVorbis_File *vf){
  1.1054 +  if(vf->vi==NULL)return OV_EINVAL;
  1.1055 +  return vorbis_synthesis_halfrate_p(vf->vi);
  1.1056 +}
  1.1057 +
  1.1058 +/* Only partially open the vorbis file; test for Vorbisness, and load
  1.1059 +   the headers for the first chain.  Do not seek (although test for
  1.1060 +   seekability).  Use ov_test_open to finish opening the file, else
  1.1061 +   ov_clear to close/free it. Same return codes as open. */
  1.1062 +
  1.1063 +int ov_test_callbacks(void *f,OggVorbis_File *vf,
  1.1064 +    const char *initial,long ibytes,ov_callbacks callbacks)
  1.1065 +{
  1.1066 +  return _ov_open1(f,vf,initial,ibytes,callbacks);
  1.1067 +}
  1.1068 +
  1.1069 +int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
  1.1070 +  ov_callbacks callbacks = {
  1.1071 +    (size_t (*)(void *, size_t, size_t, void *))  fread,
  1.1072 +    (int (*)(void *, ogg_int64_t, int))              _fseek64_wrap,
  1.1073 +    (int (*)(void *))                             fclose,
  1.1074 +    (long (*)(void *))                            ftell
  1.1075 +  };
  1.1076 +
  1.1077 +  return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
  1.1078 +}
  1.1079 +
  1.1080 +int ov_test_open(OggVorbis_File *vf){
  1.1081 +  if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
  1.1082 +  return _ov_open2(vf);
  1.1083 +}
  1.1084 +
  1.1085 +/* How many logical bitstreams in this physical bitstream? */
  1.1086 +long ov_streams(OggVorbis_File *vf){
  1.1087 +  return vf->links;
  1.1088 +}
  1.1089 +
  1.1090 +/* Is the FILE * associated with vf seekable? */
  1.1091 +long ov_seekable(OggVorbis_File *vf){
  1.1092 +  return vf->seekable;
  1.1093 +}
  1.1094 +
  1.1095 +/* returns the bitrate for a given logical bitstream or the entire
  1.1096 +   physical bitstream.  If the file is open for random access, it will
  1.1097 +   find the *actual* average bitrate.  If the file is streaming, it
  1.1098 +   returns the nominal bitrate (if set) else the average of the
  1.1099 +   upper/lower bounds (if set) else -1 (unset).
  1.1100 +
  1.1101 +   If you want the actual bitrate field settings, get them from the
  1.1102 +   vorbis_info structs */
  1.1103 +
  1.1104 +long ov_bitrate(OggVorbis_File *vf,int i){
  1.1105 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1106 +  if(i>=vf->links)return(OV_EINVAL);
  1.1107 +  if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
  1.1108 +  if(i<0){
  1.1109 +    ogg_int64_t bits=0;
  1.1110 +    int i;
  1.1111 +    float br;
  1.1112 +    for(i=0;i<vf->links;i++)
  1.1113 +      bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
  1.1114 +    /* This once read: return(rint(bits/ov_time_total(vf,-1)));
  1.1115 +     * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
  1.1116 +     * so this is slightly transformed to make it work.
  1.1117 +     */
  1.1118 +    br = bits/ov_time_total(vf,-1);
  1.1119 +    return(rint(br));
  1.1120 +  }else{
  1.1121 +    if(vf->seekable){
  1.1122 +      /* return the actual bitrate */
  1.1123 +      return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i)));
  1.1124 +    }else{
  1.1125 +      /* return nominal if set */
  1.1126 +      if(vf->vi[i].bitrate_nominal>0){
  1.1127 +        return vf->vi[i].bitrate_nominal;
  1.1128 +      }else{
  1.1129 +        if(vf->vi[i].bitrate_upper>0){
  1.1130 +          if(vf->vi[i].bitrate_lower>0){
  1.1131 +            return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
  1.1132 +          }else{
  1.1133 +            return vf->vi[i].bitrate_upper;
  1.1134 +          }
  1.1135 +        }
  1.1136 +        return(OV_FALSE);
  1.1137 +      }
  1.1138 +    }
  1.1139 +  }
  1.1140 +}
  1.1141 +
  1.1142 +/* returns the actual bitrate since last call.  returns -1 if no
  1.1143 +   additional data to offer since last call (or at beginning of stream),
  1.1144 +   EINVAL if stream is only partially open
  1.1145 +*/
  1.1146 +long ov_bitrate_instant(OggVorbis_File *vf){
  1.1147 +  int link=(vf->seekable?vf->current_link:0);
  1.1148 +  long ret;
  1.1149 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1150 +  if(vf->samptrack==0)return(OV_FALSE);
  1.1151 +  ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5;
  1.1152 +  vf->bittrack=0.f;
  1.1153 +  vf->samptrack=0.f;
  1.1154 +  return(ret);
  1.1155 +}
  1.1156 +
  1.1157 +/* Guess */
  1.1158 +long ov_serialnumber(OggVorbis_File *vf,int i){
  1.1159 +  if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
  1.1160 +  if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
  1.1161 +  if(i<0){
  1.1162 +    return(vf->current_serialno);
  1.1163 +  }else{
  1.1164 +    return(vf->serialnos[i]);
  1.1165 +  }
  1.1166 +}
  1.1167 +
  1.1168 +/* returns: total raw (compressed) length of content if i==-1
  1.1169 +            raw (compressed) length of that logical bitstream for i==0 to n
  1.1170 +            OV_EINVAL if the stream is not seekable (we can't know the length)
  1.1171 +            or if stream is only partially open
  1.1172 +*/
  1.1173 +ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
  1.1174 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1175 +  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
  1.1176 +  if(i<0){
  1.1177 +    ogg_int64_t acc=0;
  1.1178 +    int i;
  1.1179 +    for(i=0;i<vf->links;i++)
  1.1180 +      acc+=ov_raw_total(vf,i);
  1.1181 +    return(acc);
  1.1182 +  }else{
  1.1183 +    return(vf->offsets[i+1]-vf->offsets[i]);
  1.1184 +  }
  1.1185 +}
  1.1186 +
  1.1187 +/* returns: total PCM length (samples) of content if i==-1 PCM length
  1.1188 +            (samples) of that logical bitstream for i==0 to n
  1.1189 +            OV_EINVAL if the stream is not seekable (we can't know the
  1.1190 +            length) or only partially open
  1.1191 +*/
  1.1192 +ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
  1.1193 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1194 +  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
  1.1195 +  if(i<0){
  1.1196 +    ogg_int64_t acc=0;
  1.1197 +    int i;
  1.1198 +    for(i=0;i<vf->links;i++)
  1.1199 +      acc+=ov_pcm_total(vf,i);
  1.1200 +    return(acc);
  1.1201 +  }else{
  1.1202 +    return(vf->pcmlengths[i*2+1]);
  1.1203 +  }
  1.1204 +}
  1.1205 +
  1.1206 +/* returns: total seconds of content if i==-1
  1.1207 +            seconds in that logical bitstream for i==0 to n
  1.1208 +            OV_EINVAL if the stream is not seekable (we can't know the
  1.1209 +            length) or only partially open
  1.1210 +*/
  1.1211 +double ov_time_total(OggVorbis_File *vf,int i){
  1.1212 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1213 +  if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
  1.1214 +  if(i<0){
  1.1215 +    double acc=0;
  1.1216 +    int i;
  1.1217 +    for(i=0;i<vf->links;i++)
  1.1218 +      acc+=ov_time_total(vf,i);
  1.1219 +    return(acc);
  1.1220 +  }else{
  1.1221 +    return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate);
  1.1222 +  }
  1.1223 +}
  1.1224 +
  1.1225 +/* seek to an offset relative to the *compressed* data. This also
  1.1226 +   scans packets to update the PCM cursor. It will cross a logical
  1.1227 +   bitstream boundary, but only if it can't get any packets out of the
  1.1228 +   tail of the bitstream we seek to (so no surprises).
  1.1229 +
  1.1230 +   returns zero on success, nonzero on failure */
  1.1231 +
  1.1232 +int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
  1.1233 +  ogg_stream_state work_os;
  1.1234 +  int ret;
  1.1235 +
  1.1236 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1237 +  if(!vf->seekable)
  1.1238 +    return(OV_ENOSEEK); /* don't dump machine if we can't seek */
  1.1239 +
  1.1240 +  if(pos<0 || pos>vf->end)return(OV_EINVAL);
  1.1241 +
  1.1242 +  /* is the seek position outside our current link [if any]? */
  1.1243 +  if(vf->ready_state>=STREAMSET){
  1.1244 +    if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1])
  1.1245 +      _decode_clear(vf); /* clear out stream state */
  1.1246 +  }
  1.1247 +
  1.1248 +  /* don't yet clear out decoding machine (if it's initialized), in
  1.1249 +     the case we're in the same link.  Restart the decode lapping, and
  1.1250 +     let _fetch_and_process_packet deal with a potential bitstream
  1.1251 +     boundary */
  1.1252 +  vf->pcm_offset=-1;
  1.1253 +  ogg_stream_reset_serialno(&vf->os,
  1.1254 +                            vf->current_serialno); /* must set serialno */
  1.1255 +  vorbis_synthesis_restart(&vf->vd);
  1.1256 +
  1.1257 +  ret=_seek_helper(vf,pos);
  1.1258 +  if(ret)goto seek_error;
  1.1259 +
  1.1260 +  /* we need to make sure the pcm_offset is set, but we don't want to
  1.1261 +     advance the raw cursor past good packets just to get to the first
  1.1262 +     with a granulepos.  That's not equivalent behavior to beginning
  1.1263 +     decoding as immediately after the seek position as possible.
  1.1264 +
  1.1265 +     So, a hack.  We use two stream states; a local scratch state and
  1.1266 +     the shared vf->os stream state.  We use the local state to
  1.1267 +     scan, and the shared state as a buffer for later decode.
  1.1268 +
  1.1269 +     Unfortuantely, on the last page we still advance to last packet
  1.1270 +     because the granulepos on the last page is not necessarily on a
  1.1271 +     packet boundary, and we need to make sure the granpos is
  1.1272 +     correct.
  1.1273 +  */
  1.1274 +
  1.1275 +  {
  1.1276 +    ogg_page og;
  1.1277 +    ogg_packet op;
  1.1278 +    int lastblock=0;
  1.1279 +    int accblock=0;
  1.1280 +    int thisblock=0;
  1.1281 +    int lastflag=0;
  1.1282 +    int firstflag=0;
  1.1283 +    ogg_int64_t pagepos=-1;
  1.1284 +
  1.1285 +    ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
  1.1286 +    ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
  1.1287 +                                   return from not necessarily
  1.1288 +                                   starting from the beginning */
  1.1289 +
  1.1290 +    while(1){
  1.1291 +      if(vf->ready_state>=STREAMSET){
  1.1292 +        /* snarf/scan a packet if we can */
  1.1293 +        int result=ogg_stream_packetout(&work_os,&op);
  1.1294 +
  1.1295 +        if(result>0){
  1.1296 +
  1.1297 +          if(vf->vi[vf->current_link].codec_setup){
  1.1298 +            thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
  1.1299 +            if(thisblock<0){
  1.1300 +              ogg_stream_packetout(&vf->os,NULL);
  1.1301 +              thisblock=0;
  1.1302 +            }else{
  1.1303 +
  1.1304 +              /* We can't get a guaranteed correct pcm position out of the
  1.1305 +                 last page in a stream because it might have a 'short'
  1.1306 +                 granpos, which can only be detected in the presence of a
  1.1307 +                 preceding page.  However, if the last page is also the first
  1.1308 +                 page, the granpos rules of a first page take precedence.  Not
  1.1309 +                 only that, but for first==last, the EOS page must be treated
  1.1310 +                 as if its a normal first page for the stream to open/play. */
  1.1311 +              if(lastflag && !firstflag)
  1.1312 +                ogg_stream_packetout(&vf->os,NULL);
  1.1313 +              else
  1.1314 +                if(lastblock)accblock+=(lastblock+thisblock)>>2;
  1.1315 +            }
  1.1316 +
  1.1317 +            if(op.granulepos!=-1){
  1.1318 +              int i,link=vf->current_link;
  1.1319 +              ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
  1.1320 +              if(granulepos<0)granulepos=0;
  1.1321 +
  1.1322 +              for(i=0;i<link;i++)
  1.1323 +                granulepos+=vf->pcmlengths[i*2+1];
  1.1324 +              vf->pcm_offset=granulepos-accblock;
  1.1325 +              if(vf->pcm_offset<0)vf->pcm_offset=0;
  1.1326 +              break;
  1.1327 +            }
  1.1328 +            lastblock=thisblock;
  1.1329 +            continue;
  1.1330 +          }else
  1.1331 +            ogg_stream_packetout(&vf->os,NULL);
  1.1332 +        }
  1.1333 +      }
  1.1334 +
  1.1335 +      if(!lastblock){
  1.1336 +        pagepos=_get_next_page(vf,&og,-1);
  1.1337 +        if(pagepos<0){
  1.1338 +          vf->pcm_offset=ov_pcm_total(vf,-1);
  1.1339 +          break;
  1.1340 +        }
  1.1341 +      }else{
  1.1342 +        /* huh?  Bogus stream with packets but no granulepos */
  1.1343 +        vf->pcm_offset=-1;
  1.1344 +        break;
  1.1345 +      }
  1.1346 +
  1.1347 +      /* has our decoding just traversed a bitstream boundary? */
  1.1348 +      if(vf->ready_state>=STREAMSET){
  1.1349 +        if(vf->current_serialno!=ogg_page_serialno(&og)){
  1.1350 +
  1.1351 +          /* two possibilities:
  1.1352 +             1) our decoding just traversed a bitstream boundary
  1.1353 +             2) another stream is multiplexed into this logical section? */
  1.1354 +
  1.1355 +          if(ogg_page_bos(&og)){
  1.1356 +            /* we traversed */
  1.1357 +            _decode_clear(vf); /* clear out stream state */
  1.1358 +            ogg_stream_clear(&work_os);
  1.1359 +          } /* else, do nothing; next loop will scoop another page */
  1.1360 +        }
  1.1361 +      }
  1.1362 +
  1.1363 +      if(vf->ready_state<STREAMSET){
  1.1364 +        int link;
  1.1365 +        long serialno = ogg_page_serialno(&og);
  1.1366 +
  1.1367 +        for(link=0;link<vf->links;link++)
  1.1368 +          if(vf->serialnos[link]==serialno)break;
  1.1369 +
  1.1370 +        if(link==vf->links) continue; /* not the desired Vorbis
  1.1371 +                                         bitstream section; keep
  1.1372 +                                         trying */
  1.1373 +        vf->current_link=link;
  1.1374 +        vf->current_serialno=serialno;
  1.1375 +        ogg_stream_reset_serialno(&vf->os,serialno);
  1.1376 +        ogg_stream_reset_serialno(&work_os,serialno);
  1.1377 +        vf->ready_state=STREAMSET;
  1.1378 +        firstflag=(pagepos<=vf->dataoffsets[link]);
  1.1379 +      }
  1.1380 +
  1.1381 +      ogg_stream_pagein(&vf->os,&og);
  1.1382 +      ogg_stream_pagein(&work_os,&og);
  1.1383 +      lastflag=ogg_page_eos(&og);
  1.1384 +
  1.1385 +    }
  1.1386 +  }
  1.1387 +
  1.1388 +  ogg_stream_clear(&work_os);
  1.1389 +  vf->bittrack=0.f;
  1.1390 +  vf->samptrack=0.f;
  1.1391 +  return(0);
  1.1392 +
  1.1393 + seek_error:
  1.1394 +  /* dump the machine so we're in a known state */
  1.1395 +  vf->pcm_offset=-1;
  1.1396 +  ogg_stream_clear(&work_os);
  1.1397 +  _decode_clear(vf);
  1.1398 +  return OV_EBADLINK;
  1.1399 +}
  1.1400 +
  1.1401 +/* Page granularity seek (faster than sample granularity because we
  1.1402 +   don't do the last bit of decode to find a specific sample).
  1.1403 +
  1.1404 +   Seek to the last [granule marked] page preceding the specified pos
  1.1405 +   location, such that decoding past the returned point will quickly
  1.1406 +   arrive at the requested position. */
  1.1407 +int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
  1.1408 +  int link=-1;
  1.1409 +  ogg_int64_t result=0;
  1.1410 +  ogg_int64_t total=ov_pcm_total(vf,-1);
  1.1411 +
  1.1412 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1413 +  if(!vf->seekable)return(OV_ENOSEEK);
  1.1414 +
  1.1415 +  if(pos<0 || pos>total)return(OV_EINVAL);
  1.1416 +
  1.1417 +  /* which bitstream section does this pcm offset occur in? */
  1.1418 +  for(link=vf->links-1;link>=0;link--){
  1.1419 +    total-=vf->pcmlengths[link*2+1];
  1.1420 +    if(pos>=total)break;
  1.1421 +  }
  1.1422 +
  1.1423 +  /* search within the logical bitstream for the page with the highest
  1.1424 +     pcm_pos preceding (or equal to) pos.  There is a danger here;
  1.1425 +     missing pages or incorrect frame number information in the
  1.1426 +     bitstream could make our task impossible.  Account for that (it
  1.1427 +     would be an error condition) */
  1.1428 +
  1.1429 +  /* new search algorithm by HB (Nicholas Vinen) */
  1.1430 +  {
  1.1431 +    ogg_int64_t end=vf->offsets[link+1];
  1.1432 +    ogg_int64_t begin=vf->offsets[link];
  1.1433 +    ogg_int64_t begintime = vf->pcmlengths[link*2];
  1.1434 +    ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
  1.1435 +    ogg_int64_t target=pos-total+begintime;
  1.1436 +    ogg_int64_t best=begin;
  1.1437 +
  1.1438 +    ogg_page og;
  1.1439 +    while(begin<end){
  1.1440 +      ogg_int64_t bisect;
  1.1441 +
  1.1442 +      if(end-begin<CHUNKSIZE){
  1.1443 +        bisect=begin;
  1.1444 +      }else{
  1.1445 +        /* take a (pretty decent) guess. */
  1.1446 +        bisect=begin +
  1.1447 +          (ogg_int64_t)((double)(target-begintime)*(end-begin)/(endtime-begintime))
  1.1448 +          - CHUNKSIZE;
  1.1449 +        if(bisect<begin+CHUNKSIZE)
  1.1450 +          bisect=begin;
  1.1451 +      }
  1.1452 +
  1.1453 +      if(bisect!=vf->offset){
  1.1454 +        result=_seek_helper(vf,bisect);
  1.1455 +        if(result) goto seek_error;
  1.1456 +      }
  1.1457 +
  1.1458 +      while(begin<end){
  1.1459 +        result=_get_next_page(vf,&og,end-vf->offset);
  1.1460 +        if(result==OV_EREAD) goto seek_error;
  1.1461 +        if(result<0){
  1.1462 +          if(bisect<=begin+1)
  1.1463 +            end=begin; /* found it */
  1.1464 +          else{
  1.1465 +            if(bisect==0) goto seek_error;
  1.1466 +            bisect-=CHUNKSIZE;
  1.1467 +            if(bisect<=begin)bisect=begin+1;
  1.1468 +            result=_seek_helper(vf,bisect);
  1.1469 +            if(result) goto seek_error;
  1.1470 +          }
  1.1471 +        }else{
  1.1472 +          ogg_int64_t granulepos;
  1.1473 +
  1.1474 +          if(ogg_page_serialno(&og)!=vf->serialnos[link])
  1.1475 +            continue;
  1.1476 +
  1.1477 +          granulepos=ogg_page_granulepos(&og);
  1.1478 +          if(granulepos==-1)continue;
  1.1479 +
  1.1480 +          if(granulepos<target){
  1.1481 +            best=result;  /* raw offset of packet with granulepos */
  1.1482 +            begin=vf->offset; /* raw offset of next page */
  1.1483 +            begintime=granulepos;
  1.1484 +
  1.1485 +            if(target-begintime>44100)break;
  1.1486 +            bisect=begin; /* *not* begin + 1 */
  1.1487 +          }else{
  1.1488 +            if(bisect<=begin+1)
  1.1489 +              end=begin;  /* found it */
  1.1490 +            else{
  1.1491 +              if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
  1.1492 +                end=result;
  1.1493 +                bisect-=CHUNKSIZE; /* an endless loop otherwise. */
  1.1494 +                if(bisect<=begin)bisect=begin+1;
  1.1495 +                result=_seek_helper(vf,bisect);
  1.1496 +                if(result) goto seek_error;
  1.1497 +              }else{
  1.1498 +                end=bisect;
  1.1499 +                endtime=granulepos;
  1.1500 +                break;
  1.1501 +              }
  1.1502 +            }
  1.1503 +          }
  1.1504 +        }
  1.1505 +      }
  1.1506 +    }
  1.1507 +
  1.1508 +    /* found our page. seek to it, update pcm offset. Easier case than
  1.1509 +       raw_seek, don't keep packets preceding granulepos. */
  1.1510 +    {
  1.1511 +      ogg_page og;
  1.1512 +      ogg_packet op;
  1.1513 +
  1.1514 +      /* seek */
  1.1515 +      result=_seek_helper(vf,best);
  1.1516 +      vf->pcm_offset=-1;
  1.1517 +      if(result) goto seek_error;
  1.1518 +      result=_get_next_page(vf,&og,-1);
  1.1519 +      if(result<0) goto seek_error;
  1.1520 +
  1.1521 +      if(link!=vf->current_link){
  1.1522 +        /* Different link; dump entire decode machine */
  1.1523 +        _decode_clear(vf);
  1.1524 +
  1.1525 +        vf->current_link=link;
  1.1526 +        vf->current_serialno=vf->serialnos[link];
  1.1527 +        vf->ready_state=STREAMSET;
  1.1528 +
  1.1529 +      }else{
  1.1530 +        vorbis_synthesis_restart(&vf->vd);
  1.1531 +      }
  1.1532 +
  1.1533 +      ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
  1.1534 +      ogg_stream_pagein(&vf->os,&og);
  1.1535 +
  1.1536 +      /* pull out all but last packet; the one with granulepos */
  1.1537 +      while(1){
  1.1538 +        result=ogg_stream_packetpeek(&vf->os,&op);
  1.1539 +        if(result==0){
  1.1540 +          /* !!! the packet finishing this page originated on a
  1.1541 +             preceding page. Keep fetching previous pages until we
  1.1542 +             get one with a granulepos or without the 'continued' flag
  1.1543 +             set.  Then just use raw_seek for simplicity. */
  1.1544 +
  1.1545 +          result=_seek_helper(vf,best);
  1.1546 +          if(result<0) goto seek_error;
  1.1547 +
  1.1548 +          while(1){
  1.1549 +            result=_get_prev_page(vf,&og);
  1.1550 +            if(result<0) goto seek_error;
  1.1551 +            if(ogg_page_serialno(&og)==vf->current_serialno &&
  1.1552 +               (ogg_page_granulepos(&og)>-1 ||
  1.1553 +                !ogg_page_continued(&og))){
  1.1554 +              return ov_raw_seek(vf,result);
  1.1555 +            }
  1.1556 +            vf->offset=result;
  1.1557 +          }
  1.1558 +        }
  1.1559 +        if(result<0){
  1.1560 +          result = OV_EBADPACKET;
  1.1561 +          goto seek_error;
  1.1562 +        }
  1.1563 +        if(op.granulepos!=-1){
  1.1564 +          vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
  1.1565 +          if(vf->pcm_offset<0)vf->pcm_offset=0;
  1.1566 +          vf->pcm_offset+=total;
  1.1567 +          break;
  1.1568 +        }else
  1.1569 +          result=ogg_stream_packetout(&vf->os,NULL);
  1.1570 +      }
  1.1571 +    }
  1.1572 +  }
  1.1573 +
  1.1574 +  /* verify result */
  1.1575 +  if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
  1.1576 +    result=OV_EFAULT;
  1.1577 +    goto seek_error;
  1.1578 +  }
  1.1579 +  vf->bittrack=0.f;
  1.1580 +  vf->samptrack=0.f;
  1.1581 +  return(0);
  1.1582 +
  1.1583 + seek_error:
  1.1584 +  /* dump machine so we're in a known state */
  1.1585 +  vf->pcm_offset=-1;
  1.1586 +  _decode_clear(vf);
  1.1587 +  return (int)result;
  1.1588 +}
  1.1589 +
  1.1590 +/* seek to a sample offset relative to the decompressed pcm stream
  1.1591 +   returns zero on success, nonzero on failure */
  1.1592 +
  1.1593 +int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
  1.1594 +  int thisblock,lastblock=0;
  1.1595 +  int ret=ov_pcm_seek_page(vf,pos);
  1.1596 +  if(ret<0)return(ret);
  1.1597 +  if((ret=_make_decode_ready(vf)))return ret;
  1.1598 +
  1.1599 +  /* discard leading packets we don't need for the lapping of the
  1.1600 +     position we want; don't decode them */
  1.1601 +
  1.1602 +  while(1){
  1.1603 +    ogg_packet op;
  1.1604 +    ogg_page og;
  1.1605 +
  1.1606 +    int ret=ogg_stream_packetpeek(&vf->os,&op);
  1.1607 +    if(ret>0){
  1.1608 +      thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
  1.1609 +      if(thisblock<0){
  1.1610 +        ogg_stream_packetout(&vf->os,NULL);
  1.1611 +        continue; /* non audio packet */
  1.1612 +      }
  1.1613 +      if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
  1.1614 +
  1.1615 +      if(vf->pcm_offset+((thisblock+
  1.1616 +                          vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
  1.1617 +
  1.1618 +      /* remove the packet from packet queue and track its granulepos */
  1.1619 +      ogg_stream_packetout(&vf->os,NULL);
  1.1620 +      vorbis_synthesis_trackonly(&vf->vb,&op);  /* set up a vb with
  1.1621 +                                                   only tracking, no
  1.1622 +                                                   pcm_decode */
  1.1623 +      vorbis_synthesis_blockin(&vf->vd,&vf->vb);
  1.1624 +
  1.1625 +      /* end of logical stream case is hard, especially with exact
  1.1626 +         length positioning. */
  1.1627 +
  1.1628 +      if(op.granulepos>-1){
  1.1629 +        int i;
  1.1630 +        /* always believe the stream markers */
  1.1631 +        vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
  1.1632 +        if(vf->pcm_offset<0)vf->pcm_offset=0;
  1.1633 +        for(i=0;i<vf->current_link;i++)
  1.1634 +          vf->pcm_offset+=vf->pcmlengths[i*2+1];
  1.1635 +      }
  1.1636 +
  1.1637 +      lastblock=thisblock;
  1.1638 +
  1.1639 +    }else{
  1.1640 +      if(ret<0 && ret!=OV_HOLE)break;
  1.1641 +
  1.1642 +      /* suck in a new page */
  1.1643 +      if(_get_next_page(vf,&og,-1)<0)break;
  1.1644 +      if(ogg_page_bos(&og))_decode_clear(vf);
  1.1645 +
  1.1646 +      if(vf->ready_state<STREAMSET){
  1.1647 +        long serialno=ogg_page_serialno(&og);
  1.1648 +        int link;
  1.1649 +
  1.1650 +        for(link=0;link<vf->links;link++)
  1.1651 +          if(vf->serialnos[link]==serialno)break;
  1.1652 +        if(link==vf->links) continue;
  1.1653 +        vf->current_link=link;
  1.1654 +
  1.1655 +        vf->ready_state=STREAMSET;
  1.1656 +        vf->current_serialno=ogg_page_serialno(&og);
  1.1657 +        ogg_stream_reset_serialno(&vf->os,serialno);
  1.1658 +        ret=_make_decode_ready(vf);
  1.1659 +        if(ret)return ret;
  1.1660 +        lastblock=0;
  1.1661 +      }
  1.1662 +
  1.1663 +      ogg_stream_pagein(&vf->os,&og);
  1.1664 +    }
  1.1665 +  }
  1.1666 +
  1.1667 +  vf->bittrack=0.f;
  1.1668 +  vf->samptrack=0.f;
  1.1669 +  /* discard samples until we reach the desired position. Crossing a
  1.1670 +     logical bitstream boundary with abandon is OK. */
  1.1671 +  {
  1.1672 +    /* note that halfrate could be set differently in each link, but
  1.1673 +       vorbisfile encoforces all links are set or unset */
  1.1674 +    int hs=vorbis_synthesis_halfrate_p(vf->vi);
  1.1675 +    while(vf->pcm_offset<((pos>>hs)<<hs)){
  1.1676 +      ogg_int64_t target=(pos-vf->pcm_offset)>>hs;
  1.1677 +      long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
  1.1678 +
  1.1679 +      if(samples>target)samples=target;
  1.1680 +      vorbis_synthesis_read(&vf->vd,samples);
  1.1681 +      vf->pcm_offset+=samples<<hs;
  1.1682 +
  1.1683 +      if(samples<target)
  1.1684 +        if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
  1.1685 +          vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
  1.1686 +    }
  1.1687 +  }
  1.1688 +  return 0;
  1.1689 +}
  1.1690 +
  1.1691 +/* seek to a playback time relative to the decompressed pcm stream
  1.1692 +   returns zero on success, nonzero on failure */
  1.1693 +int ov_time_seek(OggVorbis_File *vf,double seconds){
  1.1694 +  /* translate time to PCM position and call ov_pcm_seek */
  1.1695 +
  1.1696 +  int link=-1;
  1.1697 +  ogg_int64_t pcm_total=0;
  1.1698 +  double time_total=0.;
  1.1699 +
  1.1700 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1701 +  if(!vf->seekable)return(OV_ENOSEEK);
  1.1702 +  if(seconds<0)return(OV_EINVAL);
  1.1703 +
  1.1704 +  /* which bitstream section does this time offset occur in? */
  1.1705 +  for(link=0;link<vf->links;link++){
  1.1706 +    double addsec = ov_time_total(vf,link);
  1.1707 +    if(seconds<time_total+addsec)break;
  1.1708 +    time_total+=addsec;
  1.1709 +    pcm_total+=vf->pcmlengths[link*2+1];
  1.1710 +  }
  1.1711 +
  1.1712 +  if(link==vf->links)return(OV_EINVAL);
  1.1713 +
  1.1714 +  /* enough information to convert time offset to pcm offset */
  1.1715 +  {
  1.1716 +    ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
  1.1717 +    return(ov_pcm_seek(vf,target));
  1.1718 +  }
  1.1719 +}
  1.1720 +
  1.1721 +/* page-granularity version of ov_time_seek
  1.1722 +   returns zero on success, nonzero on failure */
  1.1723 +int ov_time_seek_page(OggVorbis_File *vf,double seconds){
  1.1724 +  /* translate time to PCM position and call ov_pcm_seek */
  1.1725 +
  1.1726 +  int link=-1;
  1.1727 +  ogg_int64_t pcm_total=0;
  1.1728 +  double time_total=0.;
  1.1729 +
  1.1730 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1731 +  if(!vf->seekable)return(OV_ENOSEEK);
  1.1732 +  if(seconds<0)return(OV_EINVAL);
  1.1733 +
  1.1734 +  /* which bitstream section does this time offset occur in? */
  1.1735 +  for(link=0;link<vf->links;link++){
  1.1736 +    double addsec = ov_time_total(vf,link);
  1.1737 +    if(seconds<time_total+addsec)break;
  1.1738 +    time_total+=addsec;
  1.1739 +    pcm_total+=vf->pcmlengths[link*2+1];
  1.1740 +  }
  1.1741 +
  1.1742 +  if(link==vf->links)return(OV_EINVAL);
  1.1743 +
  1.1744 +  /* enough information to convert time offset to pcm offset */
  1.1745 +  {
  1.1746 +    ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate;
  1.1747 +    return(ov_pcm_seek_page(vf,target));
  1.1748 +  }
  1.1749 +}
  1.1750 +
  1.1751 +/* tell the current stream offset cursor.  Note that seek followed by
  1.1752 +   tell will likely not give the set offset due to caching */
  1.1753 +ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
  1.1754 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1755 +  return(vf->offset);
  1.1756 +}
  1.1757 +
  1.1758 +/* return PCM offset (sample) of next PCM sample to be read */
  1.1759 +ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
  1.1760 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1761 +  return(vf->pcm_offset);
  1.1762 +}
  1.1763 +
  1.1764 +/* return time offset (seconds) of next PCM sample to be read */
  1.1765 +double ov_time_tell(OggVorbis_File *vf){
  1.1766 +  int link=0;
  1.1767 +  ogg_int64_t pcm_total=0;
  1.1768 +  double time_total=0.f;
  1.1769 +
  1.1770 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1771 +  if(vf->seekable){
  1.1772 +    pcm_total=ov_pcm_total(vf,-1);
  1.1773 +    time_total=ov_time_total(vf,-1);
  1.1774 +
  1.1775 +    /* which bitstream section does this time offset occur in? */
  1.1776 +    for(link=vf->links-1;link>=0;link--){
  1.1777 +      pcm_total-=vf->pcmlengths[link*2+1];
  1.1778 +      time_total-=ov_time_total(vf,link);
  1.1779 +      if(vf->pcm_offset>=pcm_total)break;
  1.1780 +    }
  1.1781 +  }
  1.1782 +
  1.1783 +  return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate);
  1.1784 +}
  1.1785 +
  1.1786 +/*  link:   -1) return the vorbis_info struct for the bitstream section
  1.1787 +                currently being decoded
  1.1788 +           0-n) to request information for a specific bitstream section
  1.1789 +
  1.1790 +    In the case of a non-seekable bitstream, any call returns the
  1.1791 +    current bitstream.  NULL in the case that the machine is not
  1.1792 +    initialized */
  1.1793 +
  1.1794 +vorbis_info *ov_info(OggVorbis_File *vf,int link){
  1.1795 +  if(vf->seekable){
  1.1796 +    if(link<0)
  1.1797 +      if(vf->ready_state>=STREAMSET)
  1.1798 +        return vf->vi+vf->current_link;
  1.1799 +      else
  1.1800 +      return vf->vi;
  1.1801 +    else
  1.1802 +      if(link>=vf->links)
  1.1803 +        return NULL;
  1.1804 +      else
  1.1805 +        return vf->vi+link;
  1.1806 +  }else{
  1.1807 +    return vf->vi;
  1.1808 +  }
  1.1809 +}
  1.1810 +
  1.1811 +/* grr, strong typing, grr, no templates/inheritence, grr */
  1.1812 +vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
  1.1813 +  if(vf->seekable){
  1.1814 +    if(link<0)
  1.1815 +      if(vf->ready_state>=STREAMSET)
  1.1816 +        return vf->vc+vf->current_link;
  1.1817 +      else
  1.1818 +        return vf->vc;
  1.1819 +    else
  1.1820 +      if(link>=vf->links)
  1.1821 +        return NULL;
  1.1822 +      else
  1.1823 +        return vf->vc+link;
  1.1824 +  }else{
  1.1825 +    return vf->vc;
  1.1826 +  }
  1.1827 +}
  1.1828 +
  1.1829 +static int host_is_big_endian() {
  1.1830 +  ogg_int32_t pattern = 0xfeedface; /* deadbeef */
  1.1831 +  unsigned char *bytewise = (unsigned char *)&pattern;
  1.1832 +  if (bytewise[0] == 0xfe) return 1;
  1.1833 +  return 0;
  1.1834 +}
  1.1835 +
  1.1836 +/* up to this point, everything could more or less hide the multiple
  1.1837 +   logical bitstream nature of chaining from the toplevel application
  1.1838 +   if the toplevel application didn't particularly care.  However, at
  1.1839 +   the point that we actually read audio back, the multiple-section
  1.1840 +   nature must surface: Multiple bitstream sections do not necessarily
  1.1841 +   have to have the same number of channels or sampling rate.
  1.1842 +
  1.1843 +   ov_read returns the sequential logical bitstream number currently
  1.1844 +   being decoded along with the PCM data in order that the toplevel
  1.1845 +   application can take action on channel/sample rate changes.  This
  1.1846 +   number will be incremented even for streamed (non-seekable) streams
  1.1847 +   (for seekable streams, it represents the actual logical bitstream
  1.1848 +   index within the physical bitstream.  Note that the accessor
  1.1849 +   functions above are aware of this dichotomy).
  1.1850 +
  1.1851 +   ov_read_filter is exactly the same as ov_read except that it processes
  1.1852 +   the decoded audio data through a filter before packing it into the
  1.1853 +   requested format. This gives greater accuracy than applying a filter
  1.1854 +   after the audio has been converted into integral PCM.
  1.1855 +
  1.1856 +   input values: buffer) a buffer to hold packed PCM data for return
  1.1857 +                 length) the byte length requested to be placed into buffer
  1.1858 +                 bigendianp) should the data be packed LSB first (0) or
  1.1859 +                             MSB first (1)
  1.1860 +                 word) word size for output.  currently 1 (byte) or
  1.1861 +                       2 (16 bit short)
  1.1862 +
  1.1863 +   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
  1.1864 +                   0) EOF
  1.1865 +                   n) number of bytes of PCM actually returned.  The
  1.1866 +                   below works on a packet-by-packet basis, so the
  1.1867 +                   return length is not related to the 'length' passed
  1.1868 +                   in, just guaranteed to fit.
  1.1869 +
  1.1870 +            *section) set to the logical bitstream number */
  1.1871 +
  1.1872 +long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
  1.1873 +                    int bigendianp,int word,int sgned,int *bitstream,
  1.1874 +                    void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){
  1.1875 +  int i,j;
  1.1876 +  int host_endian = host_is_big_endian();
  1.1877 +  int hs;
  1.1878 +
  1.1879 +  float **pcm;
  1.1880 +  long samples;
  1.1881 +
  1.1882 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.1883 +
  1.1884 +  while(1){
  1.1885 +    if(vf->ready_state==INITSET){
  1.1886 +      samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
  1.1887 +      if(samples)break;
  1.1888 +    }
  1.1889 +
  1.1890 +    /* suck in another packet */
  1.1891 +    {
  1.1892 +      int ret=_fetch_and_process_packet(vf,NULL,1,1);
  1.1893 +      if(ret==OV_EOF)
  1.1894 +        return(0);
  1.1895 +      if(ret<=0)
  1.1896 +        return(ret);
  1.1897 +    }
  1.1898 +
  1.1899 +  }
  1.1900 +
  1.1901 +  if(samples>0){
  1.1902 +
  1.1903 +    /* yay! proceed to pack data into the byte buffer */
  1.1904 +
  1.1905 +    long channels=ov_info(vf,-1)->channels;
  1.1906 +    long bytespersample=word * channels;
  1.1907 +    vorbis_fpu_control fpu;
  1.1908 +    if(samples>length/bytespersample)samples=length/bytespersample;
  1.1909 +
  1.1910 +    if(samples <= 0)
  1.1911 +      return OV_EINVAL;
  1.1912 +
  1.1913 +    /* Here. */
  1.1914 +    if(filter)
  1.1915 +      filter(pcm,channels,samples,filter_param);
  1.1916 +
  1.1917 +    /* a tight loop to pack each size */
  1.1918 +    {
  1.1919 +      int val;
  1.1920 +      if(word==1){
  1.1921 +        int off=(sgned?0:128);
  1.1922 +        vorbis_fpu_setround(&fpu);
  1.1923 +        for(j=0;j<samples;j++)
  1.1924 +          for(i=0;i<channels;i++){
  1.1925 +            val=vorbis_ftoi(pcm[i][j]*128.f);
  1.1926 +            if(val>127)val=127;
  1.1927 +            else if(val<-128)val=-128;
  1.1928 +            *buffer++=val+off;
  1.1929 +          }
  1.1930 +        vorbis_fpu_restore(fpu);
  1.1931 +      }else{
  1.1932 +        int off=(sgned?0:32768);
  1.1933 +
  1.1934 +        if(host_endian==bigendianp){
  1.1935 +          if(sgned){
  1.1936 +
  1.1937 +            vorbis_fpu_setround(&fpu);
  1.1938 +            for(i=0;i<channels;i++) { /* It's faster in this order */
  1.1939 +              float *src=pcm[i];
  1.1940 +              short *dest=((short *)buffer)+i;
  1.1941 +              for(j=0;j<samples;j++) {
  1.1942 +                val=vorbis_ftoi(src[j]*32768.f);
  1.1943 +                if(val>32767)val=32767;
  1.1944 +                else if(val<-32768)val=-32768;
  1.1945 +                *dest=val;
  1.1946 +                dest+=channels;
  1.1947 +              }
  1.1948 +            }
  1.1949 +            vorbis_fpu_restore(fpu);
  1.1950 +
  1.1951 +          }else{
  1.1952 +
  1.1953 +            vorbis_fpu_setround(&fpu);
  1.1954 +            for(i=0;i<channels;i++) {
  1.1955 +              float *src=pcm[i];
  1.1956 +              short *dest=((short *)buffer)+i;
  1.1957 +              for(j=0;j<samples;j++) {
  1.1958 +                val=vorbis_ftoi(src[j]*32768.f);
  1.1959 +                if(val>32767)val=32767;
  1.1960 +                else if(val<-32768)val=-32768;
  1.1961 +                *dest=val+off;
  1.1962 +                dest+=channels;
  1.1963 +              }
  1.1964 +            }
  1.1965 +            vorbis_fpu_restore(fpu);
  1.1966 +
  1.1967 +          }
  1.1968 +        }else if(bigendianp){
  1.1969 +
  1.1970 +          vorbis_fpu_setround(&fpu);
  1.1971 +          for(j=0;j<samples;j++)
  1.1972 +            for(i=0;i<channels;i++){
  1.1973 +              val=vorbis_ftoi(pcm[i][j]*32768.f);
  1.1974 +              if(val>32767)val=32767;
  1.1975 +              else if(val<-32768)val=-32768;
  1.1976 +              val+=off;
  1.1977 +              *buffer++=(val>>8);
  1.1978 +              *buffer++=(val&0xff);
  1.1979 +            }
  1.1980 +          vorbis_fpu_restore(fpu);
  1.1981 +
  1.1982 +        }else{
  1.1983 +          int val;
  1.1984 +          vorbis_fpu_setround(&fpu);
  1.1985 +          for(j=0;j<samples;j++)
  1.1986 +            for(i=0;i<channels;i++){
  1.1987 +              val=vorbis_ftoi(pcm[i][j]*32768.f);
  1.1988 +              if(val>32767)val=32767;
  1.1989 +              else if(val<-32768)val=-32768;
  1.1990 +              val+=off;
  1.1991 +              *buffer++=(val&0xff);
  1.1992 +              *buffer++=(val>>8);
  1.1993 +                  }
  1.1994 +          vorbis_fpu_restore(fpu);
  1.1995 +
  1.1996 +        }
  1.1997 +      }
  1.1998 +    }
  1.1999 +
  1.2000 +    vorbis_synthesis_read(&vf->vd,samples);
  1.2001 +    hs=vorbis_synthesis_halfrate_p(vf->vi);
  1.2002 +    vf->pcm_offset+=(samples<<hs);
  1.2003 +    if(bitstream)*bitstream=vf->current_link;
  1.2004 +    return(samples*bytespersample);
  1.2005 +  }else{
  1.2006 +    return(samples);
  1.2007 +  }
  1.2008 +}
  1.2009 +
  1.2010 +long ov_read(OggVorbis_File *vf,char *buffer,int length,
  1.2011 +             int bigendianp,int word,int sgned,int *bitstream){
  1.2012 +  return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL);
  1.2013 +}
  1.2014 +
  1.2015 +/* input values: pcm_channels) a float vector per channel of output
  1.2016 +                 length) the sample length being read by the app
  1.2017 +
  1.2018 +   return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
  1.2019 +                   0) EOF
  1.2020 +                   n) number of samples of PCM actually returned.  The
  1.2021 +                   below works on a packet-by-packet basis, so the
  1.2022 +                   return length is not related to the 'length' passed
  1.2023 +                   in, just guaranteed to fit.
  1.2024 +
  1.2025 +            *section) set to the logical bitstream number */
  1.2026 +
  1.2027 +
  1.2028 +
  1.2029 +long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
  1.2030 +                   int *bitstream){
  1.2031 +
  1.2032 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.2033 +
  1.2034 +  while(1){
  1.2035 +    if(vf->ready_state==INITSET){
  1.2036 +      float **pcm;
  1.2037 +      long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
  1.2038 +      if(samples){
  1.2039 +        int hs=vorbis_synthesis_halfrate_p(vf->vi);
  1.2040 +        if(pcm_channels)*pcm_channels=pcm;
  1.2041 +        if(samples>length)samples=length;
  1.2042 +        vorbis_synthesis_read(&vf->vd,samples);
  1.2043 +        vf->pcm_offset+=samples<<hs;
  1.2044 +        if(bitstream)*bitstream=vf->current_link;
  1.2045 +        return samples;
  1.2046 +
  1.2047 +      }
  1.2048 +    }
  1.2049 +
  1.2050 +    /* suck in another packet */
  1.2051 +    {
  1.2052 +      int ret=_fetch_and_process_packet(vf,NULL,1,1);
  1.2053 +      if(ret==OV_EOF)return(0);
  1.2054 +      if(ret<=0)return(ret);
  1.2055 +    }
  1.2056 +
  1.2057 +  }
  1.2058 +}
  1.2059 +
  1.2060 +extern float *vorbis_window(vorbis_dsp_state *v,int W);
  1.2061 +
  1.2062 +static void _ov_splice(float **pcm,float **lappcm,
  1.2063 +                       int n1, int n2,
  1.2064 +                       int ch1, int ch2,
  1.2065 +                       float *w1, float *w2){
  1.2066 +  int i,j;
  1.2067 +  float *w=w1;
  1.2068 +  int n=n1;
  1.2069 +
  1.2070 +  if(n1>n2){
  1.2071 +    n=n2;
  1.2072 +    w=w2;
  1.2073 +  }
  1.2074 +
  1.2075 +  /* splice */
  1.2076 +  for(j=0;j<ch1 && j<ch2;j++){
  1.2077 +    float *s=lappcm[j];
  1.2078 +    float *d=pcm[j];
  1.2079 +
  1.2080 +    for(i=0;i<n;i++){
  1.2081 +      float wd=w[i]*w[i];
  1.2082 +      float ws=1.-wd;
  1.2083 +      d[i]=d[i]*wd + s[i]*ws;
  1.2084 +    }
  1.2085 +  }
  1.2086 +  /* window from zero */
  1.2087 +  for(;j<ch2;j++){
  1.2088 +    float *d=pcm[j];
  1.2089 +    for(i=0;i<n;i++){
  1.2090 +      float wd=w[i]*w[i];
  1.2091 +      d[i]=d[i]*wd;
  1.2092 +    }
  1.2093 +  }
  1.2094 +
  1.2095 +}
  1.2096 +
  1.2097 +/* make sure vf is INITSET */
  1.2098 +static int _ov_initset(OggVorbis_File *vf){
  1.2099 +  while(1){
  1.2100 +    if(vf->ready_state==INITSET)break;
  1.2101 +    /* suck in another packet */
  1.2102 +    {
  1.2103 +      int ret=_fetch_and_process_packet(vf,NULL,1,0);
  1.2104 +      if(ret<0 && ret!=OV_HOLE)return(ret);
  1.2105 +    }
  1.2106 +  }
  1.2107 +  return 0;
  1.2108 +}
  1.2109 +
  1.2110 +/* make sure vf is INITSET and that we have a primed buffer; if
  1.2111 +   we're crosslapping at a stream section boundary, this also makes
  1.2112 +   sure we're sanity checking against the right stream information */
  1.2113 +static int _ov_initprime(OggVorbis_File *vf){
  1.2114 +  vorbis_dsp_state *vd=&vf->vd;
  1.2115 +  while(1){
  1.2116 +    if(vf->ready_state==INITSET)
  1.2117 +      if(vorbis_synthesis_pcmout(vd,NULL))break;
  1.2118 +
  1.2119 +    /* suck in another packet */
  1.2120 +    {
  1.2121 +      int ret=_fetch_and_process_packet(vf,NULL,1,0);
  1.2122 +      if(ret<0 && ret!=OV_HOLE)return(ret);
  1.2123 +    }
  1.2124 +  }
  1.2125 +  return 0;
  1.2126 +}
  1.2127 +
  1.2128 +/* grab enough data for lapping from vf; this may be in the form of
  1.2129 +   unreturned, already-decoded pcm, remaining PCM we will need to
  1.2130 +   decode, or synthetic postextrapolation from last packets. */
  1.2131 +static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd,
  1.2132 +                       float **lappcm,int lapsize){
  1.2133 +  int lapcount=0,i;
  1.2134 +  float **pcm;
  1.2135 +
  1.2136 +  /* try first to decode the lapping data */
  1.2137 +  while(lapcount<lapsize){
  1.2138 +    int samples=vorbis_synthesis_pcmout(vd,&pcm);
  1.2139 +    if(samples){
  1.2140 +      if(samples>lapsize-lapcount)samples=lapsize-lapcount;
  1.2141 +      for(i=0;i<vi->channels;i++)
  1.2142 +        memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
  1.2143 +      lapcount+=samples;
  1.2144 +      vorbis_synthesis_read(vd,samples);
  1.2145 +    }else{
  1.2146 +    /* suck in another packet */
  1.2147 +      int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */
  1.2148 +      if(ret==OV_EOF)break;
  1.2149 +    }
  1.2150 +  }
  1.2151 +  if(lapcount<lapsize){
  1.2152 +    /* failed to get lapping data from normal decode; pry it from the
  1.2153 +       postextrapolation buffering, or the second half of the MDCT
  1.2154 +       from the last packet */
  1.2155 +    int samples=vorbis_synthesis_lapout(&vf->vd,&pcm);
  1.2156 +    if(samples==0){
  1.2157 +      for(i=0;i<vi->channels;i++)
  1.2158 +        memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount);
  1.2159 +      lapcount=lapsize;
  1.2160 +    }else{
  1.2161 +      if(samples>lapsize-lapcount)samples=lapsize-lapcount;
  1.2162 +      for(i=0;i<vi->channels;i++)
  1.2163 +        memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples);
  1.2164 +      lapcount+=samples;
  1.2165 +    }
  1.2166 +  }
  1.2167 +}
  1.2168 +
  1.2169 +/* this sets up crosslapping of a sample by using trailing data from
  1.2170 +   sample 1 and lapping it into the windowing buffer of sample 2 */
  1.2171 +int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){
  1.2172 +  vorbis_info *vi1,*vi2;
  1.2173 +  float **lappcm;
  1.2174 +  float **pcm;
  1.2175 +  float *w1,*w2;
  1.2176 +  int n1,n2,i,ret,hs1,hs2;
  1.2177 +
  1.2178 +  if(vf1==vf2)return(0); /* degenerate case */
  1.2179 +  if(vf1->ready_state<OPENED)return(OV_EINVAL);
  1.2180 +  if(vf2->ready_state<OPENED)return(OV_EINVAL);
  1.2181 +
  1.2182 +  /* the relevant overlap buffers must be pre-checked and pre-primed
  1.2183 +     before looking at settings in the event that priming would cross
  1.2184 +     a bitstream boundary.  So, do it now */
  1.2185 +
  1.2186 +  ret=_ov_initset(vf1);
  1.2187 +  if(ret)return(ret);
  1.2188 +  ret=_ov_initprime(vf2);
  1.2189 +  if(ret)return(ret);
  1.2190 +
  1.2191 +  vi1=ov_info(vf1,-1);
  1.2192 +  vi2=ov_info(vf2,-1);
  1.2193 +  hs1=ov_halfrate_p(vf1);
  1.2194 +  hs2=ov_halfrate_p(vf2);
  1.2195 +
  1.2196 +  lappcm=alloca(sizeof(*lappcm)*vi1->channels);
  1.2197 +  n1=vorbis_info_blocksize(vi1,0)>>(1+hs1);
  1.2198 +  n2=vorbis_info_blocksize(vi2,0)>>(1+hs2);
  1.2199 +  w1=vorbis_window(&vf1->vd,0);
  1.2200 +  w2=vorbis_window(&vf2->vd,0);
  1.2201 +
  1.2202 +  for(i=0;i<vi1->channels;i++)
  1.2203 +    lappcm[i]=alloca(sizeof(**lappcm)*n1);
  1.2204 +
  1.2205 +  _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1);
  1.2206 +
  1.2207 +  /* have a lapping buffer from vf1; now to splice it into the lapping
  1.2208 +     buffer of vf2 */
  1.2209 +  /* consolidate and expose the buffer. */
  1.2210 +  vorbis_synthesis_lapout(&vf2->vd,&pcm);
  1.2211 +
  1.2212 +#if 0
  1.2213 +  _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0);
  1.2214 +  _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0);
  1.2215 +#endif
  1.2216 +
  1.2217 +  /* splice */
  1.2218 +  _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2);
  1.2219 +
  1.2220 +  /* done */
  1.2221 +  return(0);
  1.2222 +}
  1.2223 +
  1.2224 +static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos,
  1.2225 +                           int (*localseek)(OggVorbis_File *,ogg_int64_t)){
  1.2226 +  vorbis_info *vi;
  1.2227 +  float **lappcm;
  1.2228 +  float **pcm;
  1.2229 +  float *w1,*w2;
  1.2230 +  int n1,n2,ch1,ch2,hs;
  1.2231 +  int i,ret;
  1.2232 +
  1.2233 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.2234 +  ret=_ov_initset(vf);
  1.2235 +  if(ret)return(ret);
  1.2236 +  vi=ov_info(vf,-1);
  1.2237 +  hs=ov_halfrate_p(vf);
  1.2238 +
  1.2239 +  ch1=vi->channels;
  1.2240 +  n1=vorbis_info_blocksize(vi,0)>>(1+hs);
  1.2241 +  w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
  1.2242 +                                   persistent; even if the decode state
  1.2243 +                                   from this link gets dumped, this
  1.2244 +                                   window array continues to exist */
  1.2245 +
  1.2246 +  lappcm=alloca(sizeof(*lappcm)*ch1);
  1.2247 +  for(i=0;i<ch1;i++)
  1.2248 +    lappcm[i]=alloca(sizeof(**lappcm)*n1);
  1.2249 +  _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
  1.2250 +
  1.2251 +  /* have lapping data; seek and prime the buffer */
  1.2252 +  ret=localseek(vf,pos);
  1.2253 +  if(ret)return ret;
  1.2254 +  ret=_ov_initprime(vf);
  1.2255 +  if(ret)return(ret);
  1.2256 +
  1.2257 + /* Guard against cross-link changes; they're perfectly legal */
  1.2258 +  vi=ov_info(vf,-1);
  1.2259 +  ch2=vi->channels;
  1.2260 +  n2=vorbis_info_blocksize(vi,0)>>(1+hs);
  1.2261 +  w2=vorbis_window(&vf->vd,0);
  1.2262 +
  1.2263 +  /* consolidate and expose the buffer. */
  1.2264 +  vorbis_synthesis_lapout(&vf->vd,&pcm);
  1.2265 +
  1.2266 +  /* splice */
  1.2267 +  _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
  1.2268 +
  1.2269 +  /* done */
  1.2270 +  return(0);
  1.2271 +}
  1.2272 +
  1.2273 +int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
  1.2274 +  return _ov_64_seek_lap(vf,pos,ov_raw_seek);
  1.2275 +}
  1.2276 +
  1.2277 +int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){
  1.2278 +  return _ov_64_seek_lap(vf,pos,ov_pcm_seek);
  1.2279 +}
  1.2280 +
  1.2281 +int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){
  1.2282 +  return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page);
  1.2283 +}
  1.2284 +
  1.2285 +static int _ov_d_seek_lap(OggVorbis_File *vf,double pos,
  1.2286 +                           int (*localseek)(OggVorbis_File *,double)){
  1.2287 +  vorbis_info *vi;
  1.2288 +  float **lappcm;
  1.2289 +  float **pcm;
  1.2290 +  float *w1,*w2;
  1.2291 +  int n1,n2,ch1,ch2,hs;
  1.2292 +  int i,ret;
  1.2293 +
  1.2294 +  if(vf->ready_state<OPENED)return(OV_EINVAL);
  1.2295 +  ret=_ov_initset(vf);
  1.2296 +  if(ret)return(ret);
  1.2297 +  vi=ov_info(vf,-1);
  1.2298 +  hs=ov_halfrate_p(vf);
  1.2299 +
  1.2300 +  ch1=vi->channels;
  1.2301 +  n1=vorbis_info_blocksize(vi,0)>>(1+hs);
  1.2302 +  w1=vorbis_window(&vf->vd,0);  /* window arrays from libvorbis are
  1.2303 +                                   persistent; even if the decode state
  1.2304 +                                   from this link gets dumped, this
  1.2305 +                                   window array continues to exist */
  1.2306 +
  1.2307 +  lappcm=alloca(sizeof(*lappcm)*ch1);
  1.2308 +  for(i=0;i<ch1;i++)
  1.2309 +    lappcm[i]=alloca(sizeof(**lappcm)*n1);
  1.2310 +  _ov_getlap(vf,vi,&vf->vd,lappcm,n1);
  1.2311 +
  1.2312 +  /* have lapping data; seek and prime the buffer */
  1.2313 +  ret=localseek(vf,pos);
  1.2314 +  if(ret)return ret;
  1.2315 +  ret=_ov_initprime(vf);
  1.2316 +  if(ret)return(ret);
  1.2317 +
  1.2318 + /* Guard against cross-link changes; they're perfectly legal */
  1.2319 +  vi=ov_info(vf,-1);
  1.2320 +  ch2=vi->channels;
  1.2321 +  n2=vorbis_info_blocksize(vi,0)>>(1+hs);
  1.2322 +  w2=vorbis_window(&vf->vd,0);
  1.2323 +
  1.2324 +  /* consolidate and expose the buffer. */
  1.2325 +  vorbis_synthesis_lapout(&vf->vd,&pcm);
  1.2326 +
  1.2327 +  /* splice */
  1.2328 +  _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2);
  1.2329 +
  1.2330 +  /* done */
  1.2331 +  return(0);
  1.2332 +}
  1.2333 +
  1.2334 +int ov_time_seek_lap(OggVorbis_File *vf,double pos){
  1.2335 +  return _ov_d_seek_lap(vf,pos,ov_time_seek);
  1.2336 +}
  1.2337 +
  1.2338 +int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){
  1.2339 +  return _ov_d_seek_lap(vf,pos,ov_time_seek_page);
  1.2340 +}