/********************************************************************1* *2* THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *3* *4* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *5* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *6* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *7* *8* THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *9* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *10* *11********************************************************************1213function: stdio-based convenience library for opening/seeking/decoding14last mod: $Id: vorbisfile.c,v 1.6 2003/03/30 23:40:56 xiphmont Exp $1516********************************************************************/1718#include <stdlib.h>19#include <stdio.h>20#include <errno.h>21#include <string.h>22#include <math.h>2324#include "ivorbiscodec.h"25#include "ivorbisfile.h"2627#include "misc.h"2829/* A 'chained bitstream' is a Vorbis bitstream that contains more than30one logical bitstream arranged end to end (the only form of Ogg31multiplexing allowed in a Vorbis bitstream; grouping [parallel32multiplexing] is not allowed in Vorbis) */3334/* A Vorbis file can be played beginning to end (streamed) without35worrying ahead of time about chaining (see decoder_example.c). If36we have the whole file, however, and want random access37(seeking/scrubbing) or desire to know the total length/time of a38file, we need to account for the possibility of chaining. */3940/* We can handle things a number of ways; we can determine the entire41bitstream structure right off the bat, or find pieces on demand.42This example determines and caches structure for the entire43bitstream, but builds a virtual decoder on the fly when moving44between links in the chain. */4546/* There are also different ways to implement seeking. Enough47information exists in an Ogg bitstream to seek to48sample-granularity positions in the output. Or, one can seek by49picking some portion of the stream roughly in the desired area if50we only want coarse navigation through the stream. */5152/*************************************************************************53* Many, many internal helpers. The intention is not to be confusing;54* rampant duplication and monolithic function implementation would be55* harder to understand anyway. The high level functions are last. Begin56* grokking near the end of the file */575859/* read a little more data from the file/pipe into the ogg_sync framer */60static long _get_data(OggVorbis_File *vf){61errno=0;62if(vf->datasource){63unsigned char *buffer=ogg_sync_bufferin(vf->oy,CHUNKSIZE);64long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);65if(bytes>0)ogg_sync_wrote(vf->oy,bytes);6667#ifndef GEKKO68else if(bytes==0 && errno )69#else70// Not sure what is up with this... appears that EOVERFLOW is set whenever71// we read to the end of the file...72// original patch by raz0red for Mednafen-Wii73else if(bytes==0 && errno && errno != EOVERFLOW )74#endif75{76return(-1);77}78return(bytes);79}else80return(0);81}8283/* save a tiny smidge of verbosity to make the code more readable */84static void _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){85if(vf->datasource){86(vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);87vf->offset=offset;88ogg_sync_reset(vf->oy);89}else{90/* shouldn't happen unless someone writes a broken callback */91return;92}93}9495/* The read/seek functions track absolute position within the stream */9697/* from the head of the stream, get the next page. boundary specifies98if the function is allowed to fetch more data from the stream (and99how much) or only use internally buffered data.100101boundary: -1) unbounded search1020) read no additional data; use cached only103n) search for a new page beginning for n bytes104105return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)106n) found a page at absolute offset n107108produces a refcounted page */109110static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,111ogg_int64_t boundary){112if(boundary>0)boundary+=vf->offset;113while(1){114long more;115116if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);117more=ogg_sync_pageseek(vf->oy,og);118119if(more<0){120/* skipped n bytes */121vf->offset-=more;122}else{123if(more==0){124/* send more paramedics */125if(!boundary)return(OV_FALSE);126{127long ret=_get_data(vf);128if(ret==0)return(OV_EOF);129if(ret<0)return(OV_EREAD);130}131}else{132/* got a page. Return the offset at the page beginning,133advance the internal offset past the page end */134ogg_int64_t ret=vf->offset;135vf->offset+=more;136return(ret);137138}139}140}141}142143/* find the latest page beginning before the current stream cursor144position. Much dirtier than the above as Ogg doesn't have any145backward search linkage. no 'readp' as it will certainly have to146read. */147/* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */148149static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){150ogg_int64_t begin=vf->offset;151ogg_int64_t end=begin;152ogg_int64_t ret;153ogg_int64_t offset=-1;154155while(offset==-1){156begin-=CHUNKSIZE;157if(begin<0)158begin=0;159_seek_helper(vf,begin);160while(vf->offset<end){161ret=_get_next_page(vf,og,end-vf->offset);162if(ret==OV_EREAD)return(OV_EREAD);163if(ret<0){164break;165}else{166offset=ret;167}168}169}170171/* we have the offset. Actually snork and hold the page now */172_seek_helper(vf,offset);173ret=_get_next_page(vf,og,CHUNKSIZE);174if(ret<0)175/* this shouldn't be possible */176return(OV_EFAULT);177178return(offset);179}180181/* finds each bitstream link one at a time using a bisection search182(has to begin by knowing the offset of the lb's initial page).183Recurses for each link so it can alloc the link storage after184finding them all, then unroll and fill the cache at the same time */185static int _bisect_forward_serialno(OggVorbis_File *vf,186ogg_int64_t begin,187ogg_int64_t searched,188ogg_int64_t end,189ogg_uint32_t currentno,190long m){191ogg_int64_t endsearched=end;192ogg_int64_t next=end;193ogg_page og={0,0,0,0};194ogg_int64_t ret;195196/* the below guards against garbage seperating the last and197first pages of two links. */198while(searched<endsearched){199ogg_int64_t bisect;200201if(endsearched-searched<CHUNKSIZE){202bisect=searched;203}else{204bisect=(searched+endsearched)/2;205}206207_seek_helper(vf,bisect);208ret=_get_next_page(vf,&og,-1);209if(ret==OV_EREAD)return(OV_EREAD);210if(ret<0 || ogg_page_serialno(&og)!=currentno){211endsearched=bisect;212if(ret>=0)next=ret;213}else{214searched=ret+og.header_len+og.body_len;215}216ogg_page_release(&og);217}218219_seek_helper(vf,next);220ret=_get_next_page(vf,&og,-1);221if(ret==OV_EREAD)return(OV_EREAD);222223if(searched>=end || ret<0){224ogg_page_release(&og);225vf->links=m+1;226vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));227vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));228vf->offsets[m+1]=searched;229}else{230ret=_bisect_forward_serialno(vf,next,vf->offset,231end,ogg_page_serialno(&og),m+1);232ogg_page_release(&og);233if(ret==OV_EREAD)return(OV_EREAD);234}235236vf->offsets[m]=begin;237vf->serialnos[m]=currentno;238return(0);239}240241/* uses the local ogg_stream storage in vf; this is important for242non-streaming input sources */243/* consumes the page that's passed in (if any) */244245static int _fetch_headers(OggVorbis_File *vf,246vorbis_info *vi,247vorbis_comment *vc,248ogg_uint32_t *serialno,249ogg_page *og_ptr){250ogg_page og={0,0,0,0};251ogg_packet op={0,0,0,0,0,0};252int i,ret;253254if(!og_ptr){255ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);256if(llret==OV_EREAD)return(OV_EREAD);257if(llret<0)return OV_ENOTVORBIS;258og_ptr=&og;259}260261ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr));262if(serialno)*serialno=vf->os->serialno;263vf->ready_state=STREAMSET;264265/* extract the initial header from the first page and verify that the266Ogg bitstream is in fact Vorbis data */267268vorbis_info_init(vi);269vorbis_comment_init(vc);270271i=0;272while(i<3){273ogg_stream_pagein(vf->os,og_ptr);274while(i<3){275int result=ogg_stream_packetout(vf->os,&op);276if(result==0)break;277if(result==-1){278ret=OV_EBADHEADER;279goto bail_header;280}281if((ret=vorbis_synthesis_headerin(vi,vc,&op))){282goto bail_header;283}284i++;285}286if(i<3)287if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){288ret=OV_EBADHEADER;289goto bail_header;290}291}292293ogg_packet_release(&op);294ogg_page_release(&og);295return 0;296297bail_header:298ogg_packet_release(&op);299ogg_page_release(&og);300vorbis_info_clear(vi);301vorbis_comment_clear(vc);302vf->ready_state=OPENED;303304return ret;305}306307/* last step of the OggVorbis_File initialization; get all the308vorbis_info structs and PCM positions. Only called by the seekable309initialization (local stream storage is hacked slightly; pay310attention to how that's done) */311312/* this is void and does not propogate errors up because we want to be313able to open and use damaged bitstreams as well as we can. Just314watch out for missing information for links in the OggVorbis_File315struct */316static void _prefetch_all_headers(OggVorbis_File *vf, ogg_int64_t dataoffset){317ogg_page og={0,0,0,0};318int i;319ogg_int64_t ret;320321vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));322vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));323vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));324vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));325326for(i=0;i<vf->links;i++){327if(i==0){328/* we already grabbed the initial header earlier. Just set the offset */329vf->dataoffsets[i]=dataoffset;330_seek_helper(vf,dataoffset);331332}else{333334/* seek to the location of the initial header */335336_seek_helper(vf,vf->offsets[i]);337if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)<0){338vf->dataoffsets[i]=-1;339}else{340vf->dataoffsets[i]=vf->offset;341}342}343344/* fetch beginning PCM offset */345346if(vf->dataoffsets[i]!=-1){347ogg_int64_t accumulated=0,pos;348long lastblock=-1;349int result;350351ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);352353while(1){354ogg_packet op={0,0,0,0,0,0};355356ret=_get_next_page(vf,&og,-1);357if(ret<0)358/* this should not be possible unless the file is359truncated/mangled */360break;361362if(ogg_page_serialno(&og)!=vf->serialnos[i])363break;364365pos=ogg_page_granulepos(&og);366367/* count blocksizes of all frames in the page */368ogg_stream_pagein(vf->os,&og);369while((result=ogg_stream_packetout(vf->os,&op))){370if(result>0){ /* ignore holes */371long thisblock=vorbis_packet_blocksize(vf->vi+i,&op);372if(lastblock!=-1)373accumulated+=(lastblock+thisblock)>>2;374lastblock=thisblock;375}376}377ogg_packet_release(&op);378379if(pos!=-1){380/* pcm offset of last packet on the first audio page */381accumulated= pos-accumulated;382break;383}384}385386/* less than zero? This is a stream with samples trimmed off387the beginning, a normal occurrence; set the offset to zero */388if(accumulated<0)accumulated=0;389390vf->pcmlengths[i*2]=accumulated;391}392393/* get the PCM length of this link. To do this,394get the last page of the stream */395{396ogg_int64_t end=vf->offsets[i+1];397_seek_helper(vf,end);398399while(1){400ret=_get_prev_page(vf,&og);401if(ret<0){402/* this should not be possible */403vorbis_info_clear(vf->vi+i);404vorbis_comment_clear(vf->vc+i);405break;406}407if(ogg_page_granulepos(&og)!=-1){408vf->pcmlengths[i*2+1]=ogg_page_granulepos(&og)-vf->pcmlengths[i*2];409break;410}411vf->offset=ret;412}413}414}415ogg_page_release(&og);416}417418static void _make_decode_ready(OggVorbis_File *vf){419if(vf->ready_state!=STREAMSET)return;420if(vf->seekable){421vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);422}else{423vorbis_synthesis_init(&vf->vd,vf->vi);424}425vorbis_block_init(&vf->vd,&vf->vb);426vf->ready_state=INITSET;427vf->bittrack=0;428vf->samptrack=0;429return;430}431432static int _open_seekable2(OggVorbis_File *vf){433ogg_uint32_t serialno=vf->current_serialno;434ogg_uint32_t tempserialno;435ogg_int64_t dataoffset=vf->offset, end;436ogg_page og={0,0,0,0};437438/* we're partially open and have a first link header state in439storage in vf */440/* we can seek, so set out learning all about this file */441(vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);442vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);443444/* We get the offset for the last page of the physical bitstream.445Most OggVorbis files will contain a single logical bitstream */446end=_get_prev_page(vf,&og);447if(end<0)return(end);448449/* more than one logical bitstream? */450tempserialno=ogg_page_serialno(&og);451ogg_page_release(&og);452453if(tempserialno!=serialno){454455/* Chained bitstream. Bisect-search each logical bitstream456section. Do so based on serial number only */457if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD);458459}else{460461/* Only one logical bitstream */462if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD);463464}465466/* the initial header memory is referenced by vf after; don't free it */467_prefetch_all_headers(vf,dataoffset);468return(ov_raw_seek(vf,0));469}470471/* clear out the current logical bitstream decoder */472static void _decode_clear(OggVorbis_File *vf){473vorbis_dsp_clear(&vf->vd);474vorbis_block_clear(&vf->vb);475vf->ready_state=OPENED;476}477478/* fetch and process a packet. Handles the case where we're at a479bitstream boundary and dumps the decoding machine. If the decoding480machine is unloaded, it loads it. It also keeps pcm_offset up to481date (seek and read both use this. seek uses a special hack with482readp).483484return: <0) error, OV_HOLE (lost packet) or OV_EOF4850) need more data (only if readp==0)4861) got a packet487*/488489static int _fetch_and_process_packet(OggVorbis_File *vf,490int readp,491int spanp){492ogg_page og={0,0,0,0};493ogg_packet op={0,0,0,0,0,0};494int ret=0;495496/* handle one packet. Try to fetch it from current stream state */497/* extract packets from page */498while(1){499500/* process a packet if we can. If the machine isn't loaded,501neither is a page */502if(vf->ready_state==INITSET){503while(1) {504int result=ogg_stream_packetout(vf->os,&op);505ogg_int64_t granulepos;506507if(result<0){508ret=OV_HOLE; /* hole in the data. */509goto cleanup;510}511if(result>0){512/* got a packet. process it */513granulepos=op.granulepos;514if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy515header handling. The516header packets aren't517audio, so if/when we518submit them,519vorbis_synthesis will520reject them */521522/* suck in the synthesis data and track bitrate */523{524int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);525/* for proper use of libvorbis within libvorbisfile,526oldsamples will always be zero. */527if(oldsamples){528ret=OV_EFAULT;529goto cleanup;530}531532vorbis_synthesis_blockin(&vf->vd,&vf->vb);533vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;534vf->bittrack+=op.bytes*8;535}536537/* update the pcm offset. */538if(granulepos!=-1 && !op.e_o_s){539int link=(vf->seekable?vf->current_link:0);540int i,samples;541542/* this packet has a pcm_offset on it (the last packet543completed on a page carries the offset) After processing544(above), we know the pcm position of the *last* sample545ready to be returned. Find the offset of the *first*546547As an aside, this trick is inaccurate if we begin548reading anew right at the last page; the end-of-stream549granulepos declares the last frame in the stream, and the550last packet of the last page may be a partial frame.551So, we need a previous granulepos from an in-sequence page552to have a reference point. Thus the !op.e_o_s clause553above */554555if(vf->seekable && link>0)556granulepos-=vf->pcmlengths[link*2];557if(granulepos<0)granulepos=0; /* actually, this558shouldn't be possible559here unless the stream560is very broken */561562samples=vorbis_synthesis_pcmout(&vf->vd,NULL);563564granulepos-=samples;565for(i=0;i<link;i++)566granulepos+=vf->pcmlengths[i*2+1];567vf->pcm_offset=granulepos;568}569ret=1;570goto cleanup;571}572}573else574break;575}576}577578if(vf->ready_state>=OPENED){579int ret;580if(!readp){581ret=0;582goto cleanup;583}584if((ret=_get_next_page(vf,&og,-1))<0){585ret=OV_EOF; /* eof. leave unitialized */586goto cleanup;587}588589/* bitrate tracking; add the header's bytes here, the body bytes590are done by packet above */591vf->bittrack+=og.header_len*8;592593/* has our decoding just traversed a bitstream boundary? */594if(vf->ready_state==INITSET){595if(vf->current_serialno!=ogg_page_serialno(&og)){596if(!spanp){597ret=OV_EOF;598goto cleanup;599}600601_decode_clear(vf);602603if(!vf->seekable){604vorbis_info_clear(vf->vi);605vorbis_comment_clear(vf->vc);606}607}608}609}610611/* Do we need to load a new machine before submitting the page? */612/* This is different in the seekable and non-seekable cases.613614In the seekable case, we already have all the header615information loaded and cached; we just initialize the machine616with it and continue on our merry way.617618In the non-seekable (streaming) case, we'll only be at a619boundary if we just left the previous logical bitstream and620we're now nominally at the header of the next bitstream621*/622623if(vf->ready_state!=INITSET){624int link;625626if(vf->ready_state<STREAMSET){627if(vf->seekable){628vf->current_serialno=ogg_page_serialno(&og);629630/* match the serialno to bitstream section. We use this rather than631offset positions to avoid problems near logical bitstream632boundaries */633for(link=0;link<vf->links;link++)634if(vf->serialnos[link]==vf->current_serialno)break;635if(link==vf->links){636ret=OV_EBADLINK; /* sign of a bogus stream. error out,637leave machine uninitialized */638goto cleanup;639}640641vf->current_link=link;642643ogg_stream_reset_serialno(vf->os,vf->current_serialno);644vf->ready_state=STREAMSET;645646}else{647/* we're streaming */648/* fetch the three header packets, build the info struct */649650int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);651if(ret) goto cleanup;652vf->current_link++;653link=0;654}655}656657_make_decode_ready(vf);658}659ogg_stream_pagein(vf->os,&og);660}661cleanup:662ogg_packet_release(&op);663ogg_page_release(&og);664return ret;665}666667/* if, eg, 64 bit stdio is configured by default, this will build with668fseek64 */669static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){670if(f==NULL)return(-1);671return fseek(f,off,whence);672}673674static int _ov_open1(void *f,OggVorbis_File *vf,char *initial,675long ibytes, ov_callbacks callbacks){676int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1);677int ret;678679memset(vf,0,sizeof(*vf));680vf->datasource=f;681vf->callbacks = callbacks;682683/* init the framing state */684vf->oy=ogg_sync_create();685686/* perhaps some data was previously read into a buffer for testing687against other stream types. Allow initialization from this688previously read data (as we may be reading from a non-seekable689stream) */690if(initial){691unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes);692memcpy(buffer,initial,ibytes);693ogg_sync_wrote(vf->oy,ibytes);694}695696/* can we seek? Stevens suggests the seek test was portable */697if(offsettest!=-1)vf->seekable=1;698699/* No seeking yet; Set up a 'single' (current) logical bitstream700entry for partial open */701vf->links=1;702vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));703vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));704vf->os=ogg_stream_create(-1); /* fill in the serialno later */705706/* Try to fetch the headers, maintaining all the storage */707if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){708vf->datasource=NULL;709ov_clear(vf);710}else if(vf->ready_state < PARTOPEN)711vf->ready_state=PARTOPEN;712return(ret);713}714715static int _ov_open2(OggVorbis_File *vf){716if(vf->ready_state < OPENED)717vf->ready_state=OPENED;718if(vf->seekable){719int ret=_open_seekable2(vf);720if(ret){721vf->datasource=NULL;722ov_clear(vf);723}724return(ret);725}726return 0;727}728729730/* clear out the OggVorbis_File struct */731int ov_clear(OggVorbis_File *vf){732if(vf){733vorbis_block_clear(&vf->vb);734vorbis_dsp_clear(&vf->vd);735ogg_stream_destroy(vf->os);736737if(vf->vi && vf->links){738int i;739for(i=0;i<vf->links;i++){740vorbis_info_clear(vf->vi+i);741vorbis_comment_clear(vf->vc+i);742}743_ogg_free(vf->vi);744_ogg_free(vf->vc);745}746if(vf->dataoffsets)_ogg_free(vf->dataoffsets);747if(vf->pcmlengths)_ogg_free(vf->pcmlengths);748if(vf->serialnos)_ogg_free(vf->serialnos);749if(vf->offsets)_ogg_free(vf->offsets);750ogg_sync_destroy(vf->oy);751752if(vf->datasource)(vf->callbacks.close_func)(vf->datasource);753memset(vf,0,sizeof(*vf));754}755#ifdef DEBUG_LEAKS756_VDBG_dump();757#endif758return(0);759}760761/* inspects the OggVorbis file and finds/documents all the logical762bitstreams contained in it. Tries to be tolerant of logical763bitstream sections that are truncated/woogie.764765return: -1) error7660) OK767*/768769int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,770ov_callbacks callbacks){771int ret=_ov_open1(f,vf,initial,ibytes,callbacks);772if(ret)return ret;773return _ov_open2(vf);774}775776int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){777ov_callbacks callbacks = {778(size_t (*)(void *, size_t, size_t, void *)) fread,779(int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,780(int (*)(void *)) fclose,781(long (*)(void *)) ftell782};783784return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);785}786787/* Only partially open the vorbis file; test for Vorbisness, and load788the headers for the first chain. Do not seek (although test for789seekability). Use ov_test_open to finish opening the file, else790ov_clear to close/free it. Same return codes as open. */791792int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes,793ov_callbacks callbacks)794{795return _ov_open1(f,vf,initial,ibytes,callbacks);796}797798int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){799ov_callbacks callbacks = {800(size_t (*)(void *, size_t, size_t, void *)) fread,801(int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,802(int (*)(void *)) fclose,803(long (*)(void *)) ftell804};805806return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);807}808809int ov_test_open(OggVorbis_File *vf){810if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);811return _ov_open2(vf);812}813814/* How many logical bitstreams in this physical bitstream? */815long ov_streams(OggVorbis_File *vf){816return vf->links;817}818819/* Is the FILE * associated with vf seekable? */820long ov_seekable(OggVorbis_File *vf){821return vf->seekable;822}823824/* returns the bitrate for a given logical bitstream or the entire825physical bitstream. If the file is open for random access, it will826find the *actual* average bitrate. If the file is streaming, it827returns the nominal bitrate (if set) else the average of the828upper/lower bounds (if set) else -1 (unset).829830If you want the actual bitrate field settings, get them from the831vorbis_info structs */832833long ov_bitrate(OggVorbis_File *vf,int i){834if(vf->ready_state<OPENED)return(OV_EINVAL);835if(i>=vf->links)return(OV_EINVAL);836if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));837if(i<0){838ogg_int64_t bits=0;839int i;840for(i=0;i<vf->links;i++)841bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;842/* This once read: return(rint(bits/ov_time_total(vf,-1)));843* gcc 3.x on x86 miscompiled this at optimisation level 2 and above,844* so this is slightly transformed to make it work.845*/846return(bits*1000/ov_time_total(vf,-1));847}else{848if(vf->seekable){849/* return the actual bitrate */850return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));851}else{852/* return nominal if set */853if(vf->vi[i].bitrate_nominal>0){854return vf->vi[i].bitrate_nominal;855}else{856if(vf->vi[i].bitrate_upper>0){857if(vf->vi[i].bitrate_lower>0){858return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;859}else{860return vf->vi[i].bitrate_upper;861}862}863return(OV_FALSE);864}865}866}867}868869/* returns the actual bitrate since last call. returns -1 if no870additional data to offer since last call (or at beginning of stream),871EINVAL if stream is only partially open872*/873long ov_bitrate_instant(OggVorbis_File *vf){874int link=(vf->seekable?vf->current_link:0);875long ret;876if(vf->ready_state<OPENED)return(OV_EINVAL);877if(vf->samptrack==0)return(OV_FALSE);878ret=vf->bittrack/vf->samptrack*vf->vi[link].rate;879vf->bittrack=0;880vf->samptrack=0;881return(ret);882}883884/* Guess */885long ov_serialnumber(OggVorbis_File *vf,int i){886if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));887if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));888if(i<0){889return(vf->current_serialno);890}else{891return(vf->serialnos[i]);892}893}894895/* returns: total raw (compressed) length of content if i==-1896raw (compressed) length of that logical bitstream for i==0 to n897OV_EINVAL if the stream is not seekable (we can't know the length)898or if stream is only partially open899*/900ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){901if(vf->ready_state<OPENED)return(OV_EINVAL);902if(!vf->seekable || i>=vf->links)return(OV_EINVAL);903if(i<0){904ogg_int64_t acc=0;905int i;906for(i=0;i<vf->links;i++)907acc+=ov_raw_total(vf,i);908return(acc);909}else{910return(vf->offsets[i+1]-vf->offsets[i]);911}912}913914/* returns: total PCM length (samples) of content if i==-1 PCM length915(samples) of that logical bitstream for i==0 to n916OV_EINVAL if the stream is not seekable (we can't know the917length) or only partially open918*/919ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){920if(vf->ready_state<OPENED)return(OV_EINVAL);921if(!vf->seekable || i>=vf->links)return(OV_EINVAL);922if(i<0){923ogg_int64_t acc=0;924int i;925for(i=0;i<vf->links;i++)926acc+=ov_pcm_total(vf,i);927return(acc);928}else{929return(vf->pcmlengths[i*2+1]);930}931}932933/* returns: total milliseconds of content if i==-1934milliseconds in that logical bitstream for i==0 to n935OV_EINVAL if the stream is not seekable (we can't know the936length) or only partially open937*/938ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){939if(vf->ready_state<OPENED)return(OV_EINVAL);940if(!vf->seekable || i>=vf->links)return(OV_EINVAL);941if(i<0){942ogg_int64_t acc=0;943int i;944for(i=0;i<vf->links;i++)945acc+=ov_time_total(vf,i);946return(acc);947}else{948return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);949}950}951952/* seek to an offset relative to the *compressed* data. This also953scans packets to update the PCM cursor. It will cross a logical954bitstream boundary, but only if it can't get any packets out of the955tail of the bitstream we seek to (so no surprises).956957returns zero on success, nonzero on failure */958959int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){960ogg_stream_state *work_os=NULL;961ogg_page og={0,0,0,0};962ogg_packet op={0,0,0,0,0,0};963964if(vf->ready_state<OPENED)return(OV_EINVAL);965if(!vf->seekable)966return(OV_ENOSEEK); /* don't dump machine if we can't seek */967968if(pos<0 || pos>vf->end)return(OV_EINVAL);969970/* don't yet clear out decoding machine (if it's initialized), in971the case we're in the same link. Restart the decode lapping, and972let _fetch_and_process_packet deal with a potential bitstream973boundary */974vf->pcm_offset=-1;975ogg_stream_reset_serialno(vf->os,976vf->current_serialno); /* must set serialno */977vorbis_synthesis_restart(&vf->vd);978979_seek_helper(vf,pos);980981/* we need to make sure the pcm_offset is set, but we don't want to982advance the raw cursor past good packets just to get to the first983with a granulepos. That's not equivalent behavior to beginning984decoding as immediately after the seek position as possible.985986So, a hack. We use two stream states; a local scratch state and987the shared vf->os stream state. We use the local state to988scan, and the shared state as a buffer for later decode.989990Unfortuantely, on the last page we still advance to last packet991because the granulepos on the last page is not necessarily on a992packet boundary, and we need to make sure the granpos is993correct.994*/995996{997int lastblock=0;998int accblock=0;999int thisblock;1000int eosflag=0;10011002work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */1003while(1){1004if(vf->ready_state>=STREAMSET){1005/* snarf/scan a packet if we can */1006int result=ogg_stream_packetout(work_os,&op);10071008if(result>0){10091010if(vf->vi[vf->current_link].codec_setup){1011thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);1012if(thisblock<0){1013ogg_stream_packetout(vf->os,NULL);1014thisblock=0;1015}else{10161017if(eosflag)1018ogg_stream_packetout(vf->os,NULL);1019else1020if(lastblock)accblock+=(lastblock+thisblock)>>2;1021}10221023if(op.granulepos!=-1){1024int i,link=vf->current_link;1025ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];1026if(granulepos<0)granulepos=0;10271028for(i=0;i<link;i++)1029granulepos+=vf->pcmlengths[i*2+1];1030vf->pcm_offset=granulepos-accblock;1031break;1032}1033lastblock=thisblock;1034continue;1035}else1036ogg_stream_packetout(vf->os,NULL);1037}1038}10391040if(!lastblock){1041if(_get_next_page(vf,&og,-1)<0){1042vf->pcm_offset=ov_pcm_total(vf,-1);1043break;1044}1045}else{1046/* huh? Bogus stream with packets but no granulepos */1047vf->pcm_offset=-1;1048break;1049}10501051/* has our decoding just traversed a bitstream boundary? */1052if(vf->ready_state>=STREAMSET)1053if(vf->current_serialno!=ogg_page_serialno(&og)){1054_decode_clear(vf); /* clear out stream state */1055ogg_stream_destroy(work_os);1056}10571058if(vf->ready_state<STREAMSET){1059int link;10601061vf->current_serialno=ogg_page_serialno(&og);1062for(link=0;link<vf->links;link++)1063if(vf->serialnos[link]==vf->current_serialno)break;1064if(link==vf->links)1065goto seek_error; /* sign of a bogus stream. error out,1066leave machine uninitialized */10671068vf->current_link=link;10691070ogg_stream_reset_serialno(vf->os,vf->current_serialno);1071ogg_stream_reset_serialno(work_os,vf->current_serialno);1072vf->ready_state=STREAMSET;10731074}10751076{1077ogg_page dup;1078ogg_page_dup(&dup,&og);1079eosflag=ogg_page_eos(&og);1080ogg_stream_pagein(vf->os,&og);1081ogg_stream_pagein(work_os,&dup);1082}1083}1084}10851086ogg_packet_release(&op);1087ogg_page_release(&og);1088ogg_stream_destroy(work_os);1089vf->bittrack=0;1090vf->samptrack=0;1091return(0);10921093seek_error:1094ogg_packet_release(&op);1095ogg_page_release(&og);10961097/* dump the machine so we're in a known state */1098vf->pcm_offset=-1;1099ogg_stream_destroy(work_os);1100_decode_clear(vf);1101return OV_EBADLINK;1102}11031104/* Page granularity seek (faster than sample granularity because we1105don't do the last bit of decode to find a specific sample).11061107Seek to the last [granule marked] page preceeding the specified pos1108location, such that decoding past the returned point will quickly1109arrive at the requested position. */1110int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){1111int link=-1;1112ogg_int64_t result=0;1113ogg_int64_t total=ov_pcm_total(vf,-1);1114ogg_page og={0,0,0,0};1115ogg_packet op={0,0,0,0,0,0};11161117if(vf->ready_state<OPENED)return(OV_EINVAL);1118if(!vf->seekable)return(OV_ENOSEEK);1119if(pos<0 || pos>total)return(OV_EINVAL);11201121/* which bitstream section does this pcm offset occur in? */1122for(link=vf->links-1;link>=0;link--){1123total-=vf->pcmlengths[link*2+1];1124if(pos>=total)break;1125}11261127/* search within the logical bitstream for the page with the highest1128pcm_pos preceeding (or equal to) pos. There is a danger here;1129missing pages or incorrect frame number information in the1130bitstream could make our task impossible. Account for that (it1131would be an error condition) */11321133/* new search algorithm by HB (Nicholas Vinen) */1134{1135ogg_int64_t end=vf->offsets[link+1];1136ogg_int64_t begin=vf->offsets[link];1137ogg_int64_t begintime = vf->pcmlengths[link*2];1138ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;1139ogg_int64_t target=pos-total+begintime;1140ogg_int64_t best=begin;11411142while(begin<end){1143ogg_int64_t bisect;11441145if(end-begin<CHUNKSIZE){1146bisect=begin;1147}else{1148/* take a (pretty decent) guess. */1149bisect=begin +1150(target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;1151if(bisect<=begin)1152bisect=begin+1;1153}11541155_seek_helper(vf,bisect);11561157while(begin<end){1158result=_get_next_page(vf,&og,end-vf->offset);1159if(result==OV_EREAD) goto seek_error;1160if(result<0){1161if(bisect<=begin+1)1162end=begin; /* found it */1163else{1164if(bisect==0) goto seek_error;1165bisect-=CHUNKSIZE;1166if(bisect<=begin)bisect=begin+1;1167_seek_helper(vf,bisect);1168}1169}else{1170ogg_int64_t granulepos=ogg_page_granulepos(&og);1171if(granulepos==-1)continue;1172if(granulepos<target){1173best=result; /* raw offset of packet with granulepos */1174begin=vf->offset; /* raw offset of next page */1175begintime=granulepos;11761177if(target-begintime>44100)break;1178bisect=begin; /* *not* begin + 1 */1179}else{1180if(bisect<=begin+1)1181end=begin; /* found it */1182else{1183if(end==vf->offset){ /* we're pretty close - we'd be stuck in */1184end=result;1185bisect-=CHUNKSIZE; /* an endless loop otherwise. */1186if(bisect<=begin)bisect=begin+1;1187_seek_helper(vf,bisect);1188}else{1189end=result;1190endtime=granulepos;1191break;1192}1193}1194}1195}1196}1197}11981199/* found our page. seek to it, update pcm offset. Easier case than1200raw_seek, don't keep packets preceeding granulepos. */1201{12021203/* seek */1204_seek_helper(vf,best);1205vf->pcm_offset=-1;12061207if(_get_next_page(vf,&og,-1)<0){1208ogg_page_release(&og);1209return(OV_EOF); /* shouldn't happen */1210}12111212if(link!=vf->current_link){1213/* Different link; dump entire decode machine */1214_decode_clear(vf);12151216vf->current_link=link;1217vf->current_serialno=ogg_page_serialno(&og);1218vf->ready_state=STREAMSET;12191220}else{1221vorbis_synthesis_restart(&vf->vd);1222}12231224ogg_stream_reset_serialno(vf->os,vf->current_serialno);1225ogg_stream_pagein(vf->os,&og);12261227/* pull out all but last packet; the one with granulepos */1228while(1){1229result=ogg_stream_packetpeek(vf->os,&op);1230if(result==0){1231/* !!! the packet finishing this page originated on a1232preceeding page. Keep fetching previous pages until we1233get one with a granulepos or without the 'continued' flag1234set. Then just use raw_seek for simplicity. */12351236_seek_helper(vf,best);12371238while(1){1239result=_get_prev_page(vf,&og);1240if(result<0) goto seek_error;1241if(ogg_page_granulepos(&og)>-1 ||1242!ogg_page_continued(&og)){1243return ov_raw_seek(vf,result);1244}1245vf->offset=result;1246}1247}1248if(result<0){1249result = OV_EBADPACKET;1250goto seek_error;1251}1252if(op.granulepos!=-1){1253vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];1254if(vf->pcm_offset<0)vf->pcm_offset=0;1255vf->pcm_offset+=total;1256break;1257}else1258result=ogg_stream_packetout(vf->os,NULL);1259}1260}1261}12621263/* verify result */1264if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){1265result=OV_EFAULT;1266goto seek_error;1267}1268vf->bittrack=0;1269vf->samptrack=0;12701271ogg_page_release(&og);1272ogg_packet_release(&op);1273return(0);12741275seek_error:12761277ogg_page_release(&og);1278ogg_packet_release(&op);12791280/* dump machine so we're in a known state */1281vf->pcm_offset=-1;1282_decode_clear(vf);1283return (int)result;1284}12851286/* seek to a sample offset relative to the decompressed pcm stream1287returns zero on success, nonzero on failure */12881289int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){1290ogg_packet op={0,0,0,0,0,0};1291ogg_page og={0,0,0,0};1292int thisblock,lastblock=0;1293int ret=ov_pcm_seek_page(vf,pos);1294if(ret<0)return(ret);1295_make_decode_ready(vf);12961297/* discard leading packets we don't need for the lapping of the1298position we want; don't decode them */12991300while(1){13011302int ret=ogg_stream_packetpeek(vf->os,&op);1303if(ret>0){1304thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);1305if(thisblock<0){1306ogg_stream_packetout(vf->os,NULL);1307continue; /* non audio packet */1308}1309if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;13101311if(vf->pcm_offset+((thisblock+1312vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;13131314/* remove the packet from packet queue and track its granulepos */1315ogg_stream_packetout(vf->os,NULL);1316vorbis_synthesis(&vf->vb,&op,0); /* set up a vb with1317only tracking, no1318pcm_decode */1319vorbis_synthesis_blockin(&vf->vd,&vf->vb);13201321/* end of logical stream case is hard, especially with exact1322length positioning. */13231324if(op.granulepos>-1){1325int i;1326/* always believe the stream markers */1327vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];1328if(vf->pcm_offset<0)vf->pcm_offset=0;1329for(i=0;i<vf->current_link;i++)1330vf->pcm_offset+=vf->pcmlengths[i*2+1];1331}13321333lastblock=thisblock;13341335}else{1336if(ret<0 && ret!=OV_HOLE)break;13371338/* suck in a new page */1339if(_get_next_page(vf,&og,-1)<0)break;1340if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);13411342if(vf->ready_state<STREAMSET){1343int link;13441345vf->current_serialno=ogg_page_serialno(&og);1346for(link=0;link<vf->links;link++)1347if(vf->serialnos[link]==vf->current_serialno)break;1348if(link==vf->links){1349ogg_page_release(&og);1350ogg_packet_release(&op);1351return(OV_EBADLINK);1352}1353vf->current_link=link;13541355ogg_stream_reset_serialno(vf->os,vf->current_serialno);1356vf->ready_state=STREAMSET;1357_make_decode_ready(vf);1358lastblock=0;1359}13601361ogg_stream_pagein(vf->os,&og);1362}1363}13641365vf->bittrack=0;1366vf->samptrack=0;1367/* discard samples until we reach the desired position. Crossing a1368logical bitstream boundary with abandon is OK. */1369while(vf->pcm_offset<pos){1370ogg_int64_t target=pos-vf->pcm_offset;1371long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);13721373if(samples>target)samples=target;1374vorbis_synthesis_read(&vf->vd,samples);1375vf->pcm_offset+=samples;13761377if(samples<target)1378if(_fetch_and_process_packet(vf,1,1)<=0)1379vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */1380}13811382ogg_page_release(&og);1383ogg_packet_release(&op);1384return 0;1385}13861387/* seek to a playback time relative to the decompressed pcm stream1388returns zero on success, nonzero on failure */1389int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){1390/* translate time to PCM position and call ov_pcm_seek */13911392int link=-1;1393ogg_int64_t pcm_total=ov_pcm_total(vf,-1);1394ogg_int64_t time_total=ov_time_total(vf,-1);13951396if(vf->ready_state<OPENED)return(OV_EINVAL);1397if(!vf->seekable)return(OV_ENOSEEK);1398if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);13991400/* which bitstream section does this time offset occur in? */1401for(link=vf->links-1;link>=0;link--){1402pcm_total-=vf->pcmlengths[link*2+1];1403time_total-=ov_time_total(vf,link);1404if(milliseconds>=time_total)break;1405}14061407/* enough information to convert time offset to pcm offset */1408{1409ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;1410return(ov_pcm_seek(vf,target));1411}1412}14131414/* page-granularity version of ov_time_seek1415returns zero on success, nonzero on failure */1416int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){1417/* translate time to PCM position and call ov_pcm_seek */14181419int link=-1;1420ogg_int64_t pcm_total=ov_pcm_total(vf,-1);1421ogg_int64_t time_total=ov_time_total(vf,-1);14221423if(vf->ready_state<OPENED)return(OV_EINVAL);1424if(!vf->seekable)return(OV_ENOSEEK);1425if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);14261427/* which bitstream section does this time offset occur in? */1428for(link=vf->links-1;link>=0;link--){1429pcm_total-=vf->pcmlengths[link*2+1];1430time_total-=ov_time_total(vf,link);1431if(milliseconds>=time_total)break;1432}14331434/* enough information to convert time offset to pcm offset */1435{1436ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;1437return(ov_pcm_seek_page(vf,target));1438}1439}14401441/* tell the current stream offset cursor. Note that seek followed by1442tell will likely not give the set offset due to caching */1443ogg_int64_t ov_raw_tell(OggVorbis_File *vf){1444if(vf->ready_state<OPENED)return(OV_EINVAL);1445return(vf->offset);1446}14471448/* return PCM offset (sample) of next PCM sample to be read */1449ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){1450if(vf->ready_state<OPENED)return(OV_EINVAL);1451return(vf->pcm_offset);1452}14531454/* return time offset (milliseconds) of next PCM sample to be read */1455ogg_int64_t ov_time_tell(OggVorbis_File *vf){1456int link=0;1457ogg_int64_t pcm_total=0;1458ogg_int64_t time_total=0;14591460if(vf->ready_state<OPENED)return(OV_EINVAL);1461if(vf->seekable){1462pcm_total=ov_pcm_total(vf,-1);1463time_total=ov_time_total(vf,-1);14641465/* which bitstream section does this time offset occur in? */1466for(link=vf->links-1;link>=0;link--){1467pcm_total-=vf->pcmlengths[link*2+1];1468time_total-=ov_time_total(vf,link);1469if(vf->pcm_offset>=pcm_total)break;1470}1471}14721473return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);1474}14751476/* link: -1) return the vorbis_info struct for the bitstream section1477currently being decoded14780-n) to request information for a specific bitstream section14791480In the case of a non-seekable bitstream, any call returns the1481current bitstream. NULL in the case that the machine is not1482initialized */14831484vorbis_info *ov_info(OggVorbis_File *vf,int link){1485if(vf->seekable){1486if(link<0)1487if(vf->ready_state>=STREAMSET)1488return vf->vi+vf->current_link;1489else1490return vf->vi;1491else1492if(link>=vf->links)1493return NULL;1494else1495return vf->vi+link;1496}else{1497return vf->vi;1498}1499}15001501/* grr, strong typing, grr, no templates/inheritence, grr */1502vorbis_comment *ov_comment(OggVorbis_File *vf,int link){1503if(vf->seekable){1504if(link<0)1505if(vf->ready_state>=STREAMSET)1506return vf->vc+vf->current_link;1507else1508return vf->vc;1509else1510if(link>=vf->links)1511return NULL;1512else1513return vf->vc+link;1514}else{1515return vf->vc;1516}1517}15181519/* up to this point, everything could more or less hide the multiple1520logical bitstream nature of chaining from the toplevel application1521if the toplevel application didn't particularly care. However, at1522the point that we actually read audio back, the multiple-section1523nature must surface: Multiple bitstream sections do not necessarily1524have to have the same number of channels or sampling rate.15251526ov_read returns the sequential logical bitstream number currently1527being decoded along with the PCM data in order that the toplevel1528application can take action on channel/sample rate changes. This1529number will be incremented even for streamed (non-seekable) streams1530(for seekable streams, it represents the actual logical bitstream1531index within the physical bitstream. Note that the accessor1532functions above are aware of this dichotomy).15331534input values: buffer) a buffer to hold packed PCM data for return1535length) the byte length requested to be placed into buffer15361537return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)15380) EOF1539n) number of bytes of PCM actually returned. The1540below works on a packet-by-packet basis, so the1541return length is not related to the 'length' passed1542in, just guaranteed to fit.15431544*section) set to the logical bitstream number */15451546long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){1547int i,j;15481549ogg_int32_t **pcm;1550long samples;15511552if(vf->ready_state<OPENED)return(OV_EINVAL);15531554while(1){1555if(vf->ready_state==INITSET){1556samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);1557if(samples)break;1558}15591560/* suck in another packet */1561{1562int ret=_fetch_and_process_packet(vf,1,1);1563if(ret==OV_EOF)1564return(0);1565if(ret<=0)1566return(ret);1567}15681569}15701571if(samples>0){15721573/* yay! proceed to pack data into the byte buffer */15741575long channels=ov_info(vf,-1)->channels;15761577if(samples>(bytes_req/(2*channels)))1578samples=bytes_req/(2*channels);15791580for(i=0;i<channels;i++) { /* It's faster in this order */1581ogg_int32_t *src=pcm[i];1582short *dest=((short *)buffer)+i;1583for(j=0;j<samples;j++) {1584*dest=CLIP_TO_15(src[j]>>9);1585dest+=channels;1586}1587}15881589vorbis_synthesis_read(&vf->vd,samples);1590vf->pcm_offset+=samples;1591if(bitstream)*bitstream=vf->current_link;1592return(samples*2*channels);1593}else{1594return(samples);1595}1596}159715981599