#include <math.h>
#include "vorbis/codec.h"
+
+/* we don't need or want the static callback symbols here */
+#define OV_EXCLUDE_STATIC_CALLBACKS
#include "vorbis/vorbisfile.h"
#include "os.h"
/* read a little more data from the file/pipe into the ogg_sync framer
*/
-#define CHUNKSIZE 65536
+#define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */
+#define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */
static long _get_data(OggVorbis_File *vf){
errno=0;
if(!(vf->callbacks.read_func))return(-1);
if(vf->datasource){
- char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
- long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
+ char *buffer=ogg_sync_buffer(&vf->oy,READSIZE);
+ long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource);
if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
if(bytes==0 && errno)return(-1);
return(bytes);
ogg_int64_t prefoffset=-1;
ogg_int64_t offset=-1;
- ogg_int64_t ret_serialno;
- ogg_int64_t ret_gran;
+ ogg_int64_t ret_serialno=-1;
+ ogg_int64_t ret_gran=-1;
while(offset==-1){
begin-=CHUNKSIZE;
/* extract packets from page */
while(1){
- /* process a packet if we can. If the machine isn't loaded,
- neither is a page */
+ if(vf->ready_state==STREAMSET){
+ int ret=_make_decode_ready(vf);
+ if(ret<0)return ret;
+ }
+
+ /* process a packet if we can. */
+
if(vf->ready_state==INITSET){
while(1) {
ogg_packet op;
link=0;
}
}
-
- {
- int ret=_make_decode_ready(vf);
- if(ret<0)return ret;
- }
}
/* the buffered page is the data we want, and we're ready for it;
int lastblock=0;
int accblock=0;
int thisblock=0;
- int eosflag=0;
+ int lastflag=0;
+ int firstflag=0;
+ ogg_int64_t pagepos=-1;
ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
thisblock=0;
}else{
- if(eosflag)
+ /* We can't get a guaranteed correct pcm position out of the
+ last page in a stream because it might have a 'short'
+ granpos, which can only be detected in the presence of a
+ preceeding page. However, if the last page is also the first
+ page, the granpos rules of a first page take precedence. Not
+ only that, but for first==last, the EOS page must be treated
+ as if its a normal first page for the stream to open/play. */
+ if(lastflag && !firstflag)
ogg_stream_packetout(&vf->os,NULL);
else
if(lastblock)accblock+=(lastblock+thisblock)>>2;
for(i=0;i<link;i++)
granulepos+=vf->pcmlengths[i*2+1];
vf->pcm_offset=granulepos-accblock;
+ if(vf->pcm_offset<0)vf->pcm_offset=0;
break;
}
lastblock=thisblock;
}
if(!lastblock){
- if(_get_next_page(vf,&og,-1)<0){
+ pagepos=_get_next_page(vf,&og,-1);
+ if(pagepos<0){
vf->pcm_offset=ov_pcm_total(vf,-1);
break;
}
ogg_stream_reset_serialno(&vf->os,serialno);
ogg_stream_reset_serialno(&work_os,serialno);
vf->ready_state=STREAMSET;
-
+ firstflag=(pagepos<=vf->dataoffsets[link]);
}
ogg_stream_pagein(&vf->os,&og);
ogg_stream_pagein(&work_os,&og);
- eosflag=ogg_page_eos(&og);
+ lastflag=ogg_page_eos(&og);
+
}
}
bisect=begin +
(ogg_int64_t)((double)(target-begintime)*(end-begin)/(endtime-begintime))
- CHUNKSIZE;
- if(bisect<=begin)
- bisect=begin+1;
+ if(bisect>begin+CHUNKSIZE){
+ result=_seek_helper(vf,bisect);
+ if(result) goto seek_error;
+ }else{
+ bisect=begin;
+ }
}
- result=_seek_helper(vf,bisect);
- if(result) goto seek_error;
-
while(begin<end){
result=_get_next_page(vf,&og,end-vf->offset);
if(result==OV_EREAD) goto seek_error;