********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id: vorbisfile.c,v 1.28 2000/08/30 06:09:21 xiphmont Exp $
+ last mod: $Id: vorbisfile.c,v 1.29 2000/10/12 03:12:54 xiphmont Exp $
********************************************************************/
/* uses the local ogg_stream storage in vf; this is important for
non-streaming input sources */
static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
- long *serialno){
+ long *serialno,ogg_page *og_ptr){
ogg_page og;
ogg_packet op;
int i,ret;
-
- ret=_get_next_page(vf,&og,CHUNKSIZE);
- if(ret==-1){
- fprintf(stderr,"Did not find initial header for bitstream.\n");
- return -1;
- }
- if(serialno)*serialno=ogg_page_serialno(&og);
- ogg_stream_init(&vf->os,ogg_page_serialno(&og));
+ if(!og_ptr){
+ ret=_get_next_page(vf,&og,CHUNKSIZE);
+ if(ret==-1){
+ fprintf(stderr,"Did not find initial header for bitstream.\n");
+ return -1;
+ }
+ og_ptr=&og;
+ }
+
+ if(serialno)*serialno=ogg_page_serialno(og_ptr);
+ ogg_stream_init(&vf->os,ogg_page_serialno(og_ptr));
/* extract the initial header from the first page and verify that the
Ogg bitstream is in fact Vorbis data */
i=0;
while(i<3){
- ogg_stream_pagein(&vf->os,&og);
+ ogg_stream_pagein(&vf->os,og_ptr);
while(i<3){
int result=ogg_stream_packetout(&vf->os,&op);
if(result==0)break;
i++;
}
if(i<3)
- if(_get_next_page(vf,&og,1)<0){
+ if(_get_next_page(vf,og_ptr,1)<0){
fprintf(stderr,"Missing header in logical bitstream.\n");
goto bail_header;
}
/* seek to the location of the initial header */
_seek_helper(vf,vf->offsets[i]);
- if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL)==-1){
+ if(_fetch_headers(vf,vf->vi+i,vf->vc+i,NULL,NULL)==-1){
fprintf(stderr,"Error opening logical bitstream #%d.\n\n",i+1);
vf->dataoffsets[i]=-1;
}else{
vorbis_comment_clear(vf->vc+i);
break;
}
- if(ogg_page_frameno(&og)!=-1){
+ if(ogg_page_granulepos(&og)!=-1){
vf->serialnos[i]=ogg_page_serialno(&og);
- vf->pcmlengths[i]=ogg_page_frameno(&og);
+ vf->pcmlengths[i]=ogg_page_granulepos(&og);
break;
}
}
static int _make_decode_ready(OggVorbis_File *vf){
if(vf->decode_ready)exit(1);
- vorbis_synthesis_init(&vf->vd,vf->vi);
+ if(vf->seekable){
+ vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link);
+ }else{
+ vorbis_synthesis_init(&vf->vd,vf->vi);
+ }
vorbis_block_init(&vf->vd,&vf->vb);
vf->decode_ready=1;
return(0);
ogg_page og;
/* is this even vorbis...? */
- ret=_fetch_headers(vf,&initial_i,&initial_c,&serialno);
+ ret=_fetch_headers(vf,&initial_i,&initial_c,&serialno,NULL);
dataoffset=vf->offset;
ogg_stream_clear(&vf->os);
if(ret==-1)return(-1);
vf->vc=calloc(vf->links,sizeof(vorbis_info));
/* Try to fetch the headers, maintaining all the storage */
- if(_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno)==-1)return(-1);
+ if(_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL)==-1)return(-1);
_make_decode_ready(vf);
return 0;
if(vf->decode_ready){
ogg_packet op;
int result=ogg_stream_packetout(&vf->os,&op);
- ogg_int64_t frameno;
+ ogg_int64_t granulepos;
/* if(result==-1)return(-1); hole in the data. For now, swallow
and go. We'll need to add a real
error code in a bit. */
if(result>0){
/* got a packet. process it */
- frameno=op.frameno;
+ granulepos=op.granulepos;
if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy
header handling. The
header packets aren't
}
/* update the pcm offset. */
- if(frameno!=-1 && !op.e_o_s){
+ if(granulepos!=-1 && !op.e_o_s){
int link=(vf->seekable?vf->current_link:0);
int i,samples;
As an aside, this trick is inaccurate if we begin
reading anew right at the last page; the end-of-stream
- frameno declares the last frame in the stream, and the
+ granulepos declares the last frame in the stream, and the
last packet of the last page may be a partial frame.
- So, we need a previous frameno from an in-sequence page
+ So, we need a previous granulepos from an in-sequence page
to have a reference point. Thus the !op.e_o_s clause
above */
samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
- frameno-=samples;
+ granulepos-=samples;
for(i=0;i<link;i++)
- frameno+=vf->pcmlengths[i];
- vf->pcm_offset=frameno;
+ granulepos+=vf->pcmlengths[i];
+ vf->pcm_offset=granulepos;
}
return(1);
}
/* we're streaming */
/* fetch the three header packets, build the info struct */
- _fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno);
+ _fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og);
vf->current_link++;
link=0;
}
/* we need to make sure the pcm_offset is set. We use the
_fetch_packet helper to process one packet with readp set, then
call it until it returns '0' with readp not set (the last packet
- from a page has the 'frameno' field set, and that's how the
+ from a page has the 'granulepos' field set, and that's how the
helper updates the offset */
switch(_process_packet(vf,1)){
if(ret==-1){
end=bisect;
}else{
- ogg_int64_t frameno=ogg_page_frameno(&og);
- if(frameno<target){
- best=ret; /* raw offset of packet with frameno */
+ ogg_int64_t granulepos=ogg_page_granulepos(&og);
+ if(granulepos<target){
+ best=ret; /* raw offset of packet with granulepos */
begin=vf->offset; /* raw offset of next packet */
}else{
end=bisect;
/* discard samples until we reach the desired position. Crossing a
logical bitstream boundary with abandon is OK. */
while(vf->pcm_offset<pos){
- double **pcm;
+ float **pcm;
long target=pos-vf->pcm_offset;
long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
while(1){
if(vf->decode_ready){
- double **pcm;
+ float **pcm;
long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
if(samples){
/* yay! proceed to pack data into the byte buffer */
if(host_endian==bigendianp){
if(sgned){
for(i=0;i<channels;i++) { /* It's faster in this order */
- double *src=pcm[i];
+ float *src=pcm[i];
short *dest=((short *)buffer)+i;
for(j=0;j<samples;j++) {
val=(int)(src[j]*32768. + 0.5);
}
}else{
for(i=0;i<channels;i++) {
- double *src=pcm[i];
+ float *src=pcm[i];
short *dest=((short *)buffer)+i;
for(j=0;j<samples;j++) {
val=(int)(src[j]*32768. + 0.5);