📄 vorbisfile.c
字号:
ogg_page_release(&og);
return(OV_EOF); /* shouldn't happen */
}
if(link!=vf->current_link){
/* Different link; dump entire decode machine */
_decode_clear(vf);
vf->current_link=link;
vf->current_serialno=ogg_page_serialno(&og);
vf->ready_state=STREAMSET;
}else{
vorbis_synthesis_restart(&vf->vd);
}
ogg_stream_reset_serialno(vf->os,vf->current_serialno);
ogg_stream_pagein(vf->os,&og);
/* pull out all but last packet; the one with granulepos */
while(1){
result=ogg_stream_packetpeek(vf->os,&op);
if(result==0){
/* !!! the packet finishing this page originated on a
preceeding page. Keep fetching previous pages until we
get one with a granulepos or without the 'continued' flag
set. Then just use raw_seek for simplicity. */
_seek_helper(vf,best);
while(1){
result=_get_prev_page(vf,&og);
if(result<0) goto seek_error;
if(ogg_page_granulepos(&og)>-1 ||
!ogg_page_continued(&og)){
return ov_raw_seek(vf,result);
}
vf->offset=result;
}
}
if(result<0){
result = OV_EBADPACKET;
goto seek_error;
}
if(op.granulepos!=-1){
vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
if(vf->pcm_offset<0)vf->pcm_offset=0;
vf->pcm_offset+=total;
break;
}else
result=ogg_stream_packetout(vf->os,NULL);
}
}
}
/* verify result */
if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
result=OV_EFAULT;
goto seek_error;
}
vf->bittrack=0;
vf->samptrack=0;
ogg_page_release(&og);
ogg_packet_release(&op);
return(0);
seek_error:
ogg_page_release(&og);
ogg_packet_release(&op);
/* dump machine so we're in a known state */
vf->pcm_offset=-1;
_decode_clear(vf);
return (int)result;
}
/* seek to a sample offset relative to the decompressed pcm stream
returns zero on success, nonzero on failure */
EXPORTED int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
ogg_packet op={0,0,0,0,0,0};
ogg_page og={0,0,0,0};
int thisblock,lastblock=0;
int ret=ov_pcm_seek_page(vf,pos);
if(ret<0)return(ret);
_make_decode_ready(vf);
/* discard leading packets we don't need for the lapping of the
position we want; don't decode them */
while(1){
int ret=ogg_stream_packetpeek(vf->os,&op);
if(ret>0){
thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
if(thisblock<0){
ogg_stream_packetout(vf->os,NULL);
continue; /* non audio packet */
}
if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
if(vf->pcm_offset+((thisblock+
vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
/* remove the packet from packet queue and track its granulepos */
ogg_stream_packetout(vf->os,NULL);
vorbis_synthesis(&vf->vb,&op,0); /* set up a vb with
only tracking, no
pcm_decode */
vorbis_synthesis_blockin(&vf->vd,&vf->vb);
/* end of logical stream case is hard, especially with exact
length positioning. */
if(op.granulepos>-1){
int i;
/* always believe the stream markers */
vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
if(vf->pcm_offset<0)vf->pcm_offset=0;
for(i=0;i<vf->current_link;i++)
vf->pcm_offset+=vf->pcmlengths[i*2+1];
}
lastblock=thisblock;
}else{
if(ret<0 && ret!=OV_HOLE)break;
/* suck in a new page */
if(_get_next_page(vf,&og,-1)<0)break;
if(vf->current_serialno!=ogg_page_serialno(&og))_decode_clear(vf);
if(vf->ready_state<STREAMSET){
int link;
vf->current_serialno=ogg_page_serialno(&og);
for(link=0;link<vf->links;link++)
if(vf->serialnos[link]==vf->current_serialno)break;
if(link==vf->links){
ogg_page_release(&og);
ogg_packet_release(&op);
return(OV_EBADLINK);
}
vf->current_link=link;
ogg_stream_reset_serialno(vf->os,vf->current_serialno);
vf->ready_state=STREAMSET;
_make_decode_ready(vf);
lastblock=0;
}
ogg_stream_pagein(vf->os,&og);
}
}
vf->bittrack=0;
vf->samptrack=0;
/* 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= (long) target;
vorbis_synthesis_read(&vf->vd,samples);
vf->pcm_offset+=samples;
if(samples<target)
if(_fetch_and_process_packet(vf,1,1)<=0)
vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
}
ogg_page_release(&og);
ogg_packet_release(&op);
return 0;
}
/* seek to a playback time relative to the decompressed pcm stream
returns zero on success, nonzero on failure */
EXPORTED int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
/* translate time to PCM position and call ov_pcm_seek */
int link=-1;
ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
ogg_int64_t time_total=ov_time_total(vf,-1);
if(vf->ready_state<OPENED)return(OV_EINVAL);
if(!vf->seekable)return(OV_ENOSEEK);
if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
/* which bitstream section does this time offset occur in? */
for(link=vf->links-1;link>=0;link--){
pcm_total-=vf->pcmlengths[link*2+1];
time_total-=ov_time_total(vf,link);
if(milliseconds>=time_total)break;
}
/* enough information to convert time offset to pcm offset */
{
ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
return(ov_pcm_seek(vf,target));
}
}
/* page-granularity version of ov_time_seek
returns zero on success, nonzero on failure */
int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){
/* translate time to PCM position and call ov_pcm_seek */
int link=-1;
ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
ogg_int64_t time_total=ov_time_total(vf,-1);
if(vf->ready_state<OPENED)return(OV_EINVAL);
if(!vf->seekable)return(OV_ENOSEEK);
if(milliseconds<0 || milliseconds>time_total)return(OV_EINVAL);
/* which bitstream section does this time offset occur in? */
for(link=vf->links-1;link>=0;link--){
pcm_total-=vf->pcmlengths[link*2+1];
time_total-=ov_time_total(vf,link);
if(milliseconds>=time_total)break;
}
/* enough information to convert time offset to pcm offset */
{
ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
return(ov_pcm_seek_page(vf,target));
}
}
/* tell the current stream offset cursor. Note that seek followed by
tell will likely not give the set offset due to caching */
EXPORTED ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
if(vf->ready_state<OPENED)return(OV_EINVAL);
return(vf->offset);
}
/* return PCM offset (sample) of next PCM sample to be read */
EXPORTED ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
if(vf->ready_state<OPENED)return(OV_EINVAL);
return(vf->pcm_offset);
}
/* return time offset (milliseconds) of next PCM sample to be read */
EXPORTED ogg_int64_t ov_time_tell(OggVorbis_File *vf){
int link=0;
ogg_int64_t pcm_total=0;
ogg_int64_t time_total=0;
if(vf->ready_state<OPENED)return(OV_EINVAL);
if(vf->seekable){
pcm_total=ov_pcm_total(vf,-1);
time_total=ov_time_total(vf,-1);
/* which bitstream section does this time offset occur in? */
for(link=vf->links-1;link>=0;link--){
pcm_total-=vf->pcmlengths[link*2+1];
time_total-=ov_time_total(vf,link);
if(vf->pcm_offset>=pcm_total)break;
}
}
return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
}
/* link: -1) return the vorbis_info struct for the bitstream section
currently being decoded
0-n) to request information for a specific bitstream section
In the case of a non-seekable bitstream, any call returns the
current bitstream. NULL in the case that the machine is not
initialized */
EXPORTED vorbis_info *ov_info(OggVorbis_File *vf,int link){
if(vf->seekable){
if(link<0)
if(vf->ready_state>=STREAMSET)
return vf->vi+vf->current_link;
else
return vf->vi;
else
if(link>=vf->links)
return NULL;
else
return vf->vi+link;
}else{
return vf->vi;
}
}
/* grr, strong typing, grr, no templates/inheritence, grr */
EXPORTED vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
if(vf->seekable){
if(link<0)
if(vf->ready_state>=STREAMSET)
return vf->vc+vf->current_link;
else
return vf->vc;
else
if(link>=vf->links)
return NULL;
else
return vf->vc+link;
}else{
return vf->vc;
}
}
/* up to this point, everything could more or less hide the multiple
logical bitstream nature of chaining from the toplevel application
if the toplevel application didn't particularly care. However, at
the point that we actually read audio back, the multiple-section
nature must surface: Multiple bitstream sections do not necessarily
have to have the same number of channels or sampling rate.
ov_read returns the sequential logical bitstream number currently
being decoded along with the PCM data in order that the toplevel
application can take action on channel/sample rate changes. This
number will be incremented even for streamed (non-seekable) streams
(for seekable streams, it represents the actual logical bitstream
index within the physical bitstream. Note that the accessor
functions above are aware of this dichotomy).
input values: buffer) a buffer to hold packed PCM data for return
length) the byte length requested to be placed into buffer
return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
0) EOF
n) number of bytes of PCM actually returned. The
below works on a packet-by-packet basis, so the
return length is not related to the 'length' passed
in, just guaranteed to fit.
*section) set to the logical bitstream number */
EXPORTED long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){
int i,j;
ogg_int32_t **pcm = NULL;
long samples=0;
if(vf->ready_state<OPENED)return(OV_EINVAL);
while(1){
if(vf->ready_state==INITSET){
samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
if(samples)break;
}
/* suck in another packet */
{
int ret=_fetch_and_process_packet(vf,1,1);
if(ret==OV_EOF)
return(0);
if(ret<=0)
return(ret);
}
}
if(samples>0){
/* yay! proceed to pack data into the byte buffer */
long channels=ov_info(vf,-1)->channels;
if(channels==1){
if(samples>(bytes_req/2))
samples=bytes_req/2;
}else{
if(samples>(bytes_req/4))
samples=bytes_req/4;
}
for(i=0;i<channels;i++) { /* It's faster in this order */
ogg_int32_t *src=pcm[i];
short *dest=((short *)buffer)+i;
for(j=0;j<samples;j++) {
*dest= (short) CLIP_TO_15(src[j]>>9);
dest+=channels;
}
}
vorbis_synthesis_read(&vf->vd,samples);
vf->pcm_offset+=samples;
if(bitstream)*bitstream=vf->current_link;
return(samples*2*channels);
}else{
return(samples);
}
}
EXPORTED void ov_getFreqBin(OggVorbis_File *vf, int active, ogg_int32_t *freqBin)
{
vf->vb.performAnalysys = active;
vf->vb.dctcoefs = freqBin;
}
EXPORTED int ov_reqFreqBin(OggVorbis_File *vf)
{
return vf->vb.performAnalysys;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -