annotate src/libvorbis-1.3.3/lib/vorbisfile.c @ 148:b4bfdf10c4b3

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