dbf-halloween2015
diff libs/vorbis/vorbisfile.c @ 1:c3f5c32cb210
barfed all the libraries in the source tree to make porting easier
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 01 Nov 2015 00:36:56 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/vorbis/vorbisfile.c Sun Nov 01 00:36:56 2015 +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 +}