annotate src/libvorbis-1.3.3/lib/vorbisfile.c @ 22:b07fe9e906dc

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