summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <xiphmont@xiph.org>2010-10-23 10:29:11 +0000
committerMonty <xiphmont@xiph.org>2010-10-23 10:29:11 +0000
commita7ebe8070c615b757f6d1f5ad878d3fc81e37125 (patch)
tree7b69d708fadfa333e4182ec1913fe692a0981272
parent06efb98e23b2001aa837a05558b0a3488fed8001 (diff)
downloadlibvorbis-git-a7ebe8070c615b757f6d1f5ad878d3fc81e37125.tar.gz
While reviewing a patch to port Tremor r17541, noticed that the
half-rate decode code in Vorbisfile was never completed past the original 'quick and dirty' feature request. Specifically, it made no attempt to keep the pcm offset tracking consistent in seeks. Complete this code, and add a testing mode to seeking_example.c to torture test seeking in halfrate mode. Also remove requirement that halfrate mode only work with seekable files. svn path=/trunk/vorbis/; revision=17560
-rw-r--r--examples/seeking_example.c44
-rw-r--r--lib/vorbisfile.c61
2 files changed, 70 insertions, 35 deletions
diff --git a/examples/seeking_example.c b/examples/seeking_example.c
index a968a81f..6355359c 100644
--- a/examples/seeking_example.c
+++ b/examples/seeking_example.c
@@ -29,11 +29,13 @@ void _verify(OggVorbis_File *ov,
ogg_int64_t val,ogg_int64_t pcmval,double timeval,
ogg_int64_t pcmlength,
char *bigassbuffer){
+ off_t i;
int j;
long bread;
char buffer[4096];
int dummy;
ogg_int64_t pos;
+ int hs = ov_halfrate_p(ov);
/* verify the raw position, the pcm position and position decode */
if(val!=-1 && ov_raw_tell(ov)<val){
@@ -58,15 +60,24 @@ void _verify(OggVorbis_File *ov,
}
bread=ov_read(ov,buffer,4096,1,1,1,&dummy);
for(j=0;j<bread;j++){
- if(buffer[j]!=bigassbuffer[j+pos*2]){
- fprintf(stderr,"data position after seek doesn't match pcm position\n");
-
+ if(buffer[j]!=bigassbuffer[j+((pos>>hs)*2)]){
+ fprintf(stderr,"data after seek doesn't match declared pcm position %lld\n",pos);
+
+ for(i=0;i<(pcmlength>>hs)*2-bread;i++){
+ for(j=0;j<bread;j++)
+ if(buffer[j] != bigassbuffer[i+j])break;
+ if(j==bread){
+ fprintf(stderr,"data after seek appears to match position %lld\n",(i/2)<<hs);
+ }
+ }
{
FILE *f=fopen("a.m","w");
- for(j=0;j<bread;j++)fprintf(f,"%d\n",(int)buffer[j]);
+ for(j=0;j<bread;j++)fprintf(f,"%d %d\n",j,(int)buffer[j]);
fclose(f);
f=fopen("b.m","w");
- for(j=0;j<bread;j++)fprintf(f,"%d\n",(int)bigassbuffer[j+pos*2]);
+ for(j=-4096;j<bread+4096;j++)
+ if(j+((pos*2)>>hs)>=0 && (j+((pos*2)>>hs))<(pcmlength>>hs)*2)
+ fprintf(f,"%d %d\n",j,(int)bigassbuffer[j+((pos*2)>>hs)]);
fclose(f);
}
@@ -82,6 +93,7 @@ int main(){
double timelength;
char *bigassbuffer;
int dummy;
+ int hs=0;
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */
_setmode( _fileno( stdin ), _O_BINARY );
@@ -94,6 +106,14 @@ int main(){
exit(1);
}
+#if 0 /*enable this code to test seeking with halfrate decode */
+ if(ov_halfrate(&ov,1)){
+ fprintf(stderr,"Sorry; unable to set half-rate decode.\n\n");
+ exit(1);
+ }else
+ hs=1;
+#endif
+
if(ov_seekable(&ov)){
/* to simplify our own lives, we want to assume the whole file is
@@ -112,10 +132,10 @@ int main(){
does what it claimed, decode the entire file into memory */
pcmlength=ov_pcm_total(&ov,-1);
timelength=ov_time_total(&ov,-1);
- bigassbuffer=malloc(pcmlength*2); /* w00t */
+ bigassbuffer=malloc((pcmlength>>hs)*2); /* w00t */
i=0;
- while(i<pcmlength*2){
- int ret=ov_read(&ov,bigassbuffer+i,pcmlength*2-i,1,1,1,&dummy);
+ while(i<(pcmlength>>hs)*2){
+ int ret=ov_read(&ov,bigassbuffer+i,((pcmlength>>hs)*2)-i,1,1,1,&dummy);
if(ret<0){
fprintf(stderr,"Error reading file.\n");
exit(1);
@@ -123,10 +143,10 @@ int main(){
if(ret){
i+=ret;
}else{
- pcmlength=i/2;
+ pcmlength=(i/2)<<hs;
}
fprintf(stderr,"\rloading.... [%ld left] ",
- (long)(pcmlength*2-i));
+ (long)((pcmlength>>hs)*2-i));
}
{
@@ -166,7 +186,7 @@ int main(){
}
}
-
+
fprintf(stderr,"\r");
{
fprintf(stderr,"testing pcm exact seeking to random places in %ld samples....\n",
@@ -180,7 +200,7 @@ int main(){
fprintf(stderr,"seek failed: %d\n",ret);
exit(1);
}
- if(ov_pcm_tell(&ov)!=val){
+ if(ov_pcm_tell(&ov)!=((val>>hs)<<hs)){
fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n",
(long)val,(long)ov_pcm_tell(&ov));
exit(1);
diff --git a/lib/vorbisfile.c b/lib/vorbisfile.c
index c775c505..029226c0 100644
--- a/lib/vorbisfile.c
+++ b/lib/vorbisfile.c
@@ -689,6 +689,8 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
/* process a packet if we can. */
if(vf->ready_state==INITSET){
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
+
while(1) {
ogg_packet op;
ogg_packet *op_ptr=(op_in?op_in:&op);
@@ -716,7 +718,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
if(oldsamples)return(OV_EFAULT);
vorbis_synthesis_blockin(&vf->vd,&vf->vb);
- vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
+ vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
vf->bittrack+=op_ptr->bytes*8;
}
@@ -745,7 +747,7 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
here unless the stream
is very broken */
- samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
+ samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<<hs);
granulepos-=samples;
for(i=0;i<link;i++)
@@ -1022,17 +1024,22 @@ int ov_fopen(const char *path,OggVorbis_File *vf){
int ov_halfrate(OggVorbis_File *vf,int flag){
int i;
if(vf->vi==NULL)return OV_EINVAL;
- if(!vf->seekable)return OV_EINVAL;
- if(vf->ready_state>=STREAMSET)
- _decode_clear(vf); /* clear out stream state; later on libvorbis
- will be able to swap this on the fly, but
- for now dumping the decode machine is needed
- to reinit the MDCT lookups. 1.1 libvorbis
- is planned to be able to switch on the fly */
+ if(vf->ready_state>STREAMSET){
+ /* clear out stream state; dumping the decode machine is needed to
+ reinit the MDCT lookups. */
+ vorbis_dsp_clear(&vf->vd);
+ vorbis_block_clear(&vf->vb);
+ vf->ready_state=STREAMSET;
+ if(vf->pcm_offset>=0){
+ ogg_int64_t pos=vf->pcm_offset;
+ vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */
+ ov_pcm_seek(vf,pos);
+ }
+ }
for(i=0;i<vf->links;i++){
if(vorbis_synthesis_halfrate(vf->vi+i,flag)){
- ov_halfrate(vf,0);
+ if(flag) ov_halfrate(vf,0);
return OV_EINVAL;
}
}
@@ -1657,17 +1664,22 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
vf->samptrack=0.f;
/* discard samples until we reach the desired position. Crossing a
logical bitstream boundary with abandon is OK. */
- while(vf->pcm_offset<pos){
- ogg_int64_t target=pos-vf->pcm_offset;
- long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
-
- if(samples>target)samples=target;
- vorbis_synthesis_read(&vf->vd,samples);
- vf->pcm_offset+=samples;
-
- if(samples<target)
- if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
- vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
+ {
+ /* note that halfrate could be set differently in each link, but
+ vorbisfile encoforces all links are set or unset */
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
+ while(vf->pcm_offset<((pos>>hs)<<hs)){
+ ogg_int64_t target=(pos-vf->pcm_offset)>>hs;
+ long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
+
+ if(samples>target)samples=target;
+ vorbis_synthesis_read(&vf->vd,samples);
+ vf->pcm_offset+=samples<<hs;
+
+ if(samples<target)
+ if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
+ vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
+ }
}
return 0;
}
@@ -1858,6 +1870,7 @@ long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){
int i,j;
int host_endian = host_is_big_endian();
+ int hs;
float **pcm;
long samples;
@@ -1981,7 +1994,8 @@ long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
}
vorbis_synthesis_read(&vf->vd,samples);
- vf->pcm_offset+=samples;
+ hs=vorbis_synthesis_halfrate_p(vf->vi);
+ vf->pcm_offset+=(samples<<hs);
if(bitstream)*bitstream=vf->current_link;
return(samples*bytespersample);
}else{
@@ -2018,10 +2032,11 @@ long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length,
float **pcm;
long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
if(samples){
+ int hs=vorbis_synthesis_halfrate_p(vf->vi);
if(pcm_channels)*pcm_channels=pcm;
if(samples>length)samples=length;
vorbis_synthesis_read(&vf->vd,samples);
- vf->pcm_offset+=samples;
+ vf->pcm_offset+=samples<<hs;
if(bitstream)*bitstream=vf->current_link;
return samples;