summaryrefslogtreecommitdiff
path: root/lib/tremor/vorbisfile.c
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-02-14 12:21:33 +1100
committerjacqueline <me@jacqueline.id.au>2024-02-14 12:21:33 +1100
commit7ec0ff2589ffd5774e78f9e6b436ea55be45deb1 (patch)
tree4bc335bf6474bff2babbcbd4690231320b52520f /lib/tremor/vorbisfile.c
parentb31bc07555fdd862181d8d6ed551163cea89bc62 (diff)
downloadtangara-fw-7ec0ff2589ffd5774e78f9e6b436ea55be45deb1.tar.gz
Switch to the lowmem tremor branch
in addition to using slightly less memory, this branch also doesn't seem to have the same issues with `-O2` builds that the main branch has.
Diffstat (limited to 'lib/tremor/vorbisfile.c')
-rw-r--r--lib/tremor/vorbisfile.c2279
1 files changed, 950 insertions, 1329 deletions
diff --git a/lib/tremor/vorbisfile.c b/lib/tremor/vorbisfile.c
index cd4814df..79cdefcd 100644
--- a/lib/tremor/vorbisfile.c
+++ b/lib/tremor/vorbisfile.c
@@ -1,18 +1,18 @@
/********************************************************************
* *
- * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
+ * THIS FILE IS PART OF THE TremorOggVorbis 'TREMOR' CODEC SOURCE CODE. *
* *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
* GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
* IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
* *
- * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2014 *
+ * THE TremorOggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
* BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
* *
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
- last mod: $Id$
+ last mod: $Id: vorbisfile.c,v 1.6.2.5 2003/11/20 06:16:17 xiphmont Exp $
********************************************************************/
@@ -22,12 +22,19 @@
#include <string.h>
#include <math.h>
-#include "ivorbiscodec.h"
+#include "codec_internal.h"
#include "ivorbisfile.h"
#include "os.h"
#include "misc.h"
+#define NOTOPEN 0
+#define PARTOPEN 1
+#define OPENED 2
+#define STREAMSET 3 /* serialno and link set, but not to current link */
+#define LINKSET 4 /* serialno and link set to current link */
+#define INITSET 5
+
/* A 'chained bitstream' is a Vorbis bitstream that contains more than
one logical bitstream arranged end to end (the only form of Ogg
multiplexing allowed in a Vorbis bitstream; grouping [parallel
@@ -52,42 +59,35 @@
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){
+/* read a little more data from the file/pipe into the tremor_ogg_sync framer */
+static long _get_data(TremorOggVorbis_File *vf){
errno=0;
- if(!(vf->callbacks.read_func))return(-1);
if(vf->datasource){
- char *buffer=ogg_sync_buffer(&vf->oy,READSIZE);
- long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource);
- if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
- if(bytes==0 && errno)return(-1);
- return(bytes);
+ unsigned char *buffer=tremor_ogg_sync_bufferin(vf->oy,CHUNKSIZE);
+ long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
+ if(bytes>0)tremor_ogg_sync_wrote(vf->oy,bytes);
+ if(bytes==0 && errno)return -1;
+ return bytes;
}else
- return(0);
+ return 0;
}
/* save a tiny smidge of verbosity to make the code more readable */
-static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
- if(vf->datasource){
- /* only seek if the file position isn't already there */
- if(vf->offset != offset){
- if(!(vf->callbacks.seek_func)||
- (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
- return OV_EREAD;
- vf->offset=offset;
- ogg_sync_reset(&vf->oy);
- }
+static void _seek_helper(TremorOggVorbis_File *vf,tremor_ogg_int64_t offset){
+ if(vf->datasource){
+ (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET);
+ vf->offset=offset;
+ tremor_ogg_sync_reset(vf->oy);
}else{
/* shouldn't happen unless someone writes a broken callback */
- return OV_EFAULT;
+ return;
}
- return 0;
}
/* The read/seek functions track absolute position within the stream */
@@ -98,310 +98,221 @@ static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
boundary: -1) unbounded search
0) read no additional data; use cached only
- n) search for a new page beginning for n bytes
+ 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 */
+ n) found a page at absolute offset n
+
+ produces a refcounted page */
-static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
- ogg_int64_t boundary){
+static tremor_ogg_int64_t _get_next_page(TremorOggVorbis_File *vf,tremor_ogg_page *og,
+ tremor_ogg_int64_t boundary){
if(boundary>0)boundary+=vf->offset;
while(1){
long more;
- if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
- more=ogg_sync_pageseek(&vf->oy,og);
-
+ if(boundary>0 && vf->offset>=boundary)return OV_FALSE;
+ more=tremor_ogg_sync_pageseek(vf->oy,og);
+
if(more<0){
/* skipped n bytes */
vf->offset-=more;
}else{
if(more==0){
- /* send more paramedics */
- if(!boundary)return(OV_FALSE);
- {
- long ret=_get_data(vf);
- if(ret==0)return(OV_EOF);
- if(ret<0)return(OV_EREAD);
- }
+ /* send more paramedics */
+ if(!boundary)return OV_FALSE;
+ {
+ long ret=_get_data(vf);
+ if(ret==0)return OV_EOF;
+ if(ret<0)return OV_EREAD;
+ }
}else{
- /* got a page. Return the offset at the page beginning,
+ /* got a page. Return the offset at the page beginning,
advance the internal offset past the page end */
- ogg_int64_t ret=vf->offset;
- vf->offset+=more;
- return(ret);
-
+ tremor_ogg_int64_t ret=vf->offset;
+ vf->offset+=more;
+ return ret;
+
}
}
}
}
-/* find the latest page beginning before the passed in 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 */
-static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){
- ogg_int64_t end = begin;
- ogg_int64_t ret;
- ogg_int64_t offset=-1;
+/* find the latest page beginning before the current stream cursor
+ 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 */
+
+static tremor_ogg_int64_t _get_prev_page(TremorOggVorbis_File *vf,tremor_ogg_page *og){
+ tremor_ogg_int64_t begin=vf->offset;
+ tremor_ogg_int64_t end=begin;
+ tremor_ogg_int64_t ret;
+ tremor_ogg_int64_t offset=-1;
while(offset==-1){
begin-=CHUNKSIZE;
if(begin<0)
begin=0;
-
- ret=_seek_helper(vf,begin);
- if(ret)return(ret);
-
+ _seek_helper(vf,begin);
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==OV_EREAD)return OV_EREAD;
if(ret<0){
- break;
+ break;
}else{
- offset=ret;
+ offset=ret;
}
}
}
- /* In a fully compliant, non-multiplexed stream, we'll still be
- 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){
- ret=_seek_helper(vf,offset);
- if(ret)return(ret);
-
- ret=_get_next_page(vf,og,CHUNKSIZE);
- if(ret<0)
- /* this shouldn't be possible */
- return(OV_EFAULT);
- }
+ /* we have the offset. Actually snork and hold the page now */
+ _seek_helper(vf,offset);
+ ret=_get_next_page(vf,og,CHUNKSIZE);
+ if(ret<0)
+ /* this shouldn't be possible */
+ return OV_EFAULT;
- return(offset);
+ return offset;
}
-static void _add_serialno(ogg_page *og,ogg_uint32_t **serialno_list, int *n){
- ogg_uint32_t s = ogg_page_serialno(og);
- (*n)++;
-
- if(*serialno_list){
- *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
- }else{
- *serialno_list = _ogg_malloc(sizeof(**serialno_list));
+/* 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
+ finding them all, then unroll and fill the cache at the same time */
+static int _bisect_forward_serialno(TremorOggVorbis_File *vf,
+ tremor_ogg_int64_t begin,
+ tremor_ogg_int64_t searched,
+ tremor_ogg_int64_t end,
+ tremor_ogg_uint32_t currentno,
+ long m){
+ tremor_ogg_int64_t endsearched=end;
+ tremor_ogg_int64_t next=end;
+ tremor_ogg_page og={0,0,0,0};
+ tremor_ogg_int64_t ret;
+
+ /* the below guards against garbage seperating the last and
+ first pages of two links. */
+ while(searched<endsearched){
+ tremor_ogg_int64_t bisect;
+
+ if(endsearched-searched<CHUNKSIZE){
+ bisect=searched;
+ }else{
+ bisect=(searched+endsearched)/2;
+ }
+
+ _seek_helper(vf,bisect);
+ ret=_get_next_page(vf,&og,-1);
+ if(ret==OV_EREAD)return OV_EREAD;
+ if(ret<0 || tremor_ogg_page_serialno(&og)!=currentno){
+ endsearched=bisect;
+ if(ret>=0)next=ret;
+ }else{
+ searched=ret+og.header_len+og.body_len;
+ }
+ tremor_ogg_page_release(&og);
}
- (*serialno_list)[(*n)-1] = s;
-}
-
-/* returns nonzero if found */
-static int _lookup_serialno(ogg_uint32_t s, ogg_uint32_t *serialno_list, int n){
- if(serialno_list){
- while(n--){
- if(*serialno_list == s) return 1;
- serialno_list++;
- }
+ _seek_helper(vf,next);
+ ret=_get_next_page(vf,&og,-1);
+ if(ret==OV_EREAD)return OV_EREAD;
+
+ if(searched>=end || ret<0){
+ tremor_ogg_page_release(&og);
+ vf->links=m+1;
+ vf->offsets=_tremor_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
+ vf->serialnos=_tremor_ogg_malloc(vf->links*sizeof(*vf->serialnos));
+ vf->offsets[m+1]=searched;
+ }else{
+ ret=_bisect_forward_serialno(vf,next,vf->offset,
+ end,tremor_ogg_page_serialno(&og),m+1);
+ tremor_ogg_page_release(&og);
+ if(ret==OV_EREAD)return OV_EREAD;
}
+
+ vf->offsets[m]=begin;
+ vf->serialnos[m]=currentno;
return 0;
}
-static int _lookup_page_serialno(ogg_page *og, ogg_uint32_t *serialno_list, int n){
- ogg_uint32_t s = ogg_page_serialno(og);
- return _lookup_serialno(s,serialno_list,n);
-}
-
-/* performs the same search as _get_prev_page, but prefers pages of
- the specified serial number. If a page of the specified serialno is
- spotted during the seek-back-and-read-forward, it will return the
- info of last page of the matching serial number instead of the very
- last page. If no page of the specified serialno is seen, it will
- return the info of last page and alter *serialno. */
-static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin,
- ogg_uint32_t *serial_list, int serial_n,
- int *serialno, ogg_int64_t *granpos){
- ogg_page og;
- ogg_int64_t end=begin;
- ogg_int64_t ret;
-
- ogg_int64_t prefoffset=-1;
- ogg_int64_t offset=-1;
- ogg_int64_t ret_serialno=-1;
- ogg_int64_t ret_gran=-1;
-
- while(offset==-1){
- begin-=CHUNKSIZE;
- if(begin<0)
- begin=0;
-
- ret=_seek_helper(vf,begin);
- if(ret)return(ret);
-
- while(vf->offset<end){
- ret=_get_next_page(vf,&og,end-vf->offset);
- if(ret==OV_EREAD)return(OV_EREAD);
- if(ret<0){
- break;
- }else{
- ret_serialno=ogg_page_serialno(&og);
- ret_gran=ogg_page_granulepos(&og);
- offset=ret;
-
- if((ogg_uint32_t)ret_serialno == *serialno){
- prefoffset=ret;
- *granpos=ret_gran;
- }
-
- if(!_lookup_serialno((ogg_uint32_t)ret_serialno,serial_list,serial_n)){
- /* we fell off the end of the link, which means we seeked
- back too far and shouldn't have been looking in that link
- to begin with. If we found the preferred serial number,
- forget that we saw it. */
- prefoffset=-1;
- }
- }
- }
+static int _decode_clear(TremorOggVorbis_File *vf){
+ if(vf->ready_state==INITSET){
+ vorbis_dsp_destroy(vf->vd);
+ vf->vd=0;
+ vf->ready_state=STREAMSET;
}
-
- /* we're not interested in the page... just the serialno and granpos. */
- if(prefoffset>=0)return(prefoffset);
-
- *serialno = ret_serialno;
- *granpos = ret_gran;
- return(offset);
-
+
+ if(vf->ready_state>=STREAMSET){
+ vorbis_info_clear(&vf->vi);
+ vorbis_comment_clear(&vf->vc);
+ vf->ready_state=OPENED;
+ }
+ return 0;
}
-/* uses the local ogg_stream storage in vf; this is important for
+/* uses the local tremor_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,
- ogg_uint32_t **serialno_list, int *serialno_n,
- ogg_page *og_ptr){
- ogg_page og;
- ogg_packet op;
+/* consumes the page that's passed in (if any) */
+/* state is LINKSET upon successful return */
+
+static int _fetch_headers(TremorOggVorbis_File *vf,
+ vorbis_info *vi,
+ vorbis_comment *vc,
+ tremor_ogg_uint32_t *serialno,
+ tremor_ogg_page *og_ptr){
+ tremor_ogg_page og={0,0,0,0};
+ tremor_ogg_packet op={0,0,0,0,0,0};
int i,ret;
- int allbos=0;
+
+ if(vf->ready_state>OPENED)_decode_clear(vf);
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);
+ tremor_ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
+ if(llret==OV_EREAD)return OV_EREAD;
+ if(llret<0)return OV_ENOTVORBIS;
og_ptr=&og;
}
+ tremor_ogg_stream_reset_serialno(vf->os,tremor_ogg_page_serialno(og_ptr));
+ if(serialno)*serialno=vf->os->serialno;
+
+ /* extract the initial header from the first page and verify that the
+ Ogg bitstream is in fact Vorbis data */
+
vorbis_info_init(vi);
vorbis_comment_init(vc);
- vf->ready_state=OPENED;
-
- /* extract the serialnos of all BOS pages + the first set of vorbis
- headers we see in the link */
-
- while(ogg_page_bos(og_ptr)){
- if(serialno_list){
- if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
- /* a dupe serialnumber in an initial header packet set == invalid stream */
- if(*serialno_list)_ogg_free(*serialno_list);
- *serialno_list=0;
- *serialno_n=0;
- ret=OV_EBADHEADER;
- goto bail_header;
+
+ i=0;
+ while(i<3){
+ tremor_ogg_stream_pagein(vf->os,og_ptr);
+ while(i<3){
+ int result=tremor_ogg_stream_packetout(vf->os,&op);
+ if(result==0)break;
+ if(result==-1){
+ ret=OV_EBADHEADER;
+ goto bail_header;
}
-
- _add_serialno(og_ptr,serialno_list,serialno_n);
- }
-
- 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);
-
- if(ogg_stream_packetout(&vf->os,&op) > 0 &&
- vorbis_synthesis_idheader(&op)){
- /* vorbis header; continue setup */
- vf->ready_state=STREAMSET;
- if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
- ret=OV_EBADHEADER;
- goto bail_header;
- }
+ if((ret=vorbis_dsp_headerin(vi,vc,&op))){
+ goto bail_header;
}
+ i++;
}
-
- /* get next page */
- {
- ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
- if(llret==OV_EREAD){
- ret=OV_EREAD;
- goto bail_header;
- }
- if(llret<0){
- ret=OV_ENOTVORBIS;
- goto bail_header;
+ if(i<3)
+ if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
+ ret=OV_EBADHEADER;
+ goto bail_header;
}
-
- /* if this page also belongs to our vorbis stream, submit it and break */
- if(vf->ready_state==STREAMSET &&
- vf->os.serialno == ogg_page_serialno(og_ptr)){
- ogg_stream_pagein(&vf->os,og_ptr);
- break;
- }
- }
}
- if(vf->ready_state!=STREAMSET){
- ret = OV_ENOTVORBIS;
- goto bail_header;
- }
-
- while(1){
-
- i=0;
- while(i<2){ /* get a page loop */
-
- while(i<2){ /* get a packet loop */
-
- int result=ogg_stream_packetout(&vf->os,&op);
- if(result==0)break;
- if(result==-1){
- ret=OV_EBADHEADER;
- goto bail_header;
- }
-
- if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
- goto bail_header;
-
- i++;
- }
-
- while(i<2){
- if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
- ret=OV_EBADHEADER;
- goto bail_header;
- }
-
- /* if this page belongs to the correct stream, go parse it */
- if(vf->os.serialno == ogg_page_serialno(og_ptr)){
- ogg_stream_pagein(&vf->os,og_ptr);
- break;
- }
-
- /* if we never see the final vorbis headers before the link
- ends, abort */
- if(ogg_page_bos(og_ptr)){
- if(allbos){
- ret = OV_EBADHEADER;
- goto bail_header;
- }else
- allbos=1;
- }
-
- /* otherwise, keep looking */
- }
- }
-
- return 0;
- }
+ tremor_ogg_packet_release(&op);
+ tremor_ogg_page_release(&og);
+ vf->ready_state=LINKSET;
+ return 0;
bail_header:
+ tremor_ogg_packet_release(&op);
+ tremor_ogg_page_release(&og);
vorbis_info_clear(vi);
vorbis_comment_clear(vc);
vf->ready_state=OPENED;
@@ -409,401 +320,321 @@ static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
return ret;
}
-/* Starting from current cursor position, get initial PCM offset of
- next page. Consumes the page in the process without decoding
- 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;
- ogg_int64_t accumulated=0;
- long lastblock=-1;
- int result;
- int serialno = vf->os.serialno;
-
- while(1){
- 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)!=serialno) continue;
-
- /* count blocksizes of all frames in the page */
- 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)
- accumulated+=(lastblock+thisblock)>>2;
- lastblock=thisblock;
- }
- }
-
- if(ogg_page_granulepos(&og)!=-1){
- /* pcm offset of last packet on the first audio page */
- accumulated= ogg_page_granulepos(&og)-accumulated;
- break;
- }
+/* we no longer preload all vorbis_info (and the associated
+ codec_setup) structs. Call this to seek and fetch the info from
+ the bitstream, if needed */
+static int _set_link_number(TremorOggVorbis_File *vf,int link){
+ if(link != vf->current_link) _decode_clear(vf);
+ if(vf->ready_state<STREAMSET){
+ _seek_helper(vf,vf->offsets[link]);
+ tremor_ogg_stream_reset_serialno(vf->os,vf->serialnos[link]);
+ vf->current_serialno=vf->serialnos[link];
+ vf->current_link=link;
+ return _fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,NULL);
}
-
- /* less than zero? This is a stream with samples trimmed off
- the beginning, a normal occurrence; set the offset to zero */
- if(accumulated<0)accumulated=0;
-
- return accumulated;
+ return 0;
}
-/* 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
- finding them all, then unroll and fill the cache at the same time */
-static int _bisect_forward_serialno(OggVorbis_File *vf,
- ogg_int64_t begin,
- ogg_int64_t searched,
- ogg_int64_t end,
- ogg_int64_t endgran,
- int endserial,
- 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;
-
- /* invariants:
- we have the headers and serialnos for the link beginning at 'begin'
- we have the offset and granpos of the last page in the file (potentially
- not a page we care about)
- */
-
- /* Is the last page in our list of current serialnumbers? */
- if(_lookup_serialno(endserial,currentno_list,currentnos)){
-
- /* last page is in the starting serialno list, so we've bisected
- down to (or just started with) a single link. Now we need to
- find the last vorbis page belonging to the first vorbis stream
- for this link. */
- searched = end;
- while(endserial != serialno){
- endserial = serialno;
- searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran);
- }
-
- vf->links=m+1;
- if(vf->offsets)_ogg_free(vf->offsets);
- if(vf->serialnos)_ogg_free(vf->serialnos);
- if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
-
- vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
- vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
- vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
- vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
- vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
- vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
-
- vf->offsets[m+1]=end;
- vf->offsets[m]=begin;
- vf->pcmlengths[m*2+1]=(endgran<0?0:endgran);
-
- }else{
-
- /* last page is not in the starting stream's serial number list,
- so we have multiple links. Find where the stream that begins
- our bisection ends. */
-
- ogg_uint32_t *next_serialno_list=NULL;
- int next_serialnos=0;
- vorbis_info vi;
- vorbis_comment vc;
- int testserial = serialno+1;
+static int _set_link_number_preserve_pos(TremorOggVorbis_File *vf,int link){
+ tremor_ogg_int64_t pos=vf->offset;
+ int ret=_set_link_number(vf,link);
+ if(ret)return ret;
+ _seek_helper(vf,pos);
+ if(pos<vf->offsets[link] || pos>=vf->offsets[link+1])
+ vf->ready_state=STREAMSET;
+ return 0;
+}
- /* the below guards against garbage seperating the last and
- first pages of two links. */
- while(searched<endsearched){
- ogg_int64_t bisect;
+/* last step of the TremorOggVorbis_File initialization; get all the offset
+ positions. Only called by the seekable initialization (local
+ stream storage is hacked slightly; pay attention to how that's
+ done) */
+
+/* this is void and does not propogate errors up because we want to be
+ able to open and use damaged bitstreams as well as we can. Just
+ watch out for missing information for links in the TremorOggVorbis_File
+ struct */
+static void _prefetch_all_offsets(TremorOggVorbis_File *vf, tremor_ogg_int64_t dataoffset){
+ tremor_ogg_page og={0,0,0,0};
+ int i;
+ tremor_ogg_int64_t ret;
+
+ vf->dataoffsets=_tremor_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
+ vf->pcmlengths=_tremor_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
+
+ for(i=0;i<vf->links;i++){
+ if(i==0){
+ /* we already grabbed the initial header earlier. Just set the offset */
+ vf->dataoffsets[i]=dataoffset;
+ _seek_helper(vf,dataoffset);
- if(endsearched-searched<CHUNKSIZE){
- bisect=searched;
- }else{
- bisect=(searched+endsearched)/2;
- }
+ }else{
- ret=_seek_helper(vf,bisect);
- if(ret)return(ret);
+ /* seek to the location of the initial header */
- last=_get_next_page(vf,&og,-1);
- if(last==OV_EREAD)return(OV_EREAD);
- if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
- endsearched=bisect;
- if(last>=0)next=last;
+ _seek_helper(vf,vf->offsets[i]);
+ if(_fetch_headers(vf,&vf->vi,&vf->vc,NULL,NULL)<0){
+ vf->dataoffsets[i]=-1;
}else{
- searched=vf->offset;
+ vf->dataoffsets[i]=vf->offset;
}
}
- /* Bisection point found */
- /* for the time being, fetch end PCM offset the simple way */
- searched = next;
- while(testserial != serialno){
- testserial = serialno;
- searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran);
- }
-
- ret=_seek_helper(vf,next);
- if(ret)return(ret);
+ /* fetch beginning PCM offset */
- ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
- if(ret)return(ret);
- serialno = vf->os.serialno;
- dataoffset = vf->offset;
+ if(vf->dataoffsets[i]!=-1){
+ tremor_ogg_int64_t accumulated=0,pos;
+ long lastblock=-1;
+ int result;
- /* this will consume a page, however the next bisection always
- starts with a raw seek */
- pcmoffset = _initial_pcmoffset(vf,&vi);
+ tremor_ogg_stream_reset_serialno(vf->os,vf->serialnos[i]);
- ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
- next_serialno_list,next_serialnos,m+1);
- if(ret)return(ret);
-
- if(next_serialno_list)_ogg_free(next_serialno_list);
+ while(1){
+ tremor_ogg_packet op={0,0,0,0,0,0};
+
+ ret=_get_next_page(vf,&og,-1);
+ if(ret<0)
+ /* this should not be possible unless the file is
+ truncated/mangled */
+ break;
+
+ if(tremor_ogg_page_serialno(&og)!=vf->serialnos[i])
+ break;
+
+ pos=tremor_ogg_page_granulepos(&og);
+
+ /* count blocksizes of all frames in the page */
+ tremor_ogg_stream_pagein(vf->os,&og);
+ while((result=tremor_ogg_stream_packetout(vf->os,&op))){
+ if(result>0){ /* ignore holes */
+ long thisblock=vorbis_packet_blocksize(&vf->vi,&op);
+ if(lastblock!=-1)
+ accumulated+=(lastblock+thisblock)>>2;
+ lastblock=thisblock;
+ }
+ }
+ tremor_ogg_packet_release(&op);
+
+ if(pos!=-1){
+ /* pcm offset of last packet on the first audio page */
+ accumulated= pos-accumulated;
+ break;
+ }
+ }
- vf->offsets[m+1]=next;
- vf->serialnos[m+1]=serialno;
- vf->dataoffsets[m+1]=dataoffset;
+ /* less than zero? This is a stream with samples trimmed off
+ the beginning, a normal occurrence; set the offset to zero */
+ if(accumulated<0)accumulated=0;
- vf->vi[m+1]=vi;
- vf->vc[m+1]=vc;
+ vf->pcmlengths[i*2]=accumulated;
+ }
- vf->pcmlengths[m*2+1]=searchgran;
- vf->pcmlengths[m*2+2]=pcmoffset;
- vf->pcmlengths[m*2+3]-=pcmoffset;
- if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0;
+ /* get the PCM length of this link. To do this,
+ get the last page of the stream */
+ {
+ tremor_ogg_int64_t end=vf->offsets[i+1];
+ _seek_helper(vf,end);
+ while(1){
+ ret=_get_prev_page(vf,&og);
+ if(ret<0){
+ /* this should not be possible */
+ vorbis_info_clear(&vf->vi);
+ vorbis_comment_clear(&vf->vc);
+ break;
+ }
+ if(tremor_ogg_page_granulepos(&og)!=-1){
+ vf->pcmlengths[i*2+1]=tremor_ogg_page_granulepos(&og)-vf->pcmlengths[i*2];
+ break;
+ }
+ vf->offset=ret;
+ }
+ }
}
- return(0);
+ tremor_ogg_page_release(&og);
}
-static int _make_decode_ready(OggVorbis_File *vf){
- if(vf->ready_state>STREAMSET)return 0;
- if(vf->ready_state<STREAMSET)return OV_EFAULT;
- if(vf->seekable){
- if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
- return OV_EBADLINK;
- }else{
- if(vorbis_synthesis_init(&vf->vd,vf->vi))
- return OV_EBADLINK;
+static int _make_decode_ready(TremorOggVorbis_File *vf){
+ int i;
+ switch(vf->ready_state){
+ case OPENED:
+ case STREAMSET:
+ for(i=0;i<vf->links;i++)
+ if(vf->offsets[i+1]>=vf->offset)break;
+ if(i==vf->links)return -1;
+ i=_set_link_number_preserve_pos(vf,i);
+ if(i)return i;
+ /* fall through */
+ case LINKSET:
+ vf->vd=vorbis_dsp_create(&vf->vi);
+ vf->ready_state=INITSET;
+ vf->bittrack=0;
+ vf->samptrack=0;
+ case INITSET:
+ return 0;
+ default:
+ return -1;
}
- vorbis_block_init(&vf->vd,&vf->vb);
- vf->ready_state=INITSET;
- vf->bittrack=0;
- vf->samptrack=0;
- return 0;
+
}
-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;
+static int _open_seekable2(TremorOggVorbis_File *vf){
+ tremor_ogg_uint32_t serialno=vf->current_serialno;
+ tremor_ogg_uint32_t tempserialno;
+ tremor_ogg_int64_t dataoffset=vf->offset, end;
+ tremor_ogg_page og={0,0,0,0};
/* we're partially open and have a first link header state in
storage in vf */
-
- /* fetch initial PCM offset */
- ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
-
/* we can seek, so set out learning all about this file */
- if(vf->callbacks.seek_func && vf->callbacks.tell_func){
- (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
- vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
- }else{
- vf->offset=vf->end=-1;
- }
+ (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 TremorOggVorbis files will contain a single logical bitstream */
+ end=_get_prev_page(vf,&og);
+ if(end<0)return end;
- /* If seek_func is implemented, tell_func must also be implemented */
- if(vf->end==-1) return(OV_EINVAL);
+ /* more than one logical bitstream? */
+ tempserialno=tremor_ogg_page_serialno(&og);
+ tremor_ogg_page_release(&og);
- /* Get the offset of the last page of the physical bitstream, or, if
- we're lucky the last vorbis page of this link as most OggVorbis
- files will contain a single logical bitstream */
- end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
- if(end<0)return(end);
+ if(tempserialno!=serialno){
- /* now determine bitstream structure recursively */
- if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial,
- vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
+ /* 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;
- vf->offsets[0]=0;
- vf->serialnos[0]=serialno;
- vf->dataoffsets[0]=dataoffset;
- vf->pcmlengths[0]=pcmoffset;
- vf->pcmlengths[1]-=pcmoffset;
- if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0;
+ }else{
- return(ov_raw_seek(vf,dataoffset));
-}
+ /* Only one logical bitstream */
+ if(_bisect_forward_serialno(vf,0,end,end+1,serialno,0))return OV_EREAD;
-/* 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;
+ }
+
+ /* the initial header memory is referenced by vf after; don't free it */
+ _prefetch_all_offsets(vf,dataoffset);
+ return ov_raw_seek(vf,0);
}
/* 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).
+ 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
*/
-static int _fetch_and_process_packet(OggVorbis_File *vf,
- ogg_packet *op_in,
- int readp,
- int spanp){
- ogg_page og;
+static int _fetch_and_process_packet(TremorOggVorbis_File *vf,
+ int readp,
+ int spanp){
+ tremor_ogg_page og={0,0,0,0};
+ tremor_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){
-
- if(vf->ready_state==STREAMSET){
- 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) {
- 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;
-
- op_in=NULL;
- if(result==-1)return(OV_HOLE); /* hole in the data. */
- if(result>0){
- /* got a packet. process it */
- 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)return(OV_EFAULT);
-
- vorbis_synthesis_blockin(&vf->vd,&vf->vb);
- vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL);
- vf->bittrack+=op_ptr->bytes*8;
- }
-
- /* update the pcm offset. */
- 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
- 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_ptr->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;
- }
- return(1);
- }
- }
- else
- break;
+ int result=tremor_ogg_stream_packetout(vf->os,&op);
+ tremor_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_dsp_synthesis(vf->vd,&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 */
+
+ vf->samptrack+=vorbis_dsp_pcmout(vf->vd,NULL,0);
+ 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_dsp_pcmout(vf->vd,NULL,0);
+
+ 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){
- ogg_int64_t ret;
+ 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;
+ }
- while(1){
- /* the loop is not strictly necessary, but there's no sense in
- doing the extra checks of the larger loop for the common
- case in a multiplexed bistream where the page is simply
- part of a different logical bitstream; keep reading until
- we get one with the correct serialno */
-
- 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
- are done by packet above */
- vf->bittrack+=og.header_len*8;
-
- if(vf->ready_state==INITSET){
- 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 */
-
- if(ogg_page_bos(&og)){
- /* boundary case */
- if(!spanp)
- return(OV_EOF);
-
- _decode_clear(vf);
-
- if(!vf->seekable){
- vorbis_info_clear(vf->vi);
- vorbis_comment_clear(vf->vc);
- }
- break;
-
- }else
- continue; /* possibility #2 */
- }
- }
-
- break;
+ /* 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!=tremor_ogg_page_serialno(&og)){
+ if(!spanp){
+ ret=OV_EOF;
+ goto cleanup;
+ }
+
+ _decode_clear(vf);
+ }
}
}
/* 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
@@ -814,79 +645,80 @@ static int _fetch_and_process_packet(OggVorbis_File *vf,
we're now nominally at the header of the next bitstream
*/
- if(vf->ready_state!=INITSET){
- int link;
+ if(vf->ready_state!=INITSET){
+ int link,ret;
if(vf->ready_state<STREAMSET){
- if(vf->seekable){
- 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]==serialno)break;
-
- 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);
- 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)return(ret);
- vf->current_serialno=vf->os.serialno;
- vf->current_link++;
- link=0;
- }
+ if(vf->seekable){
+ vf->current_serialno=tremor_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;
+ ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og);
+ if(ret) goto cleanup;
+
+ }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++;
+ }
}
+
+ if(_make_decode_ready(vf)) return OV_EBADLINK;
}
-
- /* 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);
-
+ tremor_ogg_stream_pagein(vf->os,&og);
}
+ cleanup:
+ tremor_ogg_packet_release(&op);
+ tremor_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);
+static int _fseek64_wrap(FILE *f,tremor_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,const char *initial,
- long ibytes, ov_callbacks callbacks){
- 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;
+static int _ov_open1(void *f,TremorOggVorbis_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));
+
+ /* Tremor assumes in multiple places that right shift of a signed
+ integer is an arithmetic shift */
+ if( (-1>>1) != -1) return OV_EIMPL;
+
vf->datasource=f;
vf->callbacks = callbacks;
/* init the framing state */
- ogg_sync_init(&vf->oy);
+ vf->oy=tremor_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 (especially as we may be reading from a
- non-seekable stream) */
+ previously read data (as we may be reading from a non-seekable
+ stream) */
if(initial){
- char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
+ unsigned char *buffer=tremor_ogg_sync_bufferin(vf->oy,ibytes);
memcpy(buffer,initial,ibytes);
- ogg_sync_wrote(&vf->oy,ibytes);
+ tremor_ogg_sync_wrote(vf->oy,ibytes);
}
/* can we seek? Stevens suggests the seek test was portable */
@@ -895,154 +727,115 @@ static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
/* 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));
- ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
+ vf->os=tremor_ogg_stream_create(-1); /* fill in the serialno later */
- /* Fetch all BOS pages, store the vorbis header and all seen serial
- numbers, load subsequent vorbis setup headers */
- if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
+ /* 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{
- /* serial number list for first link needs to be held somewhere
- for second stage of seekable stream open; this saves having to
- seek/reread first link's serialnumber data then. */
- vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
- vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
- vf->serialnos[1]=serialno_list_size;
- memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
-
- vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
- vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
- vf->offsets[0]=0;
- vf->dataoffsets[0]=vf->offset;
-
+ }else if(vf->ready_state < PARTOPEN)
vf->ready_state=PARTOPEN;
- }
- if(serialno_list)_ogg_free(serialno_list);
- return(ret);
+ return ret;
}
-static int _ov_open2(OggVorbis_File *vf){
- if(vf->ready_state != PARTOPEN) return OV_EINVAL;
- vf->ready_state=OPENED;
+static int _ov_open2(TremorOggVorbis_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);
- }else
- vf->ready_state=STREAMSET;
-
+ return ret;
+ }
return 0;
}
-/* clear out the OggVorbis_File struct */
-int ov_clear(OggVorbis_File *vf){
+/* clear out the TremorOggVorbis_File struct */
+int ov_clear(TremorOggVorbis_File *vf){
if(vf){
- vorbis_block_clear(&vf->vb);
- vorbis_dsp_clear(&vf->vd);
- ogg_stream_clear(&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_clear(&vf->oy);
- if(vf->datasource && vf->callbacks.close_func)
- (vf->callbacks.close_func)(vf->datasource);
+ vorbis_dsp_destroy(vf->vd);
+ vf->vd=0;
+ tremor_ogg_stream_destroy(vf->os);
+ vorbis_info_clear(&vf->vi);
+ vorbis_comment_clear(&vf->vc);
+ if(vf->dataoffsets)_tremor_ogg_free(vf->dataoffsets);
+ if(vf->pcmlengths)_tremor_ogg_free(vf->pcmlengths);
+ if(vf->serialnos)_tremor_ogg_free(vf->serialnos);
+ if(vf->offsets)_tremor_ogg_free(vf->offsets);
+ tremor_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);
+ return 0;
}
-/* inspects the OggVorbis file and finds/documents all the logical
+/* inspects the TremorOggVorbis 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,
- const char *initial,long ibytes,ov_callbacks callbacks){
+int ov_open_callbacks(void *f,TremorOggVorbis_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,const char *initial,long ibytes){
+int ov_open(FILE *f,TremorOggVorbis_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 *, tremor_ogg_int64_t, int)) _fseek64_wrap,
(int (*)(void *)) fclose,
(long (*)(void *)) ftell
};
return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
}
-
-int ov_fopen(const char *path,OggVorbis_File *vf){
- int ret;
- FILE *f = fopen(path,"rb");
- if(!f) return -1;
-
- ret = ov_open(f,vf,NULL,0);
- if(ret) fclose(f);
- return ret;
-}
-
-
+
/* 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,
- const char *initial,long ibytes,ov_callbacks callbacks)
+int ov_test_callbacks(void *f,TremorOggVorbis_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,const char *initial,long ibytes){
+int ov_test(FILE *f,TremorOggVorbis_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 *, tremor_ogg_int64_t, int)) _fseek64_wrap,
(int (*)(void *)) fclose,
(long (*)(void *)) ftell
};
return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks);
}
-
-int ov_test_open(OggVorbis_File *vf){
- if(vf->ready_state!=PARTOPEN)return(OV_EINVAL);
+
+int ov_test_open(TremorOggVorbis_File *vf){
+ if(vf->ready_state!=PARTOPEN)return OV_EINVAL;
return _ov_open2(vf);
}
/* How many logical bitstreams in this physical bitstream? */
-long ov_streams(OggVorbis_File *vf){
+long ov_streams(TremorOggVorbis_File *vf){
return vf->links;
}
/* Is the FILE * associated with vf seekable? */
-long ov_seekable(OggVorbis_File *vf){
+long ov_seekable(TremorOggVorbis_File *vf){
return vf->seekable;
}
@@ -1055,12 +848,12 @@ long ov_seekable(OggVorbis_File *vf){
If you want the actual bitrate field settings, get them from the
vorbis_info structs */
-long ov_bitrate(OggVorbis_File *vf,int i){
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(i>=vf->links)return(OV_EINVAL);
- if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
+long ov_bitrate(TremorOggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return OV_EINVAL;
+ if(i>=vf->links)return OV_EINVAL;
+ if(!vf->seekable && i!=0)return ov_bitrate(vf,0);
if(i<0){
- ogg_int64_t bits=0;
+ tremor_ogg_int64_t bits=0;
int i;
for(i=0;i<vf->links;i++)
bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
@@ -1068,24 +861,24 @@ long ov_bitrate(OggVorbis_File *vf,int i){
* gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
* so this is slightly transformed to make it work.
*/
- return(bits*1000/ov_time_total(vf,-1));
+ return bits*1000/ov_time_total(vf,-1);
}else{
if(vf->seekable){
/* return the actual bitrate */
- return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));
+ return (vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i);
}else{
/* return nominal if set */
- if(vf->vi[i].bitrate_nominal>0){
- return vf->vi[i].bitrate_nominal;
+ if(vf->vi.bitrate_nominal>0){
+ return vf->vi.bitrate_nominal;
}else{
- if(vf->vi[i].bitrate_upper>0){
- if(vf->vi[i].bitrate_lower>0){
- return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
- }else{
- return vf->vi[i].bitrate_upper;
- }
- }
- return(OV_FALSE);
+ if(vf->vi.bitrate_upper>0){
+ if(vf->vi.bitrate_lower>0){
+ return (vf->vi.bitrate_upper+vf->vi.bitrate_lower)/2;
+ }else{
+ return vf->vi.bitrate_upper;
+ }
+ }
+ return OV_FALSE;
}
}
}
@@ -1093,84 +886,83 @@ long ov_bitrate(OggVorbis_File *vf,int i){
/* returns the actual bitrate since last call. returns -1 if no
additional data to offer since last call (or at beginning of stream),
- EINVAL if stream is only partially open
+ EINVAL if stream is only partially open
*/
-long ov_bitrate_instant(OggVorbis_File *vf){
- int link=(vf->seekable?vf->current_link:0);
+long ov_bitrate_instant(TremorOggVorbis_File *vf){
long ret;
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(vf->samptrack==0)return(OV_FALSE);
- ret=vf->bittrack/vf->samptrack*vf->vi[link].rate;
+ if(vf->ready_state<OPENED)return OV_EINVAL;
+ if(vf->samptrack==0)return OV_FALSE;
+ ret=vf->bittrack/vf->samptrack*vf->vi.rate;
vf->bittrack=0;
vf->samptrack=0;
- return(ret);
+ return ret;
}
/* Guess */
-long ov_serialnumber(OggVorbis_File *vf,int i){
- if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
- if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
+long ov_serialnumber(TremorOggVorbis_File *vf,int i){
+ if(i>=vf->links)return ov_serialnumber(vf,vf->links-1);
+ if(!vf->seekable && i>=0)return ov_serialnumber(vf,-1);
if(i<0){
- return(vf->current_serialno);
+ return vf->current_serialno;
}else{
- return(vf->serialnos[i]);
+ return vf->serialnos[i];
}
}
/* returns: total raw (compressed) length of content if i==-1
raw (compressed) length of that logical bitstream for i==0 to n
- OV_EINVAL if the stream is not seekable (we can't know the length)
- or if stream is only partially open
+ OV_EINVAL if the stream is not seekable (we can't know the length)
+ or if stream is only partially open
*/
-ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
+tremor_ogg_int64_t ov_raw_total(TremorOggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return OV_EINVAL;
+ if(!vf->seekable || i>=vf->links)return OV_EINVAL;
if(i<0){
- ogg_int64_t acc=0;
+ tremor_ogg_int64_t acc=0;
int i;
for(i=0;i<vf->links;i++)
acc+=ov_raw_total(vf,i);
- return(acc);
+ return acc;
}else{
- return(vf->offsets[i+1]-vf->offsets[i]);
+ return vf->offsets[i+1]-vf->offsets[i];
}
}
/* returns: total PCM length (samples) of content if i==-1 PCM length
- (samples) of that logical bitstream for i==0 to n
- OV_EINVAL if the stream is not seekable (we can't know the
- length) or only partially open
+ (samples) of that logical bitstream for i==0 to n
+ OV_EINVAL if the stream is not seekable (we can't know the
+ length) or only partially open
*/
-ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
+tremor_ogg_int64_t ov_pcm_total(TremorOggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return OV_EINVAL;
+ if(!vf->seekable || i>=vf->links)return OV_EINVAL;
if(i<0){
- ogg_int64_t acc=0;
+ tremor_ogg_int64_t acc=0;
int i;
for(i=0;i<vf->links;i++)
acc+=ov_pcm_total(vf,i);
- return(acc);
+ return acc;
}else{
- return(vf->pcmlengths[i*2+1]);
+ return vf->pcmlengths[i*2+1];
}
}
/* returns: total milliseconds of content if i==-1
milliseconds in that logical bitstream for i==0 to n
- OV_EINVAL if the stream is not seekable (we can't know the
- length) or only partially open
+ OV_EINVAL if the stream is not seekable (we can't know the
+ length) or only partially open
*/
-ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
+tremor_ogg_int64_t ov_time_total(TremorOggVorbis_File *vf,int i){
+ if(vf->ready_state<OPENED)return OV_EINVAL;
+ if(!vf->seekable || i>=vf->links)return OV_EINVAL;
if(i<0){
- ogg_int64_t acc=0;
+ tremor_ogg_int64_t acc=0;
int i;
for(i=0;i<vf->links;i++)
acc+=ov_time_total(vf,i);
- return(acc);
+ return acc;
}else{
- return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
+ return ((tremor_ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi.rate;
}
}
@@ -1181,33 +973,27 @@ 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;
- int ret;
-
- if(vf->ready_state<OPENED)return(OV_EINVAL);
+int ov_raw_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos){
+ tremor_ogg_stream_state *work_os=NULL;
+ tremor_ogg_page og={0,0,0,0};
+ tremor_ogg_packet op={0,0,0,0,0,0};
+
+ if(vf->ready_state<OPENED)return OV_EINVAL;
if(!vf->seekable)
- return(OV_ENOSEEK); /* don't dump machine if we can't seek */
-
- if(pos<0 || pos>vf->end)return(OV_EINVAL);
+ return OV_ENOSEEK; /* don't dump machine if we can't seek */
- /* 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 */
- }
+ if(pos<0 || pos>vf->end)return OV_EINVAL;
/* 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,
- vf->current_serialno); /* must set serialno */
- vorbis_synthesis_restart(&vf->vd);
-
- ret=_seek_helper(vf,pos);
- if(ret)goto seek_error;
+ tremor_ogg_stream_reset_serialno(vf->os,
+ vf->current_serialno); /* must set serialno */
+ vorbis_dsp_restart(vf->vd);
+
+ _seek_helper(vf,pos);
/* we need to make sure the pcm_offset is set, but we don't want to
advance the raw cursor past good packets just to get to the first
@@ -1216,428 +1002,281 @@ 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=0;
- int lastflag=0;
- int firstflag=0;
- ogg_int64_t pagepos=-1;
-
- 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 */
+ int thisblock;
+ int eosflag;
+ work_os=tremor_ogg_stream_create(vf->current_serialno); /* get the memory ready */
while(1){
if(vf->ready_state>=STREAMSET){
- /* snarf/scan a packet if we can */
- 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);
- 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
- 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);
- 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;
- if(vf->pcm_offset<0)vf->pcm_offset=0;
- break;
- }
- lastblock=thisblock;
- continue;
- }else
- ogg_stream_packetout(&vf->os,NULL);
- }
+ /* snarf/scan a packet if we can */
+ int result=tremor_ogg_stream_packetout(work_os,&op);
+
+ if(result>0){
+
+ if(vf->vi.codec_setup){
+ thisblock=vorbis_packet_blocksize(&vf->vi,&op);
+ if(thisblock<0){
+ tremor_ogg_stream_packetout(vf->os,NULL);
+ thisblock=0;
+ }else{
+
+ if(eosflag)
+ tremor_ogg_stream_packetout(vf->os,NULL);
+ else
+ if(lastblock)accblock+=(lastblock+thisblock)>>2;
+ }
+
+ if(op.granulepos!=-1){
+ int i,link=vf->current_link;
+ tremor_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;
+ break;
+ }
+ lastblock=thisblock;
+ continue;
+ }else
+ tremor_ogg_stream_packetout(vf->os,NULL);
+ }
}
-
+
if(!lastblock){
- pagepos=_get_next_page(vf,&og,-1);
- if(pagepos<0){
- vf->pcm_offset=ov_pcm_total(vf,-1);
- break;
- }
+ if(_get_next_page(vf,&og,-1)<0){
+ vf->pcm_offset=ov_pcm_total(vf,-1);
+ break;
+ }
}else{
- /* huh? Bogus stream with packets but no granulepos */
- 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? */
-
- if(ogg_page_bos(&og)){
- /* we traversed */
- _decode_clear(vf); /* clear out stream state */
- ogg_stream_clear(&work_os);
- } /* else, do nothing; next loop will scoop another page */
- }
+ /* huh? Bogus stream with packets but no granulepos */
+ vf->pcm_offset=-1;
+ break;
}
+
+ /* did we just grab a page from other than current link? */
+ if(vf->ready_state>=STREAMSET)
+ if(vf->current_serialno!=tremor_ogg_page_serialno(&og)){
+ _decode_clear(vf); /* clear out stream state */
+ tremor_ogg_stream_destroy(work_os);
+ }
if(vf->ready_state<STREAMSET){
- int link;
- ogg_uint32_t serialno = ogg_page_serialno(&og);
-
- for(link=0;link<vf->links;link++)
- 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,serialno);
- ogg_stream_reset_serialno(&work_os,serialno);
- vf->ready_state=STREAMSET;
- firstflag=(pagepos<=vf->dataoffsets[link]);
+ int link;
+
+ vf->current_serialno=tremor_ogg_page_serialno(&og);
+ for(link=0;link<vf->links;link++)
+ if(vf->serialnos[link]==vf->current_serialno)break;
+ if(link==vf->links)
+ goto seek_error; /* sign of a bogus stream. error out,
+ leave machine uninitialized */
+
+ /* need to initialize machine to this link */
+ {
+ int ret=_set_link_number_preserve_pos(vf,link);
+ if(ret) goto seek_error;
+ }
+ tremor_ogg_stream_reset_serialno(vf->os,vf->current_serialno);
+ tremor_ogg_stream_reset_serialno(work_os,vf->current_serialno);
+
+
+ }
+
+ {
+ tremor_ogg_page dup;
+ tremor_ogg_page_dup(&dup,&og);
+ eosflag=tremor_ogg_page_eos(&og);
+ tremor_ogg_stream_pagein(vf->os,&og);
+ tremor_ogg_stream_pagein(work_os,&dup);
}
-
- ogg_stream_pagein(&vf->os,&og);
- ogg_stream_pagein(&work_os,&og);
- lastflag=ogg_page_eos(&og);
-
}
}
- ogg_stream_clear(&work_os);
+ tremor_ogg_packet_release(&op);
+ tremor_ogg_page_release(&og);
+ tremor_ogg_stream_destroy(work_os);
vf->bittrack=0;
vf->samptrack=0;
- return(0);
+ return 0;
seek_error:
+ tremor_ogg_packet_release(&op);
+ tremor_ogg_page_release(&og);
+
/* dump the machine so we're in a known state */
vf->pcm_offset=-1;
- ogg_stream_clear(&work_os);
+ tremor_ogg_stream_destroy(work_os);
_decode_clear(vf);
return OV_EBADLINK;
}
-/* rescales the number x from the range of [0,from] to [0,to]
- x is in the range [0,from]
- from, to are in the range [1, 1<<62-1] */
-ogg_int64_t rescale64(ogg_int64_t x, ogg_int64_t from, ogg_int64_t to){
- ogg_int64_t frac=0;
- ogg_int64_t ret=0;
- int i;
- if(x >= from) return to;
- if(x <= 0) return 0;
-
- for(i=0;i<64;i++){
- if(x>=from){
- frac|=1;
- x-=from;
- }
- x<<=1;
- frac<<=1;
- }
-
- for(i=0;i<64;i++){
- if(frac & 1){
- ret+=to;
- }
- frac>>=1;
- ret>>=1;
- }
-
- return ret;
-}
-
/* 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 preceding the specified pos
+ Seek to the last [granule marked] page preceeding 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 ov_pcm_seek_page(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos){
int link=-1;
- ogg_int64_t result=0;
- ogg_int64_t total=ov_pcm_total(vf,-1);
-
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(!vf->seekable)return(OV_ENOSEEK);
-
- if(pos<0 || pos>total)return(OV_EINVAL);
-
+ tremor_ogg_int64_t result=0;
+ tremor_ogg_int64_t total=ov_pcm_total(vf,-1);
+ tremor_ogg_page og={0,0,0,0};
+ tremor_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];
if(pos>=total)break;
}
- /* Search within the logical bitstream for the page with the highest
- pcm_pos preceding pos. If we're looking for a position on the
- first page, bisection will halt without finding our position as
- it's before the first explicit granulepos fencepost. That case is
- handled separately below.
-
- 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) */
- /* new search algorithm originally by HB (Nicholas Vinen) */
-
- {
- ogg_int64_t end=vf->offsets[link+1];
- ogg_int64_t begin=vf->dataoffsets[link];
- ogg_int64_t begintime = vf->pcmlengths[link*2];
- ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
- ogg_int64_t target=pos-total+begintime;
- ogg_int64_t best=-1;
- int got_page=0;
-
- ogg_page og;
-
- /* if we have only one page, there will be no bisection. Grab the page here */
- if(begin==end){
- result=_seek_helper(vf,begin);
- if(result) goto seek_error;
+ if(link!=vf->current_link){
+ int ret=_set_link_number(vf,link);
+ if(ret) goto seek_error;
+ }else{
+ vorbis_dsp_restart(vf->vd);
+ }
- result=_get_next_page(vf,&og,1);
- if(result<0) goto seek_error;
+ tremor_ogg_stream_reset_serialno(vf->os,vf->serialnos[link]);
- got_page=1;
- }
+ /* search within the logical bitstream for the page with the highest
+ pcm_pos preceeding (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) */
- /* bisection loop */
+ /* new search algorithm by HB (Nicholas Vinen) */
+ {
+ tremor_ogg_int64_t end=vf->offsets[link+1];
+ tremor_ogg_int64_t begin=vf->offsets[link];
+ tremor_ogg_int64_t begintime = vf->pcmlengths[link*2];
+ tremor_ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
+ tremor_ogg_int64_t target=pos-total+begintime;
+ tremor_ogg_int64_t best=begin;
+
while(begin<end){
- ogg_int64_t bisect;
-
+ tremor_ogg_int64_t bisect;
+
if(end-begin<CHUNKSIZE){
- bisect=begin;
+ bisect=begin;
}else{
- /* take a (pretty decent) guess. */
- bisect=begin + rescale64(target-begintime,
- endtime-begintime,
- end-begin) - CHUNKSIZE;
- if(bisect<begin+CHUNKSIZE)
- bisect=begin;
+ /* take a (pretty decent) guess. */
+ bisect=begin +
+ (target-begintime)*(end-begin)/(endtime-begintime) - CHUNKSIZE;
+ if(bisect<=begin)
+ bisect=begin+1;
}
-
- result=_seek_helper(vf,bisect);
- if(result) goto seek_error;
-
- /* read loop within the bisection loop */
+
+ _seek_helper(vf,bisect);
+
while(begin<end){
- result=_get_next_page(vf,&og,end-vf->offset);
- if(result==OV_EREAD) goto seek_error;
- if(result<0){
- /* there is no next page! */
- if(bisect<=begin+1)
- /* No bisection left to perform. We've either found the
- best candidate already or failed. Exit loop. */
- end=begin;
- else{
- /* We tried to load a fraction of the last page; back up a
- bit and try to get the whole last page */
- if(bisect==0) goto seek_error;
- bisect-=CHUNKSIZE;
-
- /* don't repeat/loop on a read we've already performed */
- if(bisect<=begin)bisect=begin+1;
-
- /* seek and continue bisection */
- result=_seek_helper(vf,bisect);
- if(result) goto seek_error;
- }
- }else{
- ogg_int64_t granulepos;
- got_page=1;
-
- /* got a page. analyze it */
- /* only consider pages from primary vorbis stream */
- if(ogg_page_serialno(&og)!=vf->serialnos[link])
- continue;
-
- /* only consider pages with the granulepos set */
- granulepos=ogg_page_granulepos(&og);
- if(granulepos==-1)continue;
-
- if(granulepos<target){
- /* this page is a successful candidate! Set state */
-
- best=result; /* raw offset of packet with granulepos */
- begin=vf->offset; /* raw offset of next page */
- begintime=granulepos;
-
- /* if we're before our target but within a short distance,
- don't bisect; read forward */
- if(target-begintime>44100)break;
-
- bisect=begin; /* *not* begin + 1 as above */
- }else{
-
- /* This is one of our pages, but the granpos is
- post-target; it is not a bisection return
- candidate. (The only way we'd use it is if it's the
- first page in the stream; we handle that case later
- outside the bisection) */
- if(bisect<=begin+1){
- /* No bisection left to perform. We've either found the
- best candidate already or failed. Exit loop. */
- end=begin;
- }else{
- if(end==vf->offset){
- /* bisection read to the end; use the known page
- boundary (result) to update bisection, back up a
- little bit, and try again */
- end=result;
- bisect-=CHUNKSIZE;
- if(bisect<=begin)bisect=begin+1;
- result=_seek_helper(vf,bisect);
- if(result) goto seek_error;
- }else{
- /* Normal bisection */
- end=bisect;
- endtime=granulepos;
- break;
- }
- }
- }
- }
+ result=_get_next_page(vf,&og,end-vf->offset);
+ if(result==OV_EREAD) goto seek_error;
+ if(result<0){
+ if(bisect<=begin+1)
+ end=begin; /* found it */
+ else{
+ if(bisect==0) goto seek_error;
+ bisect-=CHUNKSIZE;
+ if(bisect<=begin)bisect=begin+1;
+ _seek_helper(vf,bisect);
+ }
+ }else{
+ tremor_ogg_int64_t granulepos=tremor_ogg_page_granulepos(&og);
+ if(granulepos==-1)continue;
+ if(granulepos<target){
+ 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{
+ if(bisect<=begin+1)
+ end=begin; /* found it */
+ else{
+ if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
+ end=result;
+ bisect-=CHUNKSIZE; /* an endless loop otherwise. */
+ if(bisect<=begin)bisect=begin+1;
+ _seek_helper(vf,bisect);
+ }else{
+ end=result;
+ endtime=granulepos;
+ break;
+ }
+ }
+ }
+ }
}
}
- /* Out of bisection: did it 'fail?' */
- if(best == -1){
-
- /* Check the 'looking for data in first page' special case;
- bisection would 'fail' because our search target was before the
- first PCM granule position fencepost. */
-
- if(got_page &&
- begin == vf->dataoffsets[link] &&
- ogg_page_serialno(&og)==vf->serialnos[link]){
-
- /* Yes, this is the beginning-of-stream case. We already have
- our page, right at the beginning of PCM data. Set state
- and return. */
-
- vf->pcm_offset=total;
-
- if(link!=vf->current_link){
- /* Different link; dump entire decode machine */
- _decode_clear(vf);
-
- vf->current_link=link;
- 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);
-
- }else
- goto seek_error;
-
- }else{
-
- /* Bisection found our page. seek to it, update pcm offset. Easier case than
- raw_seek, don't keep packets preceding granulepos. */
-
- ogg_page og;
- ogg_packet op;
-
+ /* found our page. seek to it, update pcm offset. Easier case than
+ raw_seek, don't keep packets preceeding granulepos. */
+ {
+
/* seek */
- result=_seek_helper(vf,best);
+ _seek_helper(vf,best);
vf->pcm_offset=-1;
- if(result) goto seek_error;
- result=_get_next_page(vf,&og,-1);
- if(result<0) goto seek_error;
-
- if(link!=vf->current_link){
- /* Different link; dump entire decode machine */
- _decode_clear(vf);
-
- vf->current_link=link;
- vf->current_serialno=vf->serialnos[link];
- vf->ready_state=STREAMSET;
-
- }else{
- vorbis_synthesis_restart(&vf->vd);
+
+ if(_get_next_page(vf,&og,-1)<0){
+ tremor_ogg_page_release(&og);
+ return OV_EOF; /* shouldn't happen */
}
- ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
- ogg_stream_pagein(&vf->os,&og);
+ tremor_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){
- /* No packet returned; we exited the bisection with 'best'
- pointing to a page with a granule position, so the packet
- finishing this page ('best') originated on a 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. */
- /* Do not rewind past the beginning of link data; if we do,
- it's either a bug or a broken stream */
- result=best;
- while(result>vf->dataoffsets[link]){
- result=_get_prev_page(vf,result,&og);
- if(result<0) goto seek_error;
- if(ogg_page_serialno(&og)==vf->current_serialno &&
- (ogg_page_granulepos(&og)>-1 ||
- !ogg_page_continued(&og))){
- return ov_raw_seek(vf,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);
+ result=tremor_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(tremor_ogg_page_granulepos(&og)>-1 ||
+ !tremor_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=tremor_ogg_stream_packetout(vf->os,NULL);
}
}
}
-
+
/* verify result */
if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
result=OV_EFAULT;
@@ -1645,89 +1284,98 @@ int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
}
vf->bittrack=0;
vf->samptrack=0;
- return(0);
+ tremor_ogg_page_release(&og);
+ tremor_ogg_packet_release(&op);
+ return 0;
+
seek_error:
+
+ tremor_ogg_page_release(&og);
+ tremor_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
+/* 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){
+int ov_pcm_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t pos){
+ tremor_ogg_packet op={0,0,0,0,0,0};
+ tremor_ogg_page og={0,0,0,0};
int thisblock,lastblock=0;
int ret=ov_pcm_seek_page(vf,pos);
- if(ret<0)return(ret);
- if((ret=_make_decode_ready(vf)))return ret;
+ if(ret<0)return ret;
+ if(_make_decode_ready(vf))return OV_EBADLINK;
/* 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=tremor_ogg_stream_packetpeek(vf->os,&op);
if(ret>0){
- thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
+ thisblock=vorbis_packet_blocksize(&vf->vi,&op);
if(thisblock<0){
- ogg_stream_packetout(&vf->os,NULL);
- continue; /* non audio packet */
+ tremor_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;
-
+ 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_trackonly(&vf->vb,&op); /* set up a vb with
- only tracking, no
- pcm_decode */
- vorbis_synthesis_blockin(&vf->vd,&vf->vb);
-
+ tremor_ogg_stream_packetout(vf->os,NULL);
+ vorbis_dsp_synthesis(vf->vd,&op,0); /* set up a vb with
+ only tracking, no
+ pcm_decode */
+
/* end of logical stream case is hard, especially with exact
- length positioning. */
-
+ 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];
+ 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(ogg_page_bos(&og))_decode_clear(vf);
-
+ if(vf->current_serialno!=tremor_ogg_page_serialno(&og))_decode_clear(vf);
+
if(vf->ready_state<STREAMSET){
- ogg_uint32_t serialno=ogg_page_serialno(&og);
- int link;
-
- for(link=0;link<vf->links;link++)
- if(vf->serialnos[link]==serialno)break;
- if(link==vf->links) continue;
- vf->current_link=link;
-
- vf->ready_state=STREAMSET;
- vf->current_serialno=ogg_page_serialno(&og);
- ogg_stream_reset_serialno(&vf->os,serialno);
- ret=_make_decode_ready(vf);
- if(ret)return ret;
- lastblock=0;
+ int link,ret;
+
+ vf->current_serialno=tremor_ogg_page_serialno(&og);
+ for(link=0;link<vf->links;link++)
+ if(vf->serialnos[link]==vf->current_serialno)break;
+ if(link==vf->links){
+ tremor_ogg_page_release(&og);
+ tremor_ogg_packet_release(&op);
+ return OV_EBADLINK;
+ }
+
+
+ vf->current_link=link;
+ ret=_fetch_headers(vf,&vf->vi,&vf->vc,&vf->current_serialno,&og);
+ if(ret) return ret;
+ if(_make_decode_ready(vf))return OV_EBADLINK;
+ lastblock=0;
}
- ogg_stream_pagein(&vf->os,&og);
+ tremor_ogg_stream_pagein(vf->os,&og);
}
}
@@ -1736,104 +1384,107 @@ int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
/* 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);
+ tremor_ogg_int64_t target=pos-vf->pcm_offset;
+ long samples=vorbis_dsp_pcmout(vf->vd,NULL,0);
if(samples>target)samples=target;
- vorbis_synthesis_read(&vf->vd,samples);
+ vorbis_dsp_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 */
+ if(_fetch_and_process_packet(vf,1,1)<=0)
+ vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
}
+
+ tremor_ogg_page_release(&og);
+ tremor_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){
+int ov_time_seek(TremorOggVorbis_File *vf,tremor_ogg_int64_t milliseconds){
/* translate time to PCM position and call ov_pcm_seek */
int link=-1;
- ogg_int64_t pcm_total=0;
- ogg_int64_t time_total=0;
-
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(!vf->seekable)return(OV_ENOSEEK);
- if(milliseconds<0)return(OV_EINVAL);
+ tremor_ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
+ tremor_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=0;link<vf->links;link++){
- ogg_int64_t addsec = ov_time_total(vf,link);
- if(milliseconds<time_total+addsec)break;
- time_total+=addsec;
- pcm_total+=vf->pcmlengths[link*2+1];
+ 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;
}
- if(link==vf->links)return(OV_EINVAL);
-
/* 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));
+ int ret=_set_link_number(vf,link);
+ if(ret)return ret;
+ return
+ ov_pcm_seek(vf,pcm_total+(milliseconds-time_total)*
+ vf->vi.rate/1000);
}
}
/* 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){
+int ov_time_seek_page(TremorOggVorbis_File *vf,tremor_ogg_int64_t milliseconds){
/* translate time to PCM position and call ov_pcm_seek */
int link=-1;
- ogg_int64_t pcm_total=0;
- ogg_int64_t time_total=0;
-
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- if(!vf->seekable)return(OV_ENOSEEK);
- if(milliseconds<0)return(OV_EINVAL);
+ tremor_ogg_int64_t pcm_total=ov_pcm_total(vf,-1);
+ tremor_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=0;link<vf->links;link++){
- ogg_int64_t addsec = ov_time_total(vf,link);
- if(milliseconds<time_total+addsec)break;
- time_total+=addsec;
- pcm_total+=vf->pcmlengths[link*2+1];
+ 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;
}
- if(link==vf->links)return(OV_EINVAL);
-
/* 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));
+ int ret=_set_link_number(vf,link);
+ if(ret)return ret;
+ return
+ ov_pcm_seek_page(vf,pcm_total+(milliseconds-time_total)*
+ vf->vi.rate/1000);
}
}
/* tell the current stream offset cursor. Note that seek followed by
tell will likely not give the set offset due to caching */
-ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- return(vf->offset);
+tremor_ogg_int64_t ov_raw_tell(TremorOggVorbis_File *vf){
+ if(vf->ready_state<OPENED)return OV_EINVAL;
+ return vf->offset;
}
/* return PCM offset (sample) of next PCM sample to be read */
-ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
- if(vf->ready_state<OPENED)return(OV_EINVAL);
- return(vf->pcm_offset);
+tremor_ogg_int64_t ov_pcm_tell(TremorOggVorbis_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 */
-ogg_int64_t ov_time_tell(OggVorbis_File *vf){
+tremor_ogg_int64_t ov_time_tell(TremorOggVorbis_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);
+ tremor_ogg_int64_t pcm_total=0;
+ tremor_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];
@@ -1842,50 +1493,38 @@ ogg_int64_t ov_time_tell(OggVorbis_File *vf){
}
}
- return(time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi[link].rate);
+ return time_total+(1000*vf->pcm_offset-pcm_total)/vf->vi.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 */
-vorbis_info *ov_info(OggVorbis_File *vf,int link){
+vorbis_info *ov_info(TremorOggVorbis_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;
+ if(link>=vf->links)return NULL;
+ if(link>=0){
+ int ret=_set_link_number_preserve_pos(vf,link);
+ if(ret)return NULL;
+ }
}
+ return &vf->vi;
}
/* grr, strong typing, grr, no templates/inheritence, grr */
-vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
+vorbis_comment *ov_comment(TremorOggVorbis_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;
+ if(link>=vf->links)return NULL;
+ if(link>=0){
+ int ret=_set_link_number_preserve_pos(vf,link);
+ if(ret)return NULL;
+ }
}
+ return &vf->vc;
}
/* up to this point, everything could more or less hide the multiple
@@ -1904,65 +1543,47 @@ vorbis_comment *ov_comment(OggVorbis_File *vf,int link){
functions above are aware of this dichotomy).
input values: buffer) a buffer to hold packed PCM data for return
- bytes_req) the byte length requested to be placed into buffer
+ 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.
+ 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 */
+ *section) set to the logical bitstream number */
-long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream){
- int i,j;
+long ov_read(TremorOggVorbis_File *vf,void *buffer,int bytes_req,int *bitstream){
- ogg_int32_t **pcm;
long samples;
+ long channels;
- if(vf->ready_state<OPENED)return(OV_EINVAL);
+ 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;
+ channels=vf->vi.channels;
+ samples=vorbis_dsp_pcmout(vf->vd,buffer,(bytes_req>>1)/channels);
+ if(samples){
+ if(samples>0){
+ vorbis_dsp_read(vf->vd,samples);
+ vf->pcm_offset+=samples;
+ if(bitstream)*bitstream=vf->current_link;
+ return samples*2*channels;
+ }
+ return samples;
+ }
}
/* suck in another packet */
{
- int ret=_fetch_and_process_packet(vf,NULL,1,1);
+ int ret=_fetch_and_process_packet(vf,1,1);
if(ret==OV_EOF)
- return(0);
+ return 0;
if(ret<=0)
- return(ret);
+ return ret;
}
}
-
- if(samples>0){
-
- /* yay! proceed to pack data into the byte buffer */
-
- long channels=ov_info(vf,-1)->channels;
-
- if(samples>(bytes_req/(2*channels)))
- samples=bytes_req/(2*channels);
-
- 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=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);
- }
}