00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 #include <errno.h>
00022 #include <string.h>
00023 #include <math.h>
00024
00025 #include "ivorbiscodec.h"
00026 #include "ivorbisfile.h"
00027
00028 #include "os.h"
00029 #include "misc.h"
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 static long _get_data(OggVorbis_File *vf){
00063 errno=0;
00064 if(vf->datasource){
00065 unsigned char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE);
00066 long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
00067 if(bytes>0)ogg_sync_wrote(vf->oy,bytes);
00068 if(bytes==0 && errno)return(-1);
00069 return(bytes);
00070 }else
00071 return(0);
00072 }
00073
00074
00075 static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
00076 if(vf->datasource){
00077 (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
00078 vf->offset=offset;
00079 ogg_sync_reset(vf->oy);
00080 }else{
00081
00082 return;
00083 }
00084 }
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
00102 ogg_int64_t boundary){
00103 if(boundary>0)boundary+=vf->offset;
00104 while(1){
00105 long more;
00106
00107 if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
00108 more=ogg_sync_pageseek(vf->oy,og);
00109
00110 if(more<0){
00111
00112 vf->offset-=more;
00113 }else{
00114 if(more==0){
00115
00116 if(!boundary)return(OV_FALSE);
00117 {
00118 long ret=_get_data(vf);
00119 if(ret==0)return(OV_EOF);
00120 if(ret<0)return(OV_EREAD);
00121 }
00122 }else{
00123
00124
00125 ogg_int64_t ret=vf->offset;
00126 vf->offset+=more;
00127 return(ret);
00128
00129 }
00130 }
00131 }
00132 }
00133
00134
00135
00136
00137
00138
00139
00140 static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
00141 ogg_int64_t begin=vf->offset;
00142 ogg_int64_t end=begin;
00143 ogg_int64_t ret;
00144 ogg_int64_t offset=-1;
00145
00146 while(offset==-1){
00147 begin-=CHUNKSIZE;
00148 if(begin<0)
00149 begin=0;
00150 _seek_helper(vf,begin);
00151 while(vf->offset<end){
00152 ret=_get_next_page(vf,og,end-vf->offset);
00153 if(ret==OV_EREAD)return(OV_EREAD);
00154 if(ret<0){
00155 break;
00156 }else{
00157 offset=ret;
00158 }
00159 }
00160 }
00161
00162
00163 _seek_helper(vf,offset);
00164 ret=_get_next_page(vf,og,CHUNKSIZE);
00165 if(ret<0)
00166
00167 return(OV_EFAULT);
00168
00169 return(offset);
00170 }
00171
00172
00173
00174
00175
00176 static int _bisect_forward_serialno(OggVorbis_File *vf,
00177 ogg_int64_t begin,
00178 ogg_int64_t searched,
00179 ogg_int64_t end,
00180 ogg_uint32_t currentno,
00181 long m){
00182 ogg_int64_t endsearched=end;
00183 ogg_int64_t next=end;
00184 ogg_page og={0,0,0,0};
00185 ogg_int64_t ret;
00186
00187
00188
00189 while(searched<endsearched){
00190 ogg_int64_t bisect;
00191
00192 if(endsearched-searched<CHUNKSIZE){
00193 bisect=searched;
00194 }else{
00195 bisect=(searched+endsearched)/2;
00196 }
00197
00198 _seek_helper(vf,bisect);
00199 ret=_get_next_page(vf,&og,-1);
00200 if(ret==OV_EREAD)return(OV_EREAD);
00201 if(ret<0 || ogg_page_serialno(&og)!=currentno){
00202 endsearched=bisect;
00203 if(ret>=0)next=ret;
00204 }else{
00205 searched=ret+og.header_len+og.body_len;
00206 }
00207 ogg_page_release(&og);
00208 }
00209
00210 _seek_helper(vf,next);
00211 ret=_get_next_page(vf,&og,-1);
00212 if(ret==OV_EREAD)return(OV_EREAD);
00213
00214 if(searched>=end || ret<0){
00215 ogg_page_release(&og);
00216 vf->links=m+1;
00217 vf->offsets=(ogg_int64_t*)_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
00218 vf->serialnos=(ogg_uint32_t*)_ogg_malloc(vf->links*sizeof(*vf->serialnos));
00219 vf->offsets[m+1]=searched;
00220 }else{
00221 ret=_bisect_forward_serialno(vf,next,vf->offset,
00222 end,ogg_page_serialno(&og),m+1);
00223 ogg_page_release(&og);
00224 if(ret==OV_EREAD)return(OV_EREAD);
00225 }
00226
00227 vf->offsets[m]=begin;
00228 vf->serialnos[m]=currentno;
00229 return(0);
00230 }
00231
00232
00233
00234
00235
00236 static int _fetch_headers(OggVorbis_File *vf,
00237 vorbis_info *vi,
00238 vorbis_comment *vc,
00239 ogg_uint32_t *serialno,
00240 ogg_page *og_ptr){
00241 ogg_page og={0,0,0,0};
00242 ogg_packet op={0,0,0,0,0,0};
00243 int i,ret;
00244
00245 if(!og_ptr){
00246 ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
00247 if(llret==OV_EREAD)return(OV_EREAD);
00248 if(llret<0)return OV_ENOTVORBIS;
00249 og_ptr=&og;
00250 }
00251
00252 ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));
00253 if(serialno)*serialno=vf->os->serialno;
00254 vf->ready_state=STREAMSET;
00255
00256
00257
00258
00259 vorbis_info_init(vi);
00260 vorbis_comment_init(vc);
00261
00262 i=0;
00263 while(i<3){
00264 ogg_stream_pagein(vf->os,og_ptr);
00265 while(i<3){
00266 int result=ogg_stream_packetout(vf->os,&op);
00267 if(result==0)break;
00268 if(result==-1){
00269 ret=OV_EBADHEADER;
00270 goto bail_header;
00271 }
00272 ret=vorbis_synthesis_headerin(vi,vc,&op);
00273 if(ret){
00274 goto bail_header;
00275 }
00276 i++;
00277 }
00278 if(i<3)
00279 if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
00280 ret=OV_EBADHEADER;
00281 goto bail_header;
00282 }
00283 }
00284
00285 ogg_packet_release(&op);
00286 ogg_page_release(&og);
00287 return 0;
00288
00289 bail_header:
00290 ogg_packet_release(&op);
00291 ogg_page_release(&og);
00292 vorbis_info_clear(vi);
00293 vorbis_comment_clear(vc);
00294 vf->ready_state=OPENED;
00295
00296 return ret;
00297 }
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308 static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){
00309 ogg_page og={0,0,0,0};
00310 int i;
00311 ogg_int64_t ret;
00312
00313 vf->vi=(vorbis_info*)_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
00314 vf->vc=(vorbis_comment*)_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
00315 vf->dataoffsets=(ogg_int64_t*)_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
00316 vf->pcmlengths=(ogg_int64_t*)_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
00317
00318 for(i=0;i<vf->links;i++){
00319 if(i==0){
00320
00321 vf->dataoffsets[i]=dataoffset;
00322 _seek_helper(vf,dataoffset);
00323
00324 }else{
00325
00326
00327
00328 _seek_helper(vf,vf->offsets[i]);
00329 if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){
00330 vf->dataoffsets[i]=-1;
00331 }else{
00332 vf->dataoffsets[i]=vf->offset;
00333 }
00334 }
00335
00336
00337
00338 if(vf->dataoffsets[i]!=-1){
00339 ogg_int64_t accumulated=0,pos;
00340 long lastblock=-1;
00341 int result;
00342
00343 ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);
00344
00345 while(1){
00346 ogg_packet op={0,0,0,0,0,0};
00347
00348 ret=_get_next_page(vf,&og,-1);
00349 if(ret<0)
00350
00351
00352 break;
00353
00354 if(ogg_page_serialno(&og)!=vf->serialnos[i])
00355 break;
00356
00357 pos=ogg_page_granulepos(&og);
00358
00359
00360 ogg_stream_pagein(vf->os,&og);
00361 result=ogg_stream_packetout(vf->os,&op);
00362 while(result){
00363 if(result>0){
00364 long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);
00365 if(lastblock!=-1)
00366 accumulated+=(lastblock+thisblock)>>2;
00367 lastblock=thisblock;
00368 }
00369 result=ogg_stream_packetout(vf->os,&op);
00370 }
00371 ogg_packet_release(&op);
00372
00373 if(pos!=-1){
00374
00375 accumulated= pos-accumulated;
00376 break;
00377 }
00378 }
00379
00380
00381
00382 if(accumulated<0)accumulated=0;
00383
00384 vf->pcmlengths[i*2]=accumulated;
00385 }
00386
00387
00388
00389 {
00390 ogg_int64_t end=vf->offsets[i+1];
00391 _seek_helper(vf,end);
00392
00393 while(1){
00394 ret=_get_prev_page(vf,&og);
00395 if(ret<0){
00396
00397 vorbis_info_clear(vf->vi+i);
00398 vorbis_comment_clear(vf->vc+i);
00399 break;
00400 }
00401 if(ogg_page_granulepos(&og)!=-1){
00402 vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
00403 break;
00404 }
00405 vf->offset=ret;
00406 }
00407 }
00408 }
00409 ogg_page_release(&og);
00410 }
00411
00412 static void _make_decode_ready(OggVorbis_File *vf){
00413 if(vf->ready_state!=STREAMSET)return;
00414 if(vf->seekable){
00415 vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);
00416 }else{
00417 vorbis_synthesis_init(&vf->vd,vf->vi);
00418 }
00419 vorbis_block_init(&vf->vd,&vf->vb);
00420 vf->ready_state=INITSET;
00421 vf->bittrack=0;
00422 vf->samptrack=0;
00423 return;
00424 }
00425
00426 static int _open_seekable2(OggVorbis_File *vf){
00427 ogg_uint32_t serialno=vf->current_serialno;
00428 ogg_uint32_t tempserialno;
00429 ogg_int64_t dataoffset=vf->offset, end;
00430 ogg_page og={0,0,0,0};
00431
00432
00433
00434
00435 (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
00436 vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
00437
00438
00439
00440 end=_get_prev_page(vf,&og);
00441 if(end<0)return(end);
00442
00443
00444 tempserialno=ogg_page_serialno(&og);
00445 ogg_page_release(&og);
00446
00447 if(tempserialno!=serialno){
00448
00449
00450
00451 if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);
00452
00453 }else{
00454
00455
00456 if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);
00457
00458 }
00459
00460
00461 _prefetch_all_headers(vf,dataoffset);
00462 return(ov_raw_seek(vf,0));
00463 }
00464
00465
00466 static void _decode_clear(OggVorbis_File *vf){
00467 vorbis_dsp_clear(&vf->vd);
00468 vorbis_block_clear(&vf->vb);
00469 vf->ready_state=OPENED;
00470 }
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 static int _fetch_and_process_packet(OggVorbis_File *vf,
00484 int readp,
00485 int spanp){
00486 ogg_page og={0,0,0,0};
00487 ogg_packet op={0,0,0,0,0,0};
00488 int ret=0;
00489
00490
00491
00492 while(1){
00493
00494
00495
00496 if(vf->ready_state==INITSET){
00497 while(1) {
00498 int result=ogg_stream_packetout(vf->os,&op);
00499 ogg_int64_t granulepos;
00500
00501 if(result<0){
00502 ret=OV_HOLE;
00503 goto cleanup;
00504 }
00505 if(result>0){
00506
00507 granulepos=op.granulepos;
00508 if(!vorbis_synthesis(&vf->vb,&op,1)){
00509
00510
00511
00512
00513
00514
00515
00516
00517 {
00518 int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
00519
00520
00521 if(oldsamples){
00522 ret=OV_EFAULT;
00523 goto cleanup;
00524 }
00525
00526 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
00527 vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
00528 vf->bittrack+=op.bytes*8;
00529 }
00530
00531
00532 if(granulepos!=-1 && !op.e_o_s){
00533 int link=(vf->seekable?vf->current_link:0);
00534 int i,samples;
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 if(vf->seekable && link>0)
00550 granulepos-=vf->pcmlengths[link*2];
00551 if(granulepos<0)granulepos=0;
00552
00553
00554
00555
00556 samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
00557
00558 granulepos-=samples;
00559 for(i=0;i<link;i++)
00560 granulepos+=vf->pcmlengths[i*2+1];
00561 vf->pcm_offset=granulepos;
00562 }
00563 ret=1;
00564 goto cleanup;
00565 }
00566 }
00567 else
00568 break;
00569 }
00570 }
00571
00572 if(vf->ready_state>=OPENED){
00573 int ret;
00574 if(!readp){
00575
00576 goto cleanup;
00577 }
00578 ret=_get_next_page(vf,&og,-1);
00579 if(ret <0){
00580 ret=OV_EOF;
00581 goto cleanup;
00582 }
00583
00584
00585
00586 vf->bittrack+=og.header_len*8;
00587
00588
00589 if(vf->ready_state==INITSET){
00590 if(vf->current_serialno!=ogg_page_serialno(&og)){
00591 if(!spanp){
00592
00593 goto cleanup;
00594 }
00595
00596 _decode_clear(vf);
00597
00598 if(!vf->seekable){
00599 vorbis_info_clear(vf->vi);
00600 vorbis_comment_clear(vf->vc);
00601 }
00602 }
00603 }
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618 if(vf->ready_state!=INITSET){
00619 int link;
00620
00621 if(vf->ready_state<STREAMSET){
00622 if(vf->seekable){
00623 vf->current_serialno=ogg_page_serialno(&og);
00624
00625
00626
00627
00628 for(link=0;link<vf->links;link++)
00629 if(vf->serialnos[link]==vf->current_serialno)break;
00630 if(link==vf->links){
00631 ret=OV_EBADLINK;
00632
00633 goto cleanup;
00634 }
00635
00636 vf->current_link=link;
00637
00638 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
00639 vf->ready_state=STREAMSET;
00640
00641 }else{
00642
00643
00644
00645 int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
00646 if(ret) goto cleanup;
00647 vf->current_link++;
00648 link=0;
00649 }
00650 }
00651
00652 _make_decode_ready(vf);
00653 }
00654 ogg_stream_pagein(vf->os,&og);
00655 }
00656 cleanup:
00657 ogg_packet_release(&op);
00658 ogg_page_release(&og);
00659 return ret;
00660 }
00661
00662
00663
00664 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
00665 if(f==NULL)return(-1);
00666 return fseek(f,off,whence);
00667 }
00668
00669 static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,
00670 long ibytes, ov_callbacks callbacks){
00671 int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);
00672 int ret;
00673
00674 memset(vf,0,sizeof(*vf));
00675 vf->datasource=f;
00676 vf->callbacks = callbacks;
00677
00678
00679 vf->oy=ogg_sync_create();
00680
00681
00682
00683
00684
00685 if(initial){
00686 unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes);
00687 memcpy(buffer,initial,ibytes);
00688 ogg_sync_wrote(vf->oy,ibytes);
00689 }
00690
00691
00692 if(offsettest!=-1)vf->seekable=1;
00693
00694
00695
00696 vf->links=1;
00697 vf->vi=(vorbis_info*)_ogg_calloc(vf->links,sizeof(*vf->vi));
00698 vf->vc=(vorbis_comment*)_ogg_calloc(vf->links,sizeof(*vf->vc));
00699 vf->os=ogg_stream_create(-1);
00700
00701
00702 if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){
00703 vf->datasource=NULL;
00704 ov_clear(vf);
00705 }else if(vf->ready_state < PARTOPEN)
00706 vf->ready_state=PARTOPEN;
00707 return(ret);
00708 }
00709
00710 static int _ov_open2(OggVorbis_File *vf){
00711 if(vf->ready_state < OPENED)
00712 vf->ready_state=OPENED;
00713 if(vf->seekable){
00714 int ret=_open_seekable2(vf);
00715 if(ret){
00716 vf->datasource=NULL;
00717 ov_clear(vf);
00718 }
00719 return(ret);
00720 }
00721 return 0;
00722 }
00723
00724
00725
00726 int ov_clear(OggVorbis_File *vf){
00727 if(vf){
00728 vorbis_block_clear(&vf->vb);
00729 vorbis_dsp_clear(&vf->vd);
00730 ogg_stream_destroy(vf->os);
00731
00732 vf->os=NULL;
00733
00734 if(vf->vi && vf->links){
00735 int i;
00736 for(i=0;i<vf->links;i++){
00737 vorbis_info_clear(vf->vi+i);
00738 vorbis_comment_clear(vf->vc+i);
00739 }
00740 _ogg_free(vf->vi);
00741 _ogg_free(vf->vc);
00742 }
00743 if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
00744 if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
00745 if(vf->serialnos)_ogg_free(vf->serialnos);
00746 if(vf->offsets)_ogg_free(vf->offsets);
00747 ogg_sync_destroy(vf->oy);
00748
00749 if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);
00750 memset(vf,0,sizeof(*vf));
00751 }
00752 #ifdef DEBUG_LEAKS
00753 _VDBG_dump();
00754 #endif
00755 return(0);
00756 }
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766 int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
00767 ov_callbacks callbacks){
00768 int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
00769 if(ret)return ret;
00770 return _ov_open2(vf);
00771 }
00772
00773 int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
00774 ov_callbacks callbacks = {
00775 (size_t (*)(void *, size_t, size_t, void *)) fread,
00776 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
00777 (int (*)(void *)) fclose,
00778 (long (*)(void *)) ftell
00779 };
00780
00781 return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
00782 }
00783
00784
00785
00786
00787
00788
00789 int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,
00790 ov_callbacks callbacks)
00791 {
00792 return _ov_open1(f,vf,initial,ibytes,callbacks);
00793 }
00794
00795 int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){
00796 ov_callbacks callbacks = {
00797 (size_t (*)(void *, size_t, size_t, void *)) fread,
00798 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
00799 (int (*)(void *)) fclose,
00800 (long (*)(void *)) ftell
00801 };
00802
00803 return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
00804 }
00805
00806 int ov_test_open(OggVorbis_File *vf){
00807 if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
00808 return _ov_open2(vf);
00809 }
00810
00811
00812 long ov_streams(OggVorbis_File *vf){
00813 return vf->links;
00814 }
00815
00816
00817 long ov_seekable(OggVorbis_File *vf){
00818 return vf->seekable;
00819 }
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830 long ov_bitrate(OggVorbis_File *vf,int i){
00831 if(vf->ready_state<OPENED)return(OV_EINVAL);
00832 if(i>=vf->links)return(OV_EINVAL);
00833 if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
00834 if(i<0){
00835 ogg_int64_t bits=0;
00836 int i;
00837 for(i=0;i<vf->links;i++)
00838 bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
00839
00840
00841
00842
00843 return(bits*1000/ov_time_total(vf,-1));
00844 }else{
00845 if(vf->seekable){
00846
00847 return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));
00848 }else{
00849
00850 if(vf->vi[i].bitrate_nominal>0){
00851 return vf->vi[i].bitrate_nominal;
00852 }else{
00853 if(vf->vi[i].bitrate_upper>0){
00854 if(vf->vi[i].bitrate_lower>0){
00855 return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
00856 }else{
00857 return vf->vi[i].bitrate_upper;
00858 }
00859 }
00860 return(OV_FALSE);
00861 }
00862 }
00863 }
00864 }
00865
00866
00867
00868
00869
00870 long ov_bitrate_instant(OggVorbis_File *vf){
00871 int link=(vf->seekable?vf->current_link:0);
00872 long ret;
00873 if(vf->ready_state<OPENED)return(OV_EINVAL);
00874 if(vf->samptrack==0)return(OV_FALSE);
00875 ret=vf->bittrack/vf->samptrack*vf->vi[link].rate;
00876 vf->bittrack=0;
00877 vf->samptrack=0;
00878 return(ret);
00879 }
00880
00881
00882 long ov_serialnumber(OggVorbis_File *vf,int i){
00883 if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
00884 if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
00885 if(i<0){
00886 return(vf->current_serialno);
00887 }else{
00888 return(vf->serialnos[i]);
00889 }
00890 }
00891
00892
00893
00894
00895
00896
00897 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
00898 if(vf->ready_state<OPENED)return(OV_EINVAL);
00899 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
00900 if(i<0){
00901 ogg_int64_t acc=0;
00902 int i;
00903 for(i=0;i<vf->links;i++)
00904 acc+=ov_raw_total(vf,i);
00905 return(acc);
00906 }else{
00907 return(vf->offsets[i+1]-vf->offsets[i]);
00908 }
00909 }
00910
00911
00912
00913
00914
00915
00916 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
00917 if(vf->ready_state<OPENED)return(OV_EINVAL);
00918 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
00919 if(i<0){
00920 ogg_int64_t acc=0;
00921 int i;
00922 for(i=0;i<vf->links;i++)
00923 acc+=ov_pcm_total(vf,i);
00924 return(acc);
00925 }else{
00926 return(vf->pcmlengths[i*2+1]);
00927 }
00928 }
00929
00930
00931
00932
00933
00934
00935 ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
00936 if(vf->ready_state<OPENED)return(OV_EINVAL);
00937 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
00938 if(i<0){
00939 ogg_int64_t acc=0;
00940 int i;
00941 for(i=0;i<vf->links;i++)
00942 acc+=ov_time_total(vf,i);
00943 return(acc);
00944 }else{
00945 return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
00946 }
00947 }
00948
00949
00950
00951
00952
00953
00954
00955
00956 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
00957 ogg_stream_state *work_os=NULL;
00958 ogg_page og={0,0,0,0};
00959 ogg_packet op={0,0,0,0,0,0};
00960
00961 if(vf->ready_state<OPENED)return(OV_EINVAL);
00962 if(!vf->seekable)
00963 return(OV_ENOSEEK);
00964
00965 if(pos<0 || pos>vf->end)return(OV_EINVAL);
00966
00967
00968
00969
00970
00971 vf->pcm_offset=-1;
00972 ogg_stream_reset_serialno(vf->os,
00973 vf->current_serialno);
00974 vorbis_synthesis_restart(&vf->vd);
00975
00976 _seek_helper(vf,pos);
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993 {
00994 int lastblock=0;
00995 int accblock=0;
00996 int thisblock;
00997 int eosflag =0;
00998
00999 work_os=ogg_stream_create(vf->current_serialno);
01000 while(1){
01001 if(vf->ready_state>=STREAMSET){
01002
01003 int result=ogg_stream_packetout(work_os,&op);
01004
01005 if(result>0){
01006
01007 if(vf->vi[vf->current_link].codec_setup){
01008 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
01009 if(thisblock<0){
01010 ogg_stream_packetout(vf->os,NULL);
01011 thisblock=0;
01012 }else{
01013
01014 if(eosflag)
01015 ogg_stream_packetout(vf->os,NULL);
01016 else
01017 if(lastblock)accblock+=(lastblock+thisblock)>>2;
01018 }
01019
01020 if(op.granulepos!=-1){
01021 int i,link=vf->current_link;
01022 ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
01023 if(granulepos<0)granulepos=0;
01024
01025 for(i=0;i<link;i++)
01026 granulepos+=vf->pcmlengths[i*2+1];
01027 vf->pcm_offset=granulepos-accblock;
01028 break;
01029 }
01030 lastblock=thisblock;
01031 continue;
01032 }else
01033 ogg_stream_packetout(vf->os,NULL);
01034 }
01035 }
01036
01037 if(!lastblock){
01038 if(_get_next_page(vf,&og,-1)<0){
01039 vf->pcm_offset=ov_pcm_total(vf,-1);
01040 break;
01041 }
01042 }else{
01043
01044 vf->pcm_offset=-1;
01045 break;
01046 }
01047
01048
01049 if(vf->ready_state>=STREAMSET)
01050 if(vf->current_serialno!=ogg_page_serialno(&og)){
01051 _decode_clear(vf);
01052 ogg_stream_destroy(work_os);
01053 }
01054
01055 if(vf->ready_state<STREAMSET){
01056 int link;
01057
01058 vf->current_serialno=ogg_page_serialno(&og);
01059 for(link=0;link<vf->links;link++)
01060 if(vf->serialnos[link]==vf->current_serialno)break;
01061 if(link==vf->links)
01062 goto seek_error;
01063
01064
01065 vf->current_link=link;
01066
01067 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
01068 ogg_stream_reset_serialno(work_os,vf->current_serialno);
01069 vf->ready_state=STREAMSET;
01070
01071 }
01072
01073 {
01074 ogg_page dup;
01075 ogg_page_dup(&dup,&og);
01076 eosflag=ogg_page_eos(&og);
01077 ogg_stream_pagein(vf->os,&og);
01078 ogg_stream_pagein(work_os,&dup);
01079 }
01080 }
01081 }
01082
01083 ogg_packet_release(&op);
01084 ogg_page_release(&og);
01085 ogg_stream_destroy(work_os);
01086 vf->bittrack=0;
01087 vf->samptrack=0;
01088 return(0);
01089
01090 seek_error:
01091 ogg_packet_release(&op);
01092 ogg_page_release(&og);
01093
01094
01095 vf->pcm_offset=-1;
01096 ogg_stream_destroy(work_os);
01097 _decode_clear(vf);
01098 return OV_EBADLINK;
01099 }
01100
01101
01102
01103
01104
01105
01106
01107 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
01108 int link=-1;
01109 ogg_int64_t result=0;
01110 ogg_int64_t total=ov_pcm_total(vf,-1);
01111 ogg_page og={0,0,0,0};
01112 ogg_packet op={0,0,0,0,0,0};
01113
01114 if(vf->ready_state<OPENED)return(OV_EINVAL);
01115 if(!vf->seekable)return(OV_ENOSEEK);
01116 if(pos<0 || pos>total)return(OV_EINVAL);
01117
01118
01119 for(link=vf->links-1;link>=0;link--){
01120 total-=vf->pcmlengths[link*2+1];
01121 if(pos>=total)break;
01122 }
01123
01124
01125
01126
01127
01128
01129
01130
01131 {
01132 ogg_int64_t end=vf->offsets[link+1];
01133 ogg_int64_t begin=vf->offsets[link];
01134 ogg_int64_t begintime = vf->pcmlengths[link*2];
01135 ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
01136 ogg_int64_t target=pos-total+begintime;
01137 ogg_int64_t best=begin;
01138
01139 while(begin<end){
01140 ogg_int64_t bisect;
01141
01142 if(end-begin<CHUNKSIZE){
01143 bisect=begin;
01144 }else{
01145
01146 bisect=begin +
01147 (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
01148 if(bisect<=begin)
01149 bisect=begin+1;
01150 }
01151
01152 _seek_helper(vf,bisect);
01153
01154 while(begin<end){
01155 result=_get_next_page(vf,&og,end-vf->offset);
01156 if(result==OV_EREAD) goto seek_error;
01157 if(result<0){
01158 if(bisect<=begin+1)
01159 end=begin;
01160 else{
01161 if(bisect==0) goto seek_error;
01162 bisect-=CHUNKSIZE;
01163 if(bisect<=begin)bisect=begin+1;
01164 _seek_helper(vf,bisect);
01165 }
01166 }else{
01167 ogg_int64_t granulepos=ogg_page_granulepos(&og);
01168 if(granulepos==-1)continue;
01169 if(granulepos<target){
01170 best=result;
01171 begin=vf->offset;
01172 begintime=granulepos;
01173
01174 if(target-begintime>44100)break;
01175 bisect=begin;
01176 }else{
01177 if(bisect<=begin+1)
01178 end=begin;
01179 else{
01180 if(end==vf->offset){
01181 end=result;
01182 bisect-=CHUNKSIZE;
01183 if(bisect<=begin)bisect=begin+1;
01184 _seek_helper(vf,bisect);
01185 }else{
01186 end=result;
01187 endtime=granulepos;
01188 break;
01189 }
01190 }
01191 }
01192 }
01193 }
01194 }
01195
01196
01197
01198 {
01199
01200
01201 _seek_helper(vf,best);
01202 vf->pcm_offset=-1;
01203
01204 if(_get_next_page(vf,&og,-1)<0){
01205 ogg_page_release(&og);
01206 return(OV_EOF);
01207 }
01208
01209 if(link!=vf->current_link){
01210
01211 _decode_clear(vf);
01212
01213 vf->current_link=link;
01214 vf->current_serialno=ogg_page_serialno(&og);
01215 vf->ready_state=STREAMSET;
01216
01217 }else{
01218 vorbis_synthesis_restart(&vf->vd);
01219 }
01220
01221 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
01222 ogg_stream_pagein(vf->os,&og);
01223
01224
01225 while(1){
01226 result=ogg_stream_packetpeek(vf->os,&op);
01227 if(result==0){
01228
01229
01230
01231
01232
01233 _seek_helper(vf,best);
01234
01235 while(1){
01236 result=_get_prev_page(vf,&og);
01237 if(result<0) goto seek_error;
01238 if(ogg_page_granulepos(&og)>-1 ||
01239 !ogg_page_continued(&og)){
01240 return ov_raw_seek(vf,result);
01241 }
01242 vf->offset=result;
01243 }
01244 }
01245 if(result<0){
01246 result = OV_EBADPACKET;
01247 goto seek_error;
01248 }
01249 if(op.granulepos!=-1){
01250 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
01251 if(vf->pcm_offset<0)vf->pcm_offset=0;
01252 vf->pcm_offset+=total;
01253 break;
01254 }else
01255 result=ogg_stream_packetout(vf->os,NULL);
01256 }
01257 }
01258 }
01259
01260
01261 if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
01262 result=OV_EFAULT;
01263 goto seek_error;
01264 }
01265 vf->bittrack=0;
01266 vf->samptrack=0;
01267
01268 ogg_page_release(&og);
01269 ogg_packet_release(&op);
01270 return(0);
01271
01272 seek_error:
01273
01274 ogg_page_release(&og);
01275 ogg_packet_release(&op);
01276
01277
01278 vf->pcm_offset=-1;
01279 _decode_clear(vf);
01280 return (int)result;
01281 }
01282
01283
01284
01285
01286 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
01287 ogg_packet op={0,0,0,0,0,0};
01288 ogg_page og={0,0,0,0};
01289 int thisblock,lastblock=0;
01290 int ret=ov_pcm_seek_page(vf,pos);
01291 if(ret<0)return(ret);
01292 _make_decode_ready(vf);
01293
01294
01295
01296
01297 while(1){
01298
01299 int ret=ogg_stream_packetpeek(vf->os,&op);
01300 if(ret>0){
01301 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
01302 if(thisblock<0){
01303 ogg_stream_packetout(vf->os,NULL);
01304 continue;
01305 }
01306 if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
01307
01308 if(vf->pcm_offset+((thisblock+
01309 vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
01310
01311
01312 ogg_stream_packetout(vf->os,NULL);
01313 vorbis_synthesis(&vf->vb,&op,0);
01314
01315
01316 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
01317
01318
01319
01320
01321 if(op.granulepos>-1){
01322 int i;
01323
01324 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
01325 if(vf->pcm_offset<0)vf->pcm_offset=0;
01326 for(i=0;i<vf->current_link;i++)
01327 vf->pcm_offset+=vf->pcmlengths[i*2+1];
01328 }
01329
01330 lastblock=thisblock;
01331
01332 }else{
01333 if(ret<0 && ret!=OV_HOLE)break;
01334
01335
01336 if(_get_next_page(vf,&og,-1)<0)break;
01337 if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
01338
01339 if(vf->ready_state<STREAMSET){
01340 int link;
01341
01342 vf->current_serialno=ogg_page_serialno(&og);
01343 for(link=0;link<vf->links;link++)
01344 if(vf->serialnos[link]==vf->current_serialno)break;
01345 if(link==vf->links){
01346 ogg_page_release(&og);
01347 ogg_packet_release(&op);
01348 return(OV_EBADLINK);
01349 }
01350 vf->current_link=link;
01351
01352 ogg_stream_reset_serialno(vf->os,vf->current_serialno);
01353 vf->ready_state=STREAMSET;
01354 _make_decode_ready(vf);
01355 lastblock=0;
01356 }
01357
01358 ogg_stream_pagein(vf->os,&og);
01359 }
01360 }
01361
01362 vf->bittrack=0;
01363 vf->samptrack=0;
01364
01365
01366 while(vf->pcm_offset<pos){
01367 ogg_int64_t target=pos-vf->pcm_offset;
01368 long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
01369
01370 if(samples>target)samples=target;
01371 vorbis_synthesis_read(&vf->vd,samples);
01372 vf->pcm_offset+=samples;
01373
01374 if(samples<target)
01375 if(_fetch_and_process_packet(vf,1,1)<=0)
01376 vf->pcm_offset=ov_pcm_total(vf,-1);
01377 }
01378
01379 ogg_page_release(&og);
01380 ogg_packet_release(&op);
01381 return 0;
01382 }
01383
01384
01385
01386 int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
01387
01388
01389 int link=-1;
01390 ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
01391 ogg_int64_t time_total=ov_time_total(vf,-1);
01392
01393 if(vf->ready_state<OPENED)return(OV_EINVAL);
01394 if(!vf->seekable)return(OV_ENOSEEK);
01395 if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
01396
01397
01398 for(link=vf->links-1;link>=0;link--){
01399 pcm_total-=vf->pcmlengths[link*2+1];
01400 time_total-=ov_time_total(vf,link);
01401 if(milliseconds>=time_total)break;
01402 }
01403
01404
01405 {
01406 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
01407 return(ov_pcm_seek(vf,target));
01408 }
01409 }
01410
01411
01412
01413 int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){
01414
01415
01416 int link=-1;
01417 ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
01418 ogg_int64_t time_total=ov_time_total(vf,-1);
01419
01420 if(vf->ready_state<OPENED)return(OV_EINVAL);
01421 if(!vf->seekable)return(OV_ENOSEEK);
01422 if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
01423
01424
01425 for(link=vf->links-1;link>=0;link--){
01426 pcm_total-=vf->pcmlengths[link*2+1];
01427 time_total-=ov_time_total(vf,link);
01428 if(milliseconds>=time_total)break;
01429 }
01430
01431
01432 {
01433 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
01434 return(ov_pcm_seek_page(vf,target));
01435 }
01436 }
01437
01438
01439
01440 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
01441 if(vf->ready_state<OPENED)return(OV_EINVAL);
01442 return(vf->offset);
01443 }
01444
01445
01446 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
01447 if(vf->ready_state<OPENED)return(OV_EINVAL);
01448 return(vf->pcm_offset);
01449 }
01450
01451
01452 ogg_int64_t ov_time_tell(OggVorbis_File *vf){
01453 int link=0;
01454 ogg_int64_t pcm_total=0;
01455 ogg_int64_t time_total=0;
01456
01457 if(vf->ready_state<OPENED)return(OV_EINVAL);
01458 if(vf->seekable){
01459 pcm_total=ov_pcm_total(vf,-1);
01460 time_total=ov_time_total(vf,-1);
01461
01462
01463 for(link=vf->links-1;link>=0;link--){
01464 pcm_total-=vf->pcmlengths[link*2+1];
01465 time_total-=ov_time_total(vf,link);
01466 if(vf->pcm_offset>=pcm_total)break;
01467 }
01468 }
01469
01470 return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
01471 }
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481 vorbis_info *ov_info(OggVorbis_File *vf,int link){
01482 if(vf->seekable){
01483 if(link<0)
01484 if(vf->ready_state>=STREAMSET)
01485 return vf->vi+vf->current_link;
01486 else
01487 return vf->vi;
01488 else
01489 if(link>=vf->links)
01490 return NULL;
01491 else
01492 return vf->vi+link;
01493 }else{
01494 return vf->vi;
01495 }
01496 }
01497
01498
01499 vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
01500 if(vf->seekable){
01501 if(link<0)
01502 if(vf->ready_state>=STREAMSET)
01503 return vf->vc+vf->current_link;
01504 else
01505 return vf->vc;
01506 else
01507 if(link>=vf->links)
01508 return NULL;
01509 else
01510 return vf->vc+link;
01511 }else{
01512 return vf->vc;
01513 }
01514 }
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543 long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){
01544 int i,j;
01545
01546 ogg_int32_t **pcm;
01547 long samples;
01548
01549 if(vf->ready_state<OPENED)return(OV_EINVAL);
01550
01551 while(1){
01552 if(vf->ready_state==INITSET){
01553 samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
01554 if(samples)break;
01555 }
01556
01557
01558 {
01559 int ret=_fetch_and_process_packet(vf,1,1);
01560 if(ret==OV_EOF)
01561 return(0);
01562 if(ret<=0)
01563 return(ret);
01564 }
01565
01566 }
01567
01568 if(samples>0){
01569
01570
01571
01572 long channels=ov_info(vf,-1)->channels;
01573
01574 if(channels==1){
01575 if(samples>(bytes_req/2))
01576 samples=bytes_req/2;
01577 }else{
01578 if(samples>(bytes_req/4))
01579 samples=bytes_req/4;
01580 }
01581
01582 for(i=0;i<channels;i++) {
01583 ogg_int32_t *src=pcm[i];
01584 short *dest=((short *)buffer)+i;
01585 for(j=0;j<samples;j++) {
01586 *dest=CLIP_TO_15(src[j]>>9);
01587 dest+=channels;
01588 }
01589 }
01590
01591 vorbis_synthesis_read(&vf->vd,samples);
01592 vf->pcm_offset+=samples;
01593 if(bitstream)*bitstream=vf->current_link;
01594 return(samples*2*channels);
01595 }else{
01596 return(samples);
01597 }
01598 }