diff options
| author | Nils Wallménius <nils@rockbox.org> | 2010-12-06 14:36:52 +0000 |
|---|---|---|
| committer | Nils Wallménius <nils@rockbox.org> | 2010-12-06 14:36:52 +0000 |
| commit | 67efbc13870ee87ce3df442f7c396c13481921ec (patch) | |
| tree | eaf63d36c5bf2d41a6b3bb2addecb4d3c05f7eef /apps/codecs/libtremor/vorbisfile.c | |
| parent | 1f64b7fb1fa5058e3b7871078055156eac0c511d (diff) | |
| download | rockbox-67efbc13870ee87ce3df442f7c396c13481921ec.zip rockbox-67efbc13870ee87ce3df442f7c396c13481921ec.tar.gz rockbox-67efbc13870ee87ce3df442f7c396c13481921ec.tar.bz2 rockbox-67efbc13870ee87ce3df442f7c396c13481921ec.tar.xz | |
libtremor:
Merge in upstream revision 17375.
This removes tremor's internal ogg code and now uses libogg instead so a bunch of changes are just adjusting to the new api. Also brings in improvements to vorbisfile which fixes FS#10484.
Disabled a lot of unused code in the libogg files and moved some small functions into the ogg.h header so they can be inlined. Some small tweaks to fix warnings.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28742 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libtremor/vorbisfile.c')
| -rw-r--r-- | apps/codecs/libtremor/vorbisfile.c | 509 |
1 files changed, 240 insertions, 269 deletions
diff --git a/apps/codecs/libtremor/vorbisfile.c b/apps/codecs/libtremor/vorbisfile.c index 50a57af..9365ba3 100644 --- a/apps/codecs/libtremor/vorbisfile.c +++ b/apps/codecs/libtremor/vorbisfile.c @@ -53,18 +53,19 @@ we only want coarse navigation through the stream. */ /************************************************************************* - * Many, many internal helpers. The intention is not to be confusing; - * rampant duplication and monolithic function implementation would be + * Many, many internal helpers. The intention is not to be confusing; + * rampant duplication and monolithic function implementation would be * harder to understand anyway. The high level functions are last. Begin * grokking near the end of the file */ /* read a little more data from the file/pipe into the ogg_sync framer */ static long _get_data(OggVorbis_File *vf){ + if(!(vf->callbacks.read_func))return(-1); if(vf->datasource){ - char *buffer=(char *)ogg_sync_bufferin(vf->oy,CHUNKSIZE); + char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE); long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource); - if(bytes>0)ogg_sync_wrote(vf->oy,bytes); + if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); return(bytes); }else return(0); @@ -77,7 +78,7 @@ static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) return OV_EREAD; vf->offset=offset; - ogg_sync_reset(vf->oy); + ogg_sync_reset(&vf->oy); }else{ /* shouldn't happen unless someone writes a broken callback */ return OV_EFAULT; @@ -96,9 +97,7 @@ static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ n) search for a new page beginning for n bytes return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) - n) found a page at absolute offset n - - produces a refcounted page */ + n) found a page at absolute offset n */ static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, ogg_int64_t boundary){ @@ -107,8 +106,8 @@ static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, long more; if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); - more=ogg_sync_pageseek(vf->oy,og); - + more=ogg_sync_pageseek(&vf->oy,og); + if(more<0){ /* skipped n bytes */ vf->offset-=more; @@ -127,7 +126,7 @@ static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, ogg_int64_t ret=vf->offset; vf->offset+=more; return(ret); - + } } } @@ -137,8 +136,7 @@ static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, position. Much dirtier than the above as Ogg doesn't have any backward search linkage. no 'readp' as it will certainly have to read. */ -/* returns offset or OV_EREAD, OV_FAULT and produces a refcounted page */ - +/* returns offset or OV_EREAD, OV_FAULT */ static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){ ogg_int64_t begin=vf->offset; ogg_int64_t end=begin; @@ -151,9 +149,10 @@ static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){ begin=0; ret=_seek_helper(vf,begin); - if(ret)return(ret); + if(ret)return(ret); while(vf->offset<end){ + memset(og,0,sizeof(*og)); ret=_get_next_page(vf,og,end-vf->offset); if(ret==OV_EREAD)return(OV_EREAD); if(ret<0){ @@ -168,7 +167,6 @@ static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){ holding the last page. In multiplexed (or noncompliant streams), we will probably have to re-read the last page we saw */ if(og->header_len==0){ - ogg_page_release(og); ret=_seek_helper(vf,offset); if(ret)return(ret); @@ -219,14 +217,14 @@ static int _lookup_page_serialno(ogg_page *og, ogg_uint32_t *serialno_list, int static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_uint32_t *serial_list, int serial_n, int *serialno, ogg_int64_t *granpos){ - ogg_page og={0,0,0,0}; + ogg_page og; ogg_int64_t begin=vf->offset; ogg_int64_t end=begin; ogg_int64_t ret; ogg_int64_t prefoffset=-1; ogg_int64_t offset=-1; - ogg_uint32_t ret_serialno=-1; + ogg_int64_t ret_serialno=-1; ogg_int64_t ret_gran=-1; while(offset==-1){ @@ -241,13 +239,11 @@ static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ret=_get_next_page(vf,&og,end-vf->offset); if(ret==OV_EREAD)return(OV_EREAD); if(ret<0){ - ogg_page_release(&og); break; }else{ ret_serialno=ogg_page_serialno(&og); ret_gran=ogg_page_granulepos(&og); offset=ret; - ogg_page_release(&og); if(ret_serialno == (ogg_uint32_t) *serialno){ prefoffset=ret; @@ -276,23 +272,18 @@ static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, /* uses the local ogg_stream storage in vf; this is important for non-streaming input sources */ -/* consumes the page that's passed in (if any) */ - -static int _fetch_headers(OggVorbis_File *vf, - vorbis_info *vi, - vorbis_comment *vc, - ogg_uint32_t **serialno_list, - int *serialno_n, +static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, + ogg_uint32_t **serialno_list, int *serialno_n, ogg_page *og_ptr){ - ogg_page og={0,0,0,0}; - ogg_packet op={0,0,0,0,0,0}; + ogg_page og; + ogg_packet op; int i,ret; int allbos=0; - + if(!og_ptr){ ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); if(llret==OV_EREAD)return(OV_EREAD); - if(llret<0)return OV_ENOTVORBIS; + if(llret<0)return(OV_ENOTVORBIS); og_ptr=&og; } @@ -320,10 +311,10 @@ static int _fetch_headers(OggVorbis_File *vf, if(vf->ready_state<STREAMSET){ /* we don't have a vorbis stream in this link yet, so begin prospective stream setup. We need a stream to get packets */ - ogg_stream_reset_serialno(vf->os,ogg_page_serialno(og_ptr)); - ogg_stream_pagein(vf->os,og_ptr); + ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr)); + ogg_stream_pagein(&vf->os,og_ptr); - if(ogg_stream_packetout(vf->os,&op) > 0 && + if(ogg_stream_packetout(&vf->os,&op) > 0 && vorbis_synthesis_idheader(&op)){ /* vorbis header; continue setup */ vf->ready_state=STREAMSET; @@ -348,8 +339,8 @@ static int _fetch_headers(OggVorbis_File *vf, /* if this page also belongs to our vorbis stream, submit it and break */ if(vf->ready_state==STREAMSET && - (ogg_uint32_t) vf->os->serialno == ogg_page_serialno(og_ptr)){ - ogg_stream_pagein(vf->os,og_ptr); + vf->os.serialno == ogg_page_serialno(og_ptr)){ + ogg_stream_pagein(&vf->os,og_ptr); break; } } @@ -367,7 +358,7 @@ static int _fetch_headers(OggVorbis_File *vf, while(i<2){ /* get a packet loop */ - int result=ogg_stream_packetout(vf->os,&op); + int result=ogg_stream_packetout(&vf->os,&op); if(result==0)break; if(result==-1){ ret=OV_EBADHEADER; @@ -387,8 +378,8 @@ static int _fetch_headers(OggVorbis_File *vf, } /* if this page belongs to the correct stream, go parse it */ - if((ogg_uint32_t) vf->os->serialno == ogg_page_serialno(og_ptr)){ - ogg_stream_pagein(vf->os,og_ptr); + if(vf->os.serialno == ogg_page_serialno(og_ptr)){ + ogg_stream_pagein(&vf->os,og_ptr); break; } @@ -406,15 +397,10 @@ static int _fetch_headers(OggVorbis_File *vf, } } - ogg_packet_release(&op); - ogg_page_release(&og); - return 0; } bail_header: - ogg_packet_release(&op); - ogg_page_release(&og); vorbis_info_clear(vi); vorbis_comment_clear(vc); vf->ready_state=OPENED; @@ -427,25 +413,23 @@ static int _fetch_headers(OggVorbis_File *vf, audio, however this is only called during stream parsing upon seekable open. */ static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ - ogg_page og={0,0,0,0}; - ogg_int64_t accumulated=0,pos; + ogg_page og; + ogg_int64_t accumulated=0; long lastblock=-1; int result; - int serialno = vf->os->serialno; + ogg_uint32_t serialno = vf->os.serialno; while(1){ - ogg_packet op={0,0,0,0,0,0}; - + ogg_packet op; if(_get_next_page(vf,&og,-1)<0) break; /* should not be possible unless the file is truncated/mangled */ if(ogg_page_bos(&og)) break; - if(ogg_page_serialno(&og)!=(ogg_uint32_t) serialno) continue; - pos=ogg_page_granulepos(&og); + if(ogg_page_serialno(&og)!= serialno) continue; /* count blocksizes of all frames in the page */ - ogg_stream_pagein(vf->os,&og); - while((result=ogg_stream_packetout(vf->os,&op))){ + ogg_stream_pagein(&vf->os,&og); + while((result=ogg_stream_packetout(&vf->os,&op))){ if(result>0){ /* ignore holes */ long thisblock=vorbis_packet_blocksize(vi,&op); if(lastblock!=-1) @@ -453,11 +437,10 @@ static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ lastblock=thisblock; } } - ogg_packet_release(&op); - if(pos!=-1){ + if(ogg_page_granulepos(&og)!=-1){ /* pcm offset of last packet on the first audio page */ - accumulated= pos-accumulated; + accumulated= ogg_page_granulepos(&og)-accumulated; break; } } @@ -466,11 +449,9 @@ static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ the beginning, a normal occurrence; set the offset to zero */ if(accumulated<0)accumulated=0; - ogg_page_release(&og); return accumulated; } - /* finds each bitstream link one at a time using a bisection search (has to begin by knowing the offset of the lb's initial page). Recurses for each link so it can alloc the link storage after @@ -484,14 +465,14 @@ static int _bisect_forward_serialno(OggVorbis_File *vf, ogg_uint32_t *currentno_list, int currentnos, long m){ - ogg_int64_t pcmoffset; ogg_int64_t dataoffset=searched; ogg_int64_t endsearched=end; ogg_int64_t next=end; ogg_int64_t searchgran=-1; + ogg_page og; ogg_int64_t ret,last; - int serialno = vf->os->serialno; + int serialno = vf->os.serialno; /* invariants: we have the headers and serialnos for the link beginning at 'begin' @@ -538,7 +519,6 @@ static int _bisect_forward_serialno(OggVorbis_File *vf, /* the below guards against garbage seperating the last and first pages of two links. */ while(searched<endsearched){ - ogg_page og={0,0,0,0}; ogg_int64_t bisect; if(endsearched-searched<CHUNKSIZE){ @@ -547,8 +527,10 @@ static int _bisect_forward_serialno(OggVorbis_File *vf, bisect=(searched+endsearched)/2; } - ret=_seek_helper(vf,bisect); - if(ret)return(ret); + if(bisect != vf->offset){ + ret=_seek_helper(vf,bisect); + if(ret)return(ret); + } last=_get_next_page(vf,&og,-1); if(last==OV_EREAD)return(OV_EREAD); @@ -556,9 +538,8 @@ static int _bisect_forward_serialno(OggVorbis_File *vf, endsearched=bisect; if(last>=0)next=last; }else{ - searched=last+og.header_len+og.body_len; + searched=vf->offset; } - ogg_page_release(&og); } /* Bisection point found */ @@ -580,7 +561,7 @@ static int _bisect_forward_serialno(OggVorbis_File *vf, ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL); if(ret)return(ret); - serialno = vf->os->serialno; + serialno = vf->os.serialno; dataoffset = vf->offset; /* this will consume a page, however the next bistection always @@ -627,8 +608,8 @@ static int _make_decode_ready(OggVorbis_File *vf){ static int _open_seekable2(OggVorbis_File *vf){ ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1; - int endserial=vf->os->serialno; - int serialno=vf->os->serialno; + int endserial=vf->os.serialno; + int serialno=vf->os.serialno; /* we're partially open and have a first link header state in storage in vf */ @@ -666,7 +647,7 @@ static int _open_seekable2(OggVorbis_File *vf){ return(ov_raw_seek(vf,dataoffset)); } -/* clear out the current logical bitstream decoder */ +/* clear out the current logical bitstream decoder */ static void _decode_clear(OggVorbis_File *vf){ vorbis_dsp_clear(&vf->vd); vorbis_block_clear(&vf->vb); @@ -677,74 +658,67 @@ static void _decode_clear(OggVorbis_File *vf){ 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). + readp). return: <0) error, OV_HOLE (lost packet) or OV_EOF 0) need more data (only if readp==0) - 1) got a packet + 1) got a packet */ -STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, - int readp, - int spanp) ICODE_ATTR_TREMOR_NOT_MDCT; -STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, +static int _fetch_and_process_packet(OggVorbis_File *vf, + ogg_packet *op_in, int readp, int spanp){ - ogg_page og={0,0,0,0}; - ogg_packet op={0,0,0,0,0,0}; - int ret=0; + ogg_page og; /* handle one packet. Try to fetch it from current stream state */ /* extract packets from page */ while(1){ - + if(vf->ready_state==STREAMSET){ - ret=_make_decode_ready(vf); - if(ret<0) goto cleanup; + int ret=_make_decode_ready(vf); + if(ret<0)return ret; } /* 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_packet op; + ogg_packet *op_ptr=(op_in?op_in:&op); + int result=ogg_stream_packetout(&vf->os,op_ptr); ogg_int64_t granulepos; - if(result==-1){ - ret=OV_HOLE; /* hole in the data. */ - goto cleanup; - } + op_in=NULL; + if(result==-1)return(OV_HOLE); /* hole in the data. */ if(result>0){ /* got a packet. process it */ - granulepos=op.granulepos; - if(!vorbis_synthesis(&vf->vb,&op)){ /* lazy check for lazy - header handling. The - header packets aren't - audio, so if/when we - submit them, - vorbis_synthesis will - reject them */ + granulepos=op_ptr->granulepos; + if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* 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; - } + if(oldsamples)return(OV_EFAULT); vorbis_synthesis_blockin(&vf->vd,&vf->vb); vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples; - vf->bittrack+=op.bytes*8; + vf->bittrack+=op_ptr->bytes*8; } - + /* update the pcm offset. */ - if(granulepos!=-1 && !op.e_o_s){ + if(granulepos!=-1 && !op_ptr->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 @@ -755,7 +729,7 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, 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 + to have a reference point. Thus the !op_ptr->e_o_s clause above */ if(vf->seekable && link>0) @@ -766,23 +740,22 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, 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; + return(1); } } - else + else break; } } if(vf->ready_state>=OPENED){ - ogg_int64_t lret; + ogg_int64_t ret; while(1){ /* the loop is not strictly necessary, but there's no sense in @@ -791,13 +764,9 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, part of a different logical bitstream; keep reading until we get one with the correct serialno */ - if(!readp){ - ret=0; - goto cleanup; - } - if((lret=_get_next_page(vf,&og,-1))<0){ - ret=OV_EOF; /* eof. leave unitialized */ - goto cleanup; + if(!readp)return(0); + if((ret=_get_next_page(vf,&og,-1))<0){ + return(OV_EOF); /* eof. leave unitialized */ } /* bitrate tracking; add the header's bytes here, the body bytes @@ -813,10 +782,8 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, if(ogg_page_bos(&og)){ /* boundary case */ - if(!spanp){ - ret=OV_EOF; - goto cleanup; - } + if(!spanp) + return(OV_EOF); _decode_clear(vf); @@ -830,12 +797,13 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, continue; /* possibility #2 */ } } + break; } } /* Do we need to load a new machine before submitting the page? */ - /* This is different in the seekable and non-seekable cases. + /* 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 @@ -846,37 +814,37 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, we're now nominally at the header of the next bitstream */ - if(vf->ready_state!=INITSET){ + if(vf->ready_state!=INITSET){ int link; if(vf->ready_state<STREAMSET){ if(vf->seekable){ - long serialno=ogg_page_serialno(&og); + ogg_uint32_t 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]==(ogg_uint32_t) serialno)break; + if(vf->serialnos[link]==serialno)break; - if(link==vf->links) continue; /* not the desired Vorbis - bitstream section; keep - trying */ + if(link==vf->links) continue; /* not the desired Vorbis + bitstream section; keep + trying */ vf->current_serialno=serialno; vf->current_link=link; - ogg_stream_reset_serialno(vf->os,vf->current_serialno); + 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,NULL,NULL,&og); - if(ret) goto cleanup; - vf->current_serialno=vf->os->serialno; + if(ret)return(ret); + vf->current_serialno=vf->os.serialno; vf->current_link++; link=0; } @@ -885,17 +853,14 @@ STATICIRAM_NOT_MDCT int _fetch_and_process_packet(OggVorbis_File *vf, /* the buffered page is the data we want, and we're ready for it; add it to the stream state */ - ogg_stream_pagein(vf->os,&og); + ogg_stream_pagein(&vf->os,&og); + } - cleanup: - ogg_packet_release(&op); - ogg_page_release(&og); - return ret; } -static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, +static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, long ibytes, ov_callbacks callbacks){ - int offsettest=(f?callbacks.seek_func(f,0,SEEK_CUR):-1); + int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); ogg_uint32_t *serialno_list=NULL; int serialno_list_size=0; int ret; @@ -905,16 +870,16 @@ static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, vf->callbacks = callbacks; /* init the framing state */ - vf->oy=ogg_sync_create(); + ogg_sync_init(&vf->oy); /* perhaps some data was previously read into a buffer for testing against other stream types. Allow initialization from this previously read data (especially as we may be reading from a non-seekable stream) */ if(initial){ - unsigned char *buffer=ogg_sync_bufferin(vf->oy,ibytes); + char *buffer=ogg_sync_buffer(&vf->oy,ibytes); memcpy(buffer,initial,ibytes); - ogg_sync_wrote(vf->oy,ibytes); + ogg_sync_wrote(&vf->oy,ibytes); } /* can we seek? Stevens suggests the seek test was portable */ @@ -925,7 +890,7 @@ static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, 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 */ + ogg_stream_init(&vf->os,-1); /* fill in the serialno later */ /* Fetch all BOS pages, store the vorbis header and all seen serial numbers, load subsequent vorbis setup headers */ @@ -945,7 +910,7 @@ static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets)); vf->offsets[0]=0; vf->dataoffsets[0]=vf->offset; - vf->current_serialno=vf->os->serialno; + vf->current_serialno=vf->os.serialno; vf->ready_state=PARTOPEN; } @@ -954,8 +919,8 @@ static int _ov_open1(void *f,OggVorbis_File *vf,char *initial, } static int _ov_open2(OggVorbis_File *vf){ - if(vf->ready_state < OPENED) - vf->ready_state=OPENED; + if(vf->ready_state != PARTOPEN) return OV_EINVAL; + vf->ready_state=OPENED; if(vf->seekable){ int ret=_open_seekable2(vf); if(ret){ @@ -963,7 +928,9 @@ static int _ov_open2(OggVorbis_File *vf){ ov_clear(vf); } return(ret); - } + }else + vf->ready_state=STREAMSET; + return 0; } @@ -973,8 +940,8 @@ int ov_clear(OggVorbis_File *vf){ if(vf){ vorbis_block_clear(&vf->vb); vorbis_dsp_clear(&vf->vd); - ogg_stream_destroy(vf->os); - + ogg_stream_clear(&vf->os); + if(vf->vi && vf->links){ int i; for(i=0;i<vf->links;i++){ @@ -988,8 +955,7 @@ int ov_clear(OggVorbis_File *vf){ 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); - + ogg_sync_clear(&vf->oy); if(vf->datasource && vf->callbacks.close_func) (vf->callbacks.close_func)(vf->datasource); memset(vf,0,sizeof(*vf)); @@ -1002,14 +968,14 @@ int ov_clear(OggVorbis_File *vf){ /* 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. + 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 ov_open_callbacks(void *f,OggVorbis_File *vf, + const char *initial,long ibytes,ov_callbacks callbacks){ #if defined(CPU_COLDFIRE) /* this seems to be the closest we get to an init function, let's init emac here. rounding is disabled because of MULT31_SHIFT15, which will be @@ -1067,9 +1033,7 @@ ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){ returns zero on success, nonzero on failure */ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ - ogg_stream_state *work_os=NULL; - ogg_page og={0,0,0,0}; - ogg_packet op={0,0,0,0,0,0}; + ogg_stream_state work_os; int ret; if(vf->ready_state<OPENED)return(OV_EINVAL); @@ -1078,15 +1042,21 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ if(pos<0 || pos>vf->end)return(OV_EINVAL); + /* is the seek position outside our current link [if any]? */ + if(vf->ready_state>=STREAMSET){ + if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1]) + _decode_clear(vf); /* clear out stream state */ + } + /* don't yet clear out decoding machine (if it's initialized), in the case we're in the same link. Restart the decode lapping, and let _fetch_and_process_packet deal with a potential bitstream boundary */ vf->pcm_offset=-1; - ogg_stream_reset_serialno(vf->os, + ogg_stream_reset_serialno(&vf->os, vf->current_serialno); /* must set serialno */ vorbis_synthesis_restart(&vf->vd); - + ret=_seek_helper(vf,pos); if(ret)goto seek_error; @@ -1097,55 +1067,61 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ So, a hack. We use two stream states; a local scratch state and the shared vf->os stream state. We use the local state to - scan, and the shared state as a buffer for later decode. + scan, and the shared state as a buffer for later decode. Unfortuantely, on the last page we still advance to last packet because the granulepos on the last page is not necessarily on a packet boundary, and we need to make sure the granpos is - correct. + correct. */ { + ogg_page og; + ogg_packet op; int lastblock=0; int accblock=0; - int thisblock; + int thisblock=0; int lastflag=0; int firstflag=0; ogg_int64_t pagepos=-1; - work_os=ogg_stream_create(vf->current_serialno); /* get the memory ready */ + ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */ + ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE + return from not necessarily + starting from the beginning */ + while(1){ if(vf->ready_state>=STREAMSET){ /* snarf/scan a packet if we can */ - int result=ogg_stream_packetout(work_os,&op); - + int result=ogg_stream_packetout(&work_os,&op); + if(result>0){ if(vf->vi[vf->current_link].codec_setup){ thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); if(thisblock<0){ - ogg_stream_packetout(vf->os,NULL); + ogg_stream_packetout(&vf->os,NULL); thisblock=0; }else{ - + /* 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 + preceding 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); + ogg_stream_packetout(&vf->os,NULL); else if(lastblock)accblock+=(lastblock+thisblock)>>2; - } + } if(op.granulepos!=-1){ int i,link=vf->current_link; ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; if(granulepos<0)granulepos=0; - + for(i=0;i<link;i++) granulepos+=vf->pcmlengths[i*2+1]; vf->pcm_offset=granulepos-accblock; @@ -1155,10 +1131,10 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ lastblock=thisblock; continue; }else - ogg_stream_packetout(vf->os,NULL); + ogg_stream_packetout(&vf->os,NULL); } } - + if(!lastblock){ pagepos=_get_next_page(vf,&og,-1); if(pagepos<0){ @@ -1170,10 +1146,11 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ vf->pcm_offset=-1; break; } - + /* has our decoding just traversed a bitstream boundary? */ if(vf->ready_state>=STREAMSET){ if(vf->current_serialno!=ogg_page_serialno(&og)){ + /* two possibilities: 1) our decoding just traversed a bitstream boundary 2) another stream is multiplexed into this logical section? */ @@ -1181,53 +1158,45 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ if(ogg_page_bos(&og)){ /* we traversed */ _decode_clear(vf); /* clear out stream state */ - ogg_stream_destroy(work_os); + ogg_stream_clear(&work_os); } /* else, do nothing; next loop will scoop another page */ } } if(vf->ready_state<STREAMSET){ int link; - long serialno = ogg_page_serialno(&og); + ogg_uint32_t serialno = ogg_page_serialno(&og); for(link=0;link<vf->links;link++) - if(vf->serialnos[link]==vf->current_serialno)break; + if(vf->serialnos[link]==serialno)break; if(link==vf->links) continue; /* not the desired Vorbis bitstream section; keep trying */ vf->current_link=link; vf->current_serialno=serialno; - ogg_stream_reset_serialno(vf->os,vf->current_serialno); - ogg_stream_reset_serialno(work_os,vf->current_serialno); + ogg_stream_reset_serialno(&vf->os,serialno); + ogg_stream_reset_serialno(&work_os,serialno); vf->ready_state=STREAMSET; firstflag=(pagepos<=vf->dataoffsets[link]); } - - { - ogg_page dup; - ogg_page_dup(&dup,&og); - lastflag=ogg_page_eos(&og); - ogg_stream_pagein(vf->os,&og); - ogg_stream_pagein(work_os,&dup); - } + + ogg_stream_pagein(&vf->os,&og); + ogg_stream_pagein(&work_os,&og); + lastflag=ogg_page_eos(&og); + } } - ogg_packet_release(&op); - ogg_page_release(&og); - ogg_stream_destroy(work_os); + ogg_stream_clear(&work_os); vf->bittrack=0; vf->samptrack=0; return(0); seek_error: - ogg_packet_release(&op); - ogg_page_release(&og); - /* dump the machine so we're in a known state */ vf->pcm_offset=-1; - ogg_stream_destroy(work_os); + ogg_stream_clear(&work_os); _decode_clear(vf); return OV_EBADLINK; } @@ -1235,20 +1204,19 @@ int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ /* Page granularity seek (faster than sample granularity because we don't do the last bit of decode to find a specific sample). - Seek to the last [granule marked] page preceeding the specified pos + Seek to the last [granule marked] page preceding the specified pos location, such that decoding past the returned point will quickly arrive at the requested position. */ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ int link=-1; ogg_int64_t result=0; ogg_int64_t total=ov_pcm_total(vf,-1); - ogg_page og={0,0,0,0}; - ogg_packet op={0,0,0,0,0,0}; if(vf->ready_state<OPENED)return(OV_EINVAL); if(!vf->seekable)return(OV_ENOSEEK); + if(pos<0 || pos>total)return(OV_EINVAL); - + /* which bitstream section does this pcm offset occur in? */ for(link=vf->links-1;link>=0;link--){ total-=vf->pcmlengths[link*2+1]; @@ -1256,7 +1224,7 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ } /* search within the logical bitstream for the page with the highest - pcm_pos preceeding (or equal to) pos. There is a danger here; + pcm_pos preceding (or equal to) pos. There is a danger here; missing pages or incorrect frame number information in the bitstream could make our task impossible. Account for that (it would be an error condition) */ @@ -1269,22 +1237,26 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; ogg_int64_t target=pos-total+begintime; ogg_int64_t best=begin; - + + ogg_page og; while(begin<end){ ogg_int64_t bisect; - + if(end-begin<CHUNKSIZE){ bisect=begin; }else{ /* take a (pretty decent) guess. */ - bisect=begin + + bisect=begin + (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE; - if(bisect<=begin) - bisect=begin+1; + if(bisect<begin+CHUNKSIZE) + bisect=begin; } - - _seek_helper(vf,bisect); - + + if(bisect!=vf->offset){ + 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; @@ -1295,16 +1267,23 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ if(bisect==0) goto seek_error; bisect-=CHUNKSIZE; if(bisect<=begin)bisect=begin+1; - _seek_helper(vf,bisect); + result=_seek_helper(vf,bisect); + if(result) goto seek_error; } }else{ - ogg_int64_t granulepos=ogg_page_granulepos(&og); + ogg_int64_t granulepos; + + if(ogg_page_serialno(&og)!=vf->serialnos[link]) + continue; + + granulepos=ogg_page_granulepos(&og); if(granulepos==-1)continue; + if(granulepos<target){ - best=result; /* raw offset of packet with granulepos */ + best=result; /* raw offset of packet with granulepos */ begin=vf->offset; /* raw offset of next page */ begintime=granulepos; - + if(target-begintime>44100)break; bisect=begin; /* *not* begin + 1 */ }else{ @@ -1315,9 +1294,10 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ end=result; bisect-=CHUNKSIZE; /* an endless loop otherwise. */ if(bisect<=begin)bisect=begin+1; - _seek_helper(vf,bisect); + result=_seek_helper(vf,bisect); + if(result) goto seek_error; }else{ - end=result; + end=bisect; endtime=granulepos; break; } @@ -1328,9 +1308,11 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ } /* found our page. seek to it, update pcm offset. Easier case than - raw_seek, don't keep packets preceeding granulepos. */ + raw_seek, don't keep packets preceding granulepos. */ { - + ogg_page og; + ogg_packet op; + /* seek */ result=_seek_helper(vf,best); vf->pcm_offset=-1; @@ -1340,28 +1322,28 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ if(link!=vf->current_link){ /* Different link; dump entire decode machine */ - _decode_clear(vf); - + _decode_clear(vf); + vf->current_link=link; - vf->current_serialno=ogg_page_serialno(&og); + vf->current_serialno=vf->serialnos[link]; 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); + 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); + 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 + preceding 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. */ - + result=_seek_helper(vf,best); if(result<0) goto seek_error; @@ -1377,7 +1359,7 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ } } if(result<0){ - result = OV_EBADPACKET; + result = OV_EBADPACKET; goto seek_error; } if(op.granulepos!=-1){ @@ -1386,11 +1368,11 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ vf->pcm_offset+=total; break; }else - result=ogg_stream_packetout(vf->os,NULL); + result=ogg_stream_packetout(&vf->os,NULL); } } } - + /* verify result */ if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ result=OV_EFAULT; @@ -1398,60 +1380,53 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ } 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); + seek_error: /* 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 +/* seek to a sample offset relative to the decompressed pcm stream returns zero on success, nonzero on failure */ 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); + if((ret=_make_decode_ready(vf)))return ret; /* discard leading packets we don't need for the lapping of the position we want; don't decode them */ while(1){ + ogg_packet op; + ogg_page og; - int ret=ogg_stream_packetpeek(vf->os,&op); + 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); + 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); + ogg_stream_packetout(&vf->os,NULL); vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with only tracking, no pcm_decode */ - vorbis_synthesis_blockin(&vf->vd,&vf->vb); - + 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 */ @@ -1460,20 +1435,20 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ 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(ogg_page_bos(&og))_decode_clear(vf); - + if(vf->ready_state<STREAMSET){ - long serialno=ogg_page_serialno(&og); + long serialno=ogg_page_serialno(&og); int link; - + for(link=0;link<vf->links;link++) if(vf->serialnos[link]==(ogg_uint32_t) serialno)break; if(link==vf->links) continue; @@ -1481,17 +1456,13 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ vf->ready_state=STREAMSET; vf->current_serialno=ogg_page_serialno(&og); - ogg_stream_reset_serialno(vf->os,serialno); + ogg_stream_reset_serialno(&vf->os,serialno); ret=_make_decode_ready(vf); - if(ret){ - ogg_page_release(&og); - ogg_packet_release(&op); - return ret; - } + if(ret)return ret; lastblock=0; } - ogg_stream_pagein(vf->os,&og); + ogg_stream_pagein(&vf->os,&og); } } @@ -1506,18 +1477,15 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ if(samples>target)samples=target; vorbis_synthesis_read(&vf->vd,samples); vf->pcm_offset+=samples; - + if(samples<target) - if(_fetch_and_process_packet(vf,1,1)<=0) + if(_fetch_and_process_packet(vf,NULL,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 +/* seek to a playback time relative to the decompressed pcm stream returns zero on success, nonzero on failure */ int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){ /* translate time to PCM position and call ov_pcm_seek */ @@ -1529,7 +1497,7 @@ int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){ if(vf->ready_state<OPENED)return(OV_EINVAL); if(!vf->seekable)return(OV_ENOSEEK); if(milliseconds<0)return(OV_EINVAL); - + /* which bitstream section does this time offset occur in? */ for(link=0;link<vf->links;link++){ ogg_int64_t addsec = ov_time_total(vf,link); @@ -1559,7 +1527,7 @@ 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); @@ -1579,7 +1547,7 @@ ogg_int64_t ov_time_tell(OggVorbis_File *vf){ /* 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 */ @@ -1634,9 +1602,12 @@ long ov_read_fixed(OggVorbis_File *vf,ogg_int32_t ***pcm_channels,int length, /* suck in another packet */ { - int ret=_fetch_and_process_packet(vf,1,1); - if(ret==OV_EOF)return(0); - if(ret<=0)return(ret); + int ret=_fetch_and_process_packet(vf,NULL,1,1); + if(ret==OV_EOF) + return(0); + if(ret<=0) + return(ret); } } } + |