📄 vorbisfile.c
字号:
break; } vf->offset=ret; } } } ogg_page_release(&og);}static void _make_decode_ready(OggVorbis_File *vf){ if(vf->ready_state!=STREAMSET)return; 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->ready_state=INITSET; vf->bittrack=0; vf->samptrack=0; return;}static int _open_seekable2(OggVorbis_File *vf){ ogg_uint32_t serialno=vf->current_serialno; ogg_uint32_t tempserialno; ogg_int64_t dataoffset=vf->offset, end; ogg_page og={0,0,0,0}; /* we're partially open and have a first link header state in storage in vf */ /* we can seek, so set out learning all about this file */ (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); /* We get the offset for the last page of the physical bitstream. Most OggVorbis files will contain a single logical bitstream */ end=_get_prev_page(vf,&og); if(end<0)return(end); /* more than one logical bitstream? */ tempserialno=ogg_page_serialno(&og); ogg_page_release(&og); if(tempserialno!=serialno){ /* Chained bitstream. Bisect-search each logical bitstream section. Do so based on serial number only */ if(_bisect_forward_serialno(vf,0,0,end+1,serialno,0)<0)return(OV_EREAD); }else{ /* Only one logical bitstream */ if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return(OV_EREAD); } /* the initial header memory is referenced by vf after; don't free it */ _prefetch_all_headers(vf,dataoffset); return(ov_raw_seek(vf,0));}/* clear out the current logical bitstream decoder */ static void _decode_clear(OggVorbis_File *vf){ vorbis_dsp_clear(&vf->vd); vorbis_block_clear(&vf->vb); vf->ready_state=OPENED;}/* fetch and process a packet. Handles the case where we're at a bitstream boundary and dumps the decoding machine. If the decoding machine is unloaded, it loads it. It also keeps pcm_offset up to date (seek and read both use this. seek uses a special hack with readp). return: <0) error, OV_HOLE (lost packet) or OV_EOF 0) need more data (only if readp==0) 1) got a packet */static int _fetch_and_process_packet(OggVorbis_File *vf, int readp, int spanp){ ogg_page og={0,0,0,0}; ogg_packet op={0,0,0,0,0,0}; int ret=0; /* handle one packet. Try to fetch it from current stream state */ /* 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==INITSET){ while(1) { int result=ogg_stream_packetout(vf->os,&op); ogg_int64_t granulepos; if(result<0){ ret=OV_HOLE; /* hole in the data. */ goto cleanup; } if(result>0){ /* got a packet. process it */ granulepos=op.granulepos; if(!vorbis_synthesis(&vf->vb,&op,1)){ /* lazy check for lazy header handling. The header packets aren't audio, so if/when we submit them, vorbis_synthesis will reject them */ /* suck in the synthesis data and track bitrate */ { int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); /* for proper use of libvorbis within libvorbisfile, oldsamples will always be zero. */ if(oldsamples){ ret=OV_EFAULT; goto cleanup; } vorbis_synthesis_blockin(&vf->vd,&vf->vb); vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples; vf->bittrack+=op.bytes*8; } /* update the pcm offset. */ if(granulepos!=-1 && !op.e_o_s){ int link=(vf->seekable?vf->current_link:0); int i,samples; /* this packet has a pcm_offset on it (the last packet completed on a page carries the offset) After processing (above), we know the pcm position of the *last* sample ready to be returned. Find the offset of the *first* As an aside, this trick is inaccurate if we begin reading anew right at the last page; the end-of-stream 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 granulepos from an in-sequence page to have a reference point. Thus the !op.e_o_s clause above */ if(vf->seekable && link>0) granulepos-=vf->pcmlengths[link*2]; if(granulepos<0)granulepos=0; /* actually, this shouldn't be possible here unless the stream is very broken */ samples=vorbis_synthesis_pcmout(&vf->vd,NULL); granulepos-=samples; for(i=0;i<link;i++) granulepos+=vf->pcmlengths[i*2+1]; vf->pcm_offset=granulepos; } ret=1; goto cleanup; } } else break; } } if(vf->ready_state>=OPENED){ int ret; if(!readp){ ret=0; goto cleanup; } if((ret=_get_next_page(vf,&og,-1))<0){ ret=OV_EOF; /* eof. leave unitialized */ goto cleanup; } /* bitrate tracking; add the header's bytes here, the body bytes are done by packet above */ vf->bittrack+=og.header_len*8; /* has our decoding just traversed a bitstream boundary? */ if(vf->ready_state==INITSET){ if(vf->current_serialno!=ogg_page_serialno(&og)){ if(!spanp){ ret=OV_EOF; goto cleanup; } _decode_clear(vf); if(!vf->seekable){ vorbis_info_clear(vf->vi); vorbis_comment_clear(vf->vc); } } } } /* Do we need to load a new machine before submitting the page? */ /* This is different in the seekable and non-seekable cases. In the seekable case, we already have all the header information loaded and cached; we just initialize the machine with it and continue on our merry way. In the non-seekable (streaming) case, we'll only be at a boundary if we just left the previous logical bitstream and we're now nominally at the header of the next bitstream */ if(vf->ready_state!=INITSET){ int link; if(vf->ready_state<STREAMSET){ if(vf->seekable){ vf->current_serialno=ogg_page_serialno(&og); /* match the serialno to bitstream section. We use this rather than offset positions to avoid problems near logical bitstream boundaries */ for(link=0;link<vf->links;link++) if(vf->serialnos[link]==vf->current_serialno)break; if(link==vf->links){ ret=OV_EBADLINK; /* sign of a bogus stream. error out, leave machine uninitialized */ goto cleanup; } vf->current_link=link; ogg_stream_reset_serialno(vf->os,vf->current_serialno); vf->ready_state=STREAMSET; }else{ /* we're streaming */ /* fetch the three header packets, build the info struct */ int ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,&og); if(ret) goto cleanup; vf->current_link++; link=0; } } _make_decode_ready(vf); } ogg_stream_pagein(vf->os,&og); } cleanup: ogg_packet_release(&op); ogg_page_release(&og); return ret;}/* if, eg, 64 bit stdio is configured by default, this will build with fseek64 */static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ if(f==NULL)return(-1); return fseek(f,off,whence);}static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, long ibytes, ov_callbacks callbacks){ int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1); int ret; memset(vf,0,sizeof(*vf)); vf->datasource=f; vf->callbacks = callbacks; /* init the framing state */ vf->oy=ogg_sync_create(); /* perhaps some data was previously read into a buffer for testing against other stream types. Allow initialization from this previously read data (as we may be reading from a non-seekable stream) */ if(initial){ char *buffer=ogg_sync_bufferin(vf->oy,ibytes); memcpy(buffer,initial,ibytes); ogg_sync_wrote(vf->oy,ibytes); } /* can we seek? Stevens suggests the seek test was portable */ if(offsettest!=-1)vf->seekable=1; /* No seeking yet; Set up a 'single' (current) logical bitstream entry for partial open */ vf->links=1; vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); vf->os=ogg_stream_create(-1); /* fill in the serialno later */ /* Try to fetch the headers, maintaining all the storage */ if((ret=_fetch_headers(vf,vf->vi,vf->vc,&vf->current_serialno,NULL))<0){ vf->datasource=NULL; ov_clear(vf); }else if(vf->ready_state < PARTOPEN) vf->ready_state=PARTOPEN; return(ret);}static int _ov_open2(OggVorbis_File *vf){ if(vf->ready_state < OPENED) vf->ready_state=OPENED; if(vf->seekable){ int ret=_open_seekable2(vf); if(ret){ vf->datasource=NULL; ov_clear(vf); } return(ret); } return 0;}/* clear out the OggVorbis_File struct */int ov_clear(OggVorbis_File *vf){ if(vf){ vorbis_block_clear(&vf->vb); vorbis_dsp_clear(&vf->vd); ogg_stream_destroy(vf->os); if(vf->vi && vf->links){ int i; for(i=0;i<vf->links;i++){ vorbis_info_clear(vf->vi+i); vorbis_comment_clear(vf->vc+i); } _ogg_free(vf->vi); _ogg_free(vf->vc); } if(vf->dataoffsets)_ogg_free(vf->dataoffsets); if(vf->pcmlengths)_ogg_free(vf->pcmlengths); if(vf->serialnos)_ogg_free(vf->serialnos); if(vf->offsets)_ogg_free(vf->offsets); ogg_sync_destroy(vf->oy); if(vf->datasource)(vf->callbacks.close_func)(vf->datasource); memset(vf,0,sizeof(*vf)); }#ifdef DEBUG_LEAKS _VDBG_dump();#endif return(0);}/* inspects the OggVorbis file and finds/documents all the logical bitstreams contained in it. Tries to be tolerant of logical bitstream sections that are truncated/woogie. return: -1) error 0) OK*/int ov_open_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, ov_callbacks callbacks){ int ret=_ov_open1(f,vf,initial,ibytes,callbacks); if(ret)return ret; return _ov_open2(vf);}int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, (int (*)(void *)) fclose, (long (*)(void *)) ftell }; return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);} /* Only partially open the vorbis file; test for Vorbisness, and load the headers for the first chain. Do not seek (although test for seekability). Use ov_test_open to finish opening the file, else ov_clear to close/free it. Same return codes as open. */int ov_test_callbacks(void *f,OggVorbis_File *vf,char *initial,long ibytes, ov_callbacks callbacks){ return _ov_open1(f,vf,initial,ibytes,callbacks);}int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes){ ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, (int (*)(void *)) fclose, (long (*)(void *)) ftell }; return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -