summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorNils Wallménius <nils@rockbox.org>2010-12-06 14:36:52 +0000
committerNils Wallménius <nils@rockbox.org>2010-12-06 14:36:52 +0000
commit67efbc13870ee87ce3df442f7c396c13481921ec (patch)
treeeaf63d36c5bf2d41a6b3bb2addecb4d3c05f7eef /apps
parent1f64b7fb1fa5058e3b7871078055156eac0c511d (diff)
downloadrockbox-67efbc13870ee87ce3df442f7c396c13481921ec.tar.gz
rockbox-67efbc13870ee87ce3df442f7c396c13481921ec.tar.bz2
rockbox-67efbc13870ee87ce3df442f7c396c13481921ec.zip
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')
-rw-r--r--apps/codecs/libtremor/bitwise.c949
-rw-r--r--apps/codecs/libtremor/codebook.c18
-rw-r--r--apps/codecs/libtremor/framing.c2672
-rw-r--r--apps/codecs/libtremor/info.c4
-rw-r--r--apps/codecs/libtremor/ivorbisfile.h10
-rw-r--r--apps/codecs/libtremor/ogg.h387
-rw-r--r--apps/codecs/libtremor/synthesis.c6
-rw-r--r--apps/codecs/libtremor/vorbisfile.c509
8 files changed, 3102 insertions, 1453 deletions
diff --git a/apps/codecs/libtremor/bitwise.c b/apps/codecs/libtremor/bitwise.c
index dabba468b9..050fb67c60 100644
--- a/apps/codecs/libtremor/bitwise.c
+++ b/apps/codecs/libtremor/bitwise.c
@@ -1,28 +1,31 @@
/********************************************************************
* *
- * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
- * *
+ * THIS FILE IS PART OF THE Ogg CONTAINER 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-2002 *
- * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: packing variable sized words into an octet stream
+ last mod: $Id$
********************************************************************/
/* We're 'LSb' endian; if we write a word but read individual bits,
then we'll read the lsb first */
-#include "config-tremor.h"
#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
#include "ogg.h"
-const unsigned long oggpack_mask[] ICONST_ATTR =
+#define BUFFER_INCREMENT 256
+
+const unsigned long mask[] ICONST_ATTR =
{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
@@ -31,184 +34,832 @@ const unsigned long oggpack_mask[] ICONST_ATTR =
0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
0x3fffffff,0x7fffffff,0xffffffff };
-void oggpack_readinit(oggpack_buffer *b,ogg_reference *r){
+#if 0
+static const unsigned int mask8B[]=
+{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
+
+void oggpack_writeinit(oggpack_buffer *b){
memset(b,0,sizeof(*b));
+ b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT);
+ b->buffer[0]='\0';
+ b->storage=BUFFER_INCREMENT;
+}
+
+void oggpackB_writeinit(oggpack_buffer *b){
+ oggpack_writeinit(b);
+}
- b->tail=b->head=r;
- b->count=0;
- b->headptr=b->head->buffer->data+b->head->begin;
- b->headend=b->head->length;
- _span(b);
+int oggpack_writecheck(oggpack_buffer *b){
+ if(!b->ptr || !b->storage)return -1;
+ return 0;
}
-#define _lookspan() while(!end){\
- head=head->next;\
- if(!head) return -1;\
- ptr=head->buffer->data + head->begin;\
- end=head->length;\
- }
+int oggpackB_writecheck(oggpack_buffer *b){
+ return oggpack_writecheck(b);
+}
-/* Read in bits without advancing the bitptr; bits <= 32 */
-long oggpack_look_full(oggpack_buffer *b,int bits) ICODE_ATTR_TREMOR_NOT_MDCT;
-long oggpack_look_full(oggpack_buffer *b,int bits){
- unsigned long m=oggpack_mask[bits];
- unsigned long ret=-1;
-
- bits+=b->headbit;
-
- if(bits >= b->headend<<3){
- int end=b->headend;
- unsigned char *ptr=b->headptr;
- ogg_reference *head=b->head;
-
- if(end<0)return -1;
-
- if(bits){
- _lookspan();
- ret=*ptr++>>b->headbit;
- if(bits>8){
- --end;
- _lookspan();
- ret|=*ptr++<<(8-b->headbit);
- if(bits>16){
- --end;
- _lookspan();
- ret|=*ptr++<<(16-b->headbit);
- if(bits>24){
- --end;
- _lookspan();
- ret|=*ptr++<<(24-b->headbit);
- if(bits>32 && b->headbit){
- --end;
- _lookspan();
- ret|=*ptr<<(32-b->headbit);
- }
- }
+void oggpack_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ if(b->ptr){
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask[bits];
+ }
+}
+
+void oggpackB_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ if(b->ptr){
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask8B[bits];
+ }
+}
+
+/* Takes only up to 32 bits. */
+void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(bits<0 || bits>32) goto err;
+ if(b->endbyte>=b->storage-4){
+ void *ret;
+ if(!b->ptr)return;
+ if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
+ ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value&=mask[bits];
+ bits+=b->endbit;
+
+ b->ptr[0]|=value<<b->endbit;
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(8-b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(16-b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(24-b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value>>(32-b->endbit));
+ else
+ b->ptr[4]=0;
}
}
}
+ }
- }else{
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+/* Takes only up to 32 bits. */
+void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(bits<0 || bits>32) goto err;
+ if(b->endbyte>=b->storage-4){
+ void *ret;
+ if(!b->ptr)return;
+ if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
+ ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value=(value&mask[bits])<<(32-bits);
+ bits+=b->endbit;
- /* make this a switch jump-table */
- ret=b->headptr[0]>>b->headbit;
- if(bits>8){
- ret|=b->headptr[1]<<(8-b->headbit);
- if(bits>16){
- ret|=b->headptr[2]<<(16-b->headbit);
- if(bits>24){
- ret|=b->headptr[3]<<(24-b->headbit);
- if(bits>32 && b->headbit)
- ret|=b->headptr[4]<<(32-b->headbit);
+ b->ptr[0]|=value>>(24+b->endbit);
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(16+b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(8+b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value<<(8-b->endbit));
+ else
+ b->ptr[4]=0;
}
}
}
}
- ret&=m;
- return ret;
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+void oggpack_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpack_write(b,0,bits);
+}
+
+void oggpackB_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpackB_write(b,0,bits);
+}
+
+static void oggpack_writecopy_helper(oggpack_buffer *b,
+ void *source,
+ long bits,
+ void (*w)(oggpack_buffer *,
+ unsigned long,
+ int),
+ int msb){
+ unsigned char *ptr=(unsigned char *)source;
+
+ long bytes=bits/8;
+ bits-=bytes*8;
+
+ if(b->endbit){
+ int i;
+ /* unaligned copy. Do it the hard way. */
+ for(i=0;i<bytes;i++)
+ w(b,(unsigned long)(ptr[i]),8);
+ }else{
+ /* aligned block copy */
+ if(b->endbyte+bytes+1>=b->storage){
+ void *ret;
+ if(!b->ptr) goto err;
+ if(b->endbyte+bytes+BUFFER_INCREMENT>b->storage) goto err;
+ b->storage=b->endbyte+bytes+BUFFER_INCREMENT;
+ ret=_ogg_realloc(b->buffer,b->storage);
+ if(!ret) goto err;
+ b->buffer=ret;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ memmove(b->ptr,source,bytes);
+ b->ptr+=bytes;
+ b->endbyte+=bytes;
+ *b->ptr=0;
+
+ }
+ if(bits){
+ if(msb)
+ w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits);
+ else
+ w(b,(unsigned long)(ptr[bytes]),bits);
+ }
+ return;
+ err:
+ oggpack_writeclear(b);
+}
+
+void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpack_write,0);
+}
+
+void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpackB_write,1);
+}
+
+void oggpack_reset(oggpack_buffer *b){
+ if(!b->ptr)return;
+ b->ptr=b->buffer;
+ b->buffer[0]=0;
+ b->endbit=b->endbyte=0;
+}
+
+void oggpackB_reset(oggpack_buffer *b){
+ oggpack_reset(b);
+}
+
+void oggpack_writeclear(oggpack_buffer *b){
+ if(b->buffer)_ogg_free(b->buffer);
+ memset(b,0,sizeof(*b));
+}
+
+void oggpackB_writeclear(oggpack_buffer *b){
+ oggpack_writeclear(b);
}
+#endif
+void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ memset(b,0,sizeof(*b));
+ b->buffer=b->ptr=buf;
+ b->storage=bytes;
+}
+#if 0
+void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ oggpack_readinit(b,buf,bytes);
+}
+#endif
+/* Read in bits without advancing the bitptr; bits <= 32 */
+/* moved to ogg.h for inlining */
+#if 0
+long oggpack_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ unsigned long m;
+
+ if(bits<0 || bits>32) return -1;
+ m=mask[bits];
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
-/* spans forward and finds next byte. Never halts */
-static void _span_one(oggpack_buffer *b){
- while(b->headend<1){
- if(b->head->next){
- b->count+=b->head->length;
- b->head=b->head->next;
- b->headptr=b->head->buffer->data+b->head->begin;
- b->headend=b->head->length;
- }else
- break;
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
}
+ return(m&ret);
}
+#endif
+
+#if 0
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpackB_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ int m=32-bits;
+
+ if(m<0 || m>32) return -1;
+ bits+=b->endbit;
-static int _halt_one(oggpack_buffer *b){
- if(b->headend<1){
- _adv_halt(b);
- return -1;
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
}
- return 0;
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1);
+}
+#endif
+long oggpack_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>b->endbit)&1);
}
+#if 0
+long oggpackB_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>(7-b->endbit))&1);
+}
+#endif
+/* moved to ogg.h for inlining
+void oggpack_adv(oggpack_buffer *b,int bits){
+ bits+=b->endbit;
+
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return;
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+}
+*/
+#if 0
+void oggpackB_adv(oggpack_buffer *b,int bits){
+ oggpack_adv(b,bits);
+}
+#endif
+void oggpack_adv1(oggpack_buffer *b){
+ if(++(b->endbit)>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+}
+#if 0
+void oggpackB_adv1(oggpack_buffer *b){
+ oggpack_adv1(b);
+}
+#endif
/* bits <= 32 */
-long oggpack_read(oggpack_buffer *b,register int bits) ICODE_ATTR_TREMOR_NOT_MDCT;
-long oggpack_read(oggpack_buffer *b,register int bits){
- unsigned long m=oggpack_mask[bits];
- ogg_uint32_t ret=-1;
+long oggpack_read(oggpack_buffer *b,int bits) ICODE_ATTR_TREMOR_NOT_MDCT;
+long oggpack_read(oggpack_buffer *b,int bits){
+ long ret;
+ unsigned long m;
- bits+=b->headbit;
+ if(bits<0 || bits>32) goto err;
+ m=mask[bits];
+ bits+=b->endbit;
- if(bits >= b->headend<<3){
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
- if(b->headend<0)return -1;
-
- if(bits){
- if (_halt_one(b)) return -1;
- ret=*b->headptr>>b->headbit;
-
- if(bits>=8){
- ++b->headptr;
- --b->headend;
- _span_one(b);
- if(bits>8){
- if (_halt_one(b)) return -1;
- ret|=*b->headptr<<(8-b->headbit);
-
- if(bits>=16){
- ++b->headptr;
- --b->headend;
- _span_one(b);
- if(bits>16){
- if (_halt_one(b)) return -1;
- ret|=*b->headptr<<(16-b->headbit);
-
- if(bits>=24){
- ++b->headptr;
- --b->headend;
- _span_one(b);
- if(bits>24){
- if (_halt_one(b)) return -1;
- ret|=*b->headptr<<(24-b->headbit);
-
- if(bits>=32){
- ++b->headptr;
- --b->headend;
- _span_one(b);
- if(bits>32){
- if (_halt_one(b)) return -1;
- if(b->headbit)ret|=*b->headptr<<(32-b->headbit);
-
- }
- }
- }
- }
- }
- }
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit){
+ ret|=b->ptr[4]<<(32-b->endbit);
}
}
}
- }else{
+ }
+ ret&=m;
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return ret;
- ret=b->headptr[0]>>b->headbit;
- if(bits>8){
- ret|=b->headptr[1]<<(8-b->headbit);
- if(bits>16){
- ret|=b->headptr[2]<<(16-b->headbit);
- if(bits>24){
- ret|=b->headptr[3]<<(24-b->headbit);
- if(bits>32 && b->headbit){
- ret|=b->headptr[4]<<(32-b->headbit);
- }
- }
+ overflow:
+ err:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+#if 0
+/* bits <= 32 */
+long oggpackB_read(oggpack_buffer *b,int bits){
+ long ret;
+ long m=32-bits;
+
+ if(m<0 || m>32) goto err;
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
}
}
-
- b->headptr+=((unsigned)bits)/8;
- b->headend-=((unsigned)bits)/8;
}
+ ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1);
- ret&=m;
- b->headbit=bits&7;
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
return ret;
+
+ overflow:
+ err:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
}
+#endif
+long oggpack_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte >= b->storage) goto overflow;
+ ret=(b->ptr[0]>>b->endbit)&1;
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return ret;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+#if 0
+long oggpackB_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte >= b->storage) goto overflow;
+ ret=(b->ptr[0]>>(7-b->endbit))&1;
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return ret;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
+ return -1L;
+}
+
+long oggpack_bytes(oggpack_buffer *b){
+ return(b->endbyte+(b->endbit+7)/8);
+}
+
+long oggpack_bits(oggpack_buffer *b){
+ return(b->endbyte*8+b->endbit);
+}
+
+long oggpackB_bytes(oggpack_buffer *b){
+ return oggpack_bytes(b);
+}
+
+long oggpackB_bits(oggpack_buffer *b){
+ return oggpack_bits(b);
+}
+
+unsigned char *oggpack_get_buffer(oggpack_buffer *b){
+ return(b->buffer);
+}
+
+unsigned char *oggpackB_get_buffer(oggpack_buffer *b){
+ return oggpack_get_buffer(b);
+}
+#endif
+/* Self test of the bitwise routines; everything else is based on
+ them, so they damned well better be solid. */
+
+#ifdef _V_SELFTEST
+#include <stdio.h>
+
+static int ilog(unsigned int v){
+ int ret=0;
+ while(v){
+ ret++;
+ v>>=1;
+ }
+ return(ret);
+}
+
+oggpack_buffer o;
+oggpack_buffer r;
+
+void report(char *in){
+ fprintf(stderr,"%s",in);
+ exit(1);
+}
+
+void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpack_reset(&o);
+ for(i=0;i<vals;i++)
+ oggpack_write(&o,b[i],bits?bits:ilog(b[i]));
+ buffer=oggpack_get_buffer(&o);
+ bytes=oggpack_bytes(&o);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
+ for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
+ report("wrote incorrect value!\n");
+ }
+ oggpack_readinit(&r,buffer,bytes);
+ for(i=0;i<vals;i++){
+ int tbit=bits?bits:ilog(b[i]);
+ if(oggpack_look(&r,tbit)==-1)
+ report("out of data!\n");
+ if(oggpack_look(&r,tbit)!=(b[i]&mask[tbit]))
+ report("looked at incorrect value!\n");
+ if(tbit==1)
+ if(oggpack_look1(&r)!=(b[i]&mask[tbit]))
+ report("looked at single bit incorrect value!\n");
+ if(tbit==1){
+ if(oggpack_read1(&r)!=(b[i]&mask[tbit]))
+ report("read incorrect single bit value!\n");
+ }else{
+ if(oggpack_read(&r,tbit)!=(b[i]&mask[tbit]))
+ report("read incorrect value!\n");
+ }
+ }
+ if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+}
+
+void cliptestB(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpackB_reset(&o);
+ for(i=0;i<vals;i++)
+ oggpackB_write(&o,b[i],bits?bits:ilog(b[i]));
+ buffer=oggpackB_get_buffer(&o);
+ bytes=oggpackB_bytes(&o);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
+ for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
+ report("wrote incorrect value!\n");
+ }
+ oggpackB_readinit(&r,buffer,bytes);
+ for(i=0;i<vals;i++){
+ int tbit=bits?bits:ilog(b[i]);
+ if(oggpackB_look(&r,tbit)==-1)
+ report("out of data!\n");
+ if(oggpackB_look(&r,tbit)!=(b[i]&mask[tbit]))
+ report("looked at incorrect value!\n");
+ if(tbit==1)
+ if(oggpackB_look1(&r)!=(b[i]&mask[tbit]))
+ report("looked at single bit incorrect value!\n");
+ if(tbit==1){
+ if(oggpackB_read1(&r)!=(b[i]&mask[tbit]))
+ report("read incorrect single bit value!\n");
+ }else{
+ if(oggpackB_read(&r,tbit)!=(b[i]&mask[tbit]))
+ report("read incorrect value!\n");
+ }
+ }
+ if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+}
+
+int main(void){
+ unsigned char *buffer;
+ long bytes,i;
+ static unsigned long testbuffer1[]=
+ {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
+ 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
+ int test1size=43;
+
+ static unsigned long testbuffer2[]=
+ {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,346435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,349528352};
+ int test2size=21;
+
+ static unsigned long testbuffer3[]=
+ {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
+ 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
+ int test3size=56;
+
+ static unsigned long large[]=
+ {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,2146528352};
+
+ int onesize=33;
+ static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
+ 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
+ 223,4};
+ static int oneB[33]={150,101,131,33,203,15,204,216,105,193,156,65,84,85,222,
+ 8,139,145,227,126,34,55,244,171,85,100,39,195,173,18,
+ 245,251,128};
+
+ int twosize=6;
+ static int two[6]={61,255,255,251,231,29};
+ static int twoB[6]={247,63,255,253,249,120};
+
+ int threesize=54;
+ static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
+ 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
+ 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
+ 100,52,4,14,18,86,77,1};
+ static int threeB[54]={206,128,42,153,57,8,183,251,13,89,36,30,32,144,183,
+ 130,59,240,121,59,85,223,19,228,180,134,33,107,74,98,
+ 233,253,196,135,63,2,110,114,50,155,90,127,37,170,104,
+ 200,20,254,4,58,106,176,144,0};
+
+ int foursize=38;
+ static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
+ 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
+ 28,2,133,0,1};
+ static int fourB[38]={36,48,102,83,243,24,52,7,4,35,132,10,145,21,2,93,2,41,
+ 1,219,184,16,33,184,54,149,170,132,18,30,29,98,229,67,
+ 129,10,4,32};
+
+ int fivesize=45;
+ static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
+ 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
+ 84,75,159,2,1,0,132,192,8,0,0,18,22};
+ static int fiveB[45]={1,84,145,111,245,100,128,8,56,36,40,71,126,78,213,226,
+ 124,105,12,0,133,128,0,162,233,242,67,152,77,205,77,
+ 172,150,169,129,79,128,0,6,4,32,0,27,9,0};
+
+ int sixsize=7;
+ static int six[7]={17,177,170,242,169,19,148};
+ static int sixB[7]={136,141,85,79,149,200,41};
+
+ /* Test read/write together */
+ /* Later we test against pregenerated bitstreams */
+ oggpack_writeinit(&o);
+
+ fprintf(stderr,"\nSmall preclipped packing (LSb): ");
+ cliptest(testbuffer1,test1size,0,one,onesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nNull bit call (LSb): ");
+ cliptest(testbuffer3,test3size,0,two,twosize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge preclipped packing (LSb): ");
+ cliptest(testbuffer2,test2size,0,three,threesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\n32 bit preclipped packing (LSb): ");
+ oggpack_reset(&o);
+ for(i=0;i<test2size;i++)
+ oggpack_write(&o,large[i],32);
+ buffer=oggpack_get_buffer(&o);
+ bytes=oggpack_bytes(&o);
+ oggpack_readinit(&r,buffer,bytes);
+ for(i=0;i<test2size;i++){
+ if(oggpack_look(&r,32)==-1)report("out of data. failed!");
+ if(oggpack_look(&r,32)!=large[i]){
+ fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpack_look(&r,32),large[i],
+ oggpack_look(&r,32),large[i]);
+ report("read incorrect value!\n");
+ }
+ oggpack_adv(&r,32);
+ }
+ if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSmall unclipped packing (LSb): ");
+ cliptest(testbuffer1,test1size,7,four,foursize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge unclipped packing (LSb): ");
+ cliptest(testbuffer2,test2size,17,five,fivesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSingle bit unclipped packing (LSb): ");
+ cliptest(testbuffer3,test3size,1,six,sixsize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nTesting read past end (LSb): ");
+ oggpack_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ for(i=0;i<64;i++){
+ if(oggpack_read(&r,1)!=0){
+ fprintf(stderr,"failed; got -1 prematurely.\n");
+ exit(1);
+ }
+ }
+ if(oggpack_look(&r,1)!=-1 ||
+ oggpack_read(&r,1)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpack_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ if(oggpack_read(&r,30)!=0 || oggpack_read(&r,16)!=0){
+ fprintf(stderr,"failed 2; got -1 prematurely.\n");
+ exit(1);
+ }
+
+ if(oggpack_look(&r,18)!=0 ||
+ oggpack_look(&r,18)!=0){
+ fprintf(stderr,"failed 3; got -1 prematurely.\n");
+ exit(1);
+ }
+ if(oggpack_look(&r,19)!=-1 ||
+ oggpack_look(&r,19)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ if(oggpack_look(&r,32)!=-1 ||
+ oggpack_look(&r,32)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpack_writeclear(&o);
+ fprintf(stderr,"ok.\n");
+
+ /********** lazy, cut-n-paste retest with MSb packing ***********/
+
+ /* Test read/write together */
+ /* Later we test against pregenerated bitstreams */
+ oggpackB_writeinit(&o);
+
+ fprintf(stderr,"\nSmall preclipped packing (MSb): ");
+ cliptestB(testbuffer1,test1size,0,oneB,onesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nNull bit call (MSb): ");
+ cliptestB(testbuffer3,test3size,0,twoB,twosize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge preclipped packing (MSb): ");
+ cliptestB(testbuffer2,test2size,0,threeB,threesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\n32 bit preclipped packing (MSb): ");
+ oggpackB_reset(&o);
+ for(i=0;i<test2size;i++)
+ oggpackB_write(&o,large[i],32);
+ buffer=oggpackB_get_buffer(&o);
+ bytes=oggpackB_bytes(&o);
+ oggpackB_readinit(&r,buffer,bytes);
+ for(i=0;i<test2size;i++){
+ if(oggpackB_look(&r,32)==-1)report("out of data. failed!");
+ if(oggpackB_look(&r,32)!=large[i]){
+ fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpackB_look(&r,32),large[i],
+ oggpackB_look(&r,32),large[i]);
+ report("read incorrect value!\n");
+ }
+ oggpackB_adv(&r,32);
+ }
+ if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSmall unclipped packing (MSb): ");
+ cliptestB(testbuffer1,test1size,7,fourB,foursize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge unclipped packing (MSb): ");
+ cliptestB(testbuffer2,test2size,17,fiveB,fivesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSingle bit unclipped packing (MSb): ");
+ cliptestB(testbuffer3,test3size,1,sixB,sixsize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nTesting read past end (MSb): ");
+ oggpackB_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ for(i=0;i<64;i++){
+ if(oggpackB_read(&r,1)!=0){
+ fprintf(stderr,"failed; got -1 prematurely.\n");
+ exit(1);
+ }
+ }
+ if(oggpackB_look(&r,1)!=-1 ||
+ oggpackB_read(&r,1)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpackB_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
+ if(oggpackB_read(&r,30)!=0 || oggpackB_read(&r,16)!=0){
+ fprintf(stderr,"failed 2; got -1 prematurely.\n");
+ exit(1);
+ }
+
+ if(oggpackB_look(&r,18)!=0 ||
+ oggpackB_look(&r,18)!=0){
+ fprintf(stderr,"failed 3; got -1 prematurely.\n");
+ exit(1);
+ }
+ if(oggpackB_look(&r,19)!=-1 ||
+ oggpackB_look(&r,19)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ if(oggpackB_look(&r,32)!=-1 ||
+ oggpackB_look(&r,32)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpackB_writeclear(&o);
+ fprintf(stderr,"ok.\n\n");
+
+
+ return(0);
+}
+#endif /* _V_SELFTEST */
+#undef BUFFER_INCREMENT
diff --git a/apps/codecs/libtremor/codebook.c b/apps/codecs/libtremor/codebook.c
index 561b597aeb..860cf07bad 100644
--- a/apps/codecs/libtremor/codebook.c
+++ b/apps/codecs/libtremor/codebook.c
@@ -279,7 +279,7 @@ static long decode_packed_block(codebook *book, oggpack_buffer *b,
long *bufend = buf + n;
while (bufptr<bufend) {
- if (b->headend > 8) {
+ if(b->endbyte < b->storage - 8) {
ogg_uint32_t *ptr;
unsigned long bit, bitend;
unsigned long adr;
@@ -292,10 +292,10 @@ static long decode_packed_block(codebook *book, oggpack_buffer *b,
const ogg_uint32_t *book_codelist = book->codelist;
const char *book_dec_codelengths = book->dec_codelengths;
- adr = (unsigned long)b->headptr;
- bit = (adr&3)*8+b->headbit;
+ adr = (unsigned long)b->ptr;
+ bit = (adr&3)*8+b->endbit;
ptr = (ogg_uint32_t*)(adr&~3);
- bitend = ((adr&3)+b->headend)*8;
+ bitend = ((adr&3)+(b->storage-b->endbyte))*8;
while (bufptr<bufend){
if (UNLIKELY(cachesize<book_dec_maxlength)) {
if (bit-cachesize+32>=bitend)
@@ -323,11 +323,11 @@ static long decode_packed_block(codebook *book, oggpack_buffer *b,
cache >>= l;
}
- adr=(unsigned long)b->headptr;
+ adr=(unsigned long)b->ptr;
bit-=(adr&3)*8+cachesize;
- b->headend-=(bit/8);
- b->headptr+=bit/8;
- b->headbit=bit%8;
+ b->endbyte+=bit/8;
+ b->ptr+=bit/8;
+ b->endbit=bit&7;
} else {
long r = decode_packed_entry_number(book, b);
if (r == -1) return bufptr-buf;
@@ -337,7 +337,6 @@ static long decode_packed_block(codebook *book, oggpack_buffer *b,
return n;
}
-
/* Decode side is specced and easier, because we don't need to find
matches using different criteria; we simply read and map. There are
two things we need to do 'depending':
@@ -570,3 +569,4 @@ long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,
}
return(0);
}
+
diff --git a/apps/codecs/libtremor/framing.c b/apps/codecs/libtremor/framing.c
index ac95831d5d..a40e8dec65 100644
--- a/apps/codecs/libtremor/framing.c
+++ b/apps/codecs/libtremor/framing.c
@@ -1,17 +1,18 @@
/********************************************************************
* *
- * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
- * *
+ * THIS FILE IS PART OF THE Ogg CONTAINER 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-2003 *
- * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
- function: decode Ogg streams back into raw packets
+ function: code raw packets into framed OggSquish stream and
+ decode Ogg streams back into raw packets
+ last mod: $Id$
note: The CRC code is directly derived from public domain code by
Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
@@ -19,458 +20,102 @@
********************************************************************/
-#include "config-tremor.h"
+#include <stdlib.h>
#include <string.h>
#include "ogg.h"
-#include "misc.h"
-
/* A complete description of Ogg framing exists in docs/framing.html */
-/* basic, centralized Ogg memory management based on linked lists of
- references to refcounted memory buffers. References and buffers
- are both recycled. Buffers are passed around and consumed in
- reference form. */
-
-static ogg_buffer_state *ogg_buffer_create(void){
- ogg_buffer_state *bs=_ogg_calloc(1,sizeof(*bs));
- return bs;
-}
-
-/* destruction is 'lazy'; there may be memory references outstanding,
- and yanking the buffer state out from underneath would be
- antisocial. Dealloc what is currently unused and have
- _release_one watch for the stragglers to come in. When they do,
- finish destruction. */
-
-/* call the helper while holding lock */
-static void _ogg_buffer_destroy(ogg_buffer_state *bs){
- ogg_buffer *bt;
- ogg_reference *rt;
-
- if(bs->shutdown){
-
- bt=bs->unused_buffers;
- rt=bs->unused_references;
-
- while(bt){
- ogg_buffer *b=bt;
- bt=b->ptr.next;
- if(b->data)_ogg_free(b->data);
- _ogg_free(b);
- }
- bs->unused_buffers=0;
- while(rt){
- ogg_reference *r=rt;
- rt=r->next;
- _ogg_free(r);
- }
- bs->unused_references=0;
-
- if(!bs->outstanding)
- _ogg_free(bs);
-
- }
-}
-
-static void ogg_buffer_destroy(ogg_buffer_state *bs){
- bs->shutdown=1;
- _ogg_buffer_destroy(bs);
-}
-
-static ogg_buffer *_fetch_buffer(ogg_buffer_state *bs,long bytes){
- ogg_buffer *ob;
- bs->outstanding++;
-
- /* do we have an unused buffer sitting in the pool? */
- if(bs->unused_buffers){
- ob=bs->unused_buffers;
- bs->unused_buffers=ob->ptr.next;
-
- /* if the unused buffer is too small, grow it */
- if(ob->size<bytes){
- ob->data=_ogg_realloc(ob->data,bytes);
- ob->size=bytes;
- }
- }else{
- /* allocate a new buffer */
- ob=_ogg_malloc(sizeof(*ob));
- ob->data=_ogg_malloc(bytes<16?16:bytes);
- ob->size=bytes;
- }
-
- ob->refcount=1;
- ob->ptr.owner=bs;
- return ob;
-}
-
-STATICIRAM_NOT_MDCT ogg_reference *_fetch_ref(ogg_buffer_state *bs)
- ICODE_ATTR_TREMOR_NOT_MDCT;
-STATICIRAM_NOT_MDCT ogg_reference *_fetch_ref(ogg_buffer_state *bs){
- ogg_reference *or;
- bs->outstanding++;
-
- /* do we have an unused reference sitting in the pool? */
- if(bs->unused_references){
- or=bs->unused_references;
- bs->unused_references=or->next;
- }else{
- /* allocate a new reference */
- or=_ogg_malloc(sizeof(*or));
- }
-
- or->begin=0;
- or->length=0;
- or->next=0;
- return or;
-}
-
-/* fetch a reference pointing to a fresh, initially continguous buffer
- of at least [bytes] length */
-static ogg_reference *ogg_buffer_alloc(ogg_buffer_state *bs,long bytes){
- ogg_buffer *ob=_fetch_buffer(bs,bytes);
- ogg_reference *or=_fetch_ref(bs);
- or->buffer=ob;
- return or;
-}
-
-/* enlarge the data buffer in the current link */
-static void ogg_buffer_realloc(ogg_reference *or,long bytes){
- ogg_buffer *ob=or->buffer;
-
- /* if the unused buffer is too small, grow it */
- if(ob->size<bytes){
- ob->data=_ogg_realloc(ob->data,bytes);
- ob->size=bytes;
- }
+int ogg_page_version(const ogg_page *og){
+ return((int)(og->header[4]));
}
-static void _ogg_buffer_mark_one(ogg_reference *or){
- or->buffer->refcount++;
+int ogg_page_continued(const ogg_page *og){
+ return((int)(og->header[5]&0x01));
}
-/* increase the refcount of the buffers to which the reference points */
-static void ogg_buffer_mark(ogg_reference *or){
- while(or){
- _ogg_buffer_mark_one(or);
- or=or->next;
- }
+int ogg_page_bos(const ogg_page *og){
+ return((int)(og->header[5]&0x02));
}
-/* duplicate a reference (pointing to the same actual buffer memory)
- and increment buffer refcount. If the desired segment begins out
- of range, NULL is returned; if the desired segment is simply zero
- length, a zero length ref is returned. Partial range overlap
- returns the overlap of the ranges */
-static ogg_reference *ogg_buffer_sub(ogg_reference *or,long begin,long length){
- ogg_reference *ret=0,*head=0;
-
- /* walk past any preceeding fragments we don't want */
- while(or && begin>=or->length){
- begin-=or->length;
- or=or->next;
- }
-
- /* duplicate the reference chain; increment refcounts */
- while(or && length){
- ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner);
- if(head)
- head->next=temp;
- else
- ret=temp;
- head=temp;
- head->buffer=or->buffer;
- head->begin=or->begin+begin;
- head->length=length;
- if(head->length>or->length-begin)
- head->length=or->length-begin;
-
- begin=0;
- length-=head->length;
- or=or->next;
- }
-
- ogg_buffer_mark(ret);
- return ret;
+int ogg_page_eos(const ogg_page *og){
+ return((int)(og->header[5]&0x04));
}
-static ogg_reference *ogg_buffer_dup(ogg_reference *or){
- ogg_reference *ret=0,*head=0;
- /* duplicate the reference chain; increment refcounts */
- while(or){
- ogg_reference *temp=_fetch_ref(or->buffer->ptr.owner);
- if(head)
- head->next=temp;
- else
- ret=temp;
- head=temp;
- head->buffer=or->buffer;
- head->begin=or->begin;
- head->length=or->length;
- or=or->next;
- }
-
- ogg_buffer_mark(ret);
- return ret;
+ogg_int64_t ogg_page_granulepos(const ogg_page *og){
+ unsigned char *page=og->header;
+ ogg_int64_t granulepos=page[13]&(0xff);
+ granulepos= (granulepos<<8)|(page[12]&0xff);
+ granulepos= (granulepos<<8)|(page[11]&0xff);
+ granulepos= (granulepos<<8)|(page[10]&0xff);
+ granulepos= (granulepos<<8)|(page[9]&0xff);
+ granulepos= (granulepos<<8)|(page[8]&0xff);
+ granulepos= (granulepos<<8)|(page[7]&0xff);
+ granulepos= (granulepos<<8)|(page[6]&0xff);
+ return(granulepos);
}
-/* split a reference into two references; 'return' is a reference to
- the buffer preceeding pos and 'head'/'tail' are the buffer past the
- split. If pos is at or past the end of the passed in segment,
- 'head/tail' are NULL */
-static ogg_reference *ogg_buffer_split(ogg_reference **tail,
- ogg_reference **head,long pos){
-
- /* walk past any preceeding fragments to one of:
- a) the exact boundary that seps two fragments
- b) the fragment that needs split somewhere in the middle */
- ogg_reference *ret=*tail;
- ogg_reference *or=*tail;
-
- while(or && pos>or->length){
- pos-=or->length;
- or=or->next;
- }
-
- if(!or || pos==0){
-
- return 0;
-
- }else{
-
- if(pos>=or->length){
- /* exact split, or off the end? */
- if(or->next){
-
- /* a split */
- *tail=or->next;
- or->next=0;
-
- }else{
-
- /* off or at the end */
- *tail=*head=0;
-
- }
- }else{
-
- /* split within a fragment */
- long lengthA=pos;
- long beginB=or->begin+pos;
- long lengthB=or->length-pos;
-
- /* make a new reference to tail the second piece */
- *tail=_fetch_ref(or->buffer->ptr.owner);
-
- (*tail)->buffer=or->buffer;
- (*tail)->begin=beginB;
- (*tail)->length=lengthB;
- (*tail)->next=or->next;
- _ogg_buffer_mark_one(*tail);
- if(head && or==*head)*head=*tail;
-
- /* update the first piece */
- or->next=0;
- or->length=lengthA;
-
- }
- }
- return ret;
-}
-
-static void ogg_buffer_release_one(ogg_reference *or){
- ogg_buffer *ob=or->buffer;
- ogg_buffer_state *bs=ob->ptr.owner;
-
- ob->refcount--;
- if(ob->refcount==0){
- bs->outstanding--; /* for the returned buffer */
- ob->ptr.next=bs->unused_buffers;
- bs->unused_buffers=ob;
- }
-
- bs->outstanding--; /* for the returned reference */
- or->next=bs->unused_references;
- bs->unused_references=or;
-
- _ogg_buffer_destroy(bs); /* lazy cleanup (if needed) */
-
-}
-
-/* release the references, decrease the refcounts of buffers to which
- they point, release any buffers with a refcount that drops to zero */
-static void ogg_buffer_release(ogg_reference *or){
- while(or){
- ogg_reference *next=or->next;
- ogg_buffer_release_one(or);
- or=next;
- }
-}
-
-static ogg_reference *ogg_buffer_pretruncate(ogg_reference *or,long pos){
- /* release preceeding fragments we don't want */
- while(or && pos>=or->length){
- ogg_reference *next=or->next;
- pos-=or->length;
- ogg_buffer_release_one(or);
- or=next;
- }
- if (or) {
- or->begin+=pos;
- or->length-=pos;
- }
- return or;
-}
-
-static ogg_reference *ogg_buffer_walk(ogg_reference *or){
- if(!or)return NULL;
- while(or->next){
- or=or->next;
- }
- return(or);
-}
-
-/* *head is appended to the front end (head) of *tail; both continue to
- be valid pointers, with *tail at the tail and *head at the head */
-static ogg_reference *ogg_buffer_cat(ogg_reference *tail, ogg_reference *head){
- if(!tail)return head;
-
- while(tail->next){
- tail=tail->next;
- }
- tail->next=head;
- return ogg_buffer_walk(head);
-}
-
-static void _positionB(oggbyte_buffer *b,int pos){
- if(pos<b->pos){
- /* start at beginning, scan forward */
- b->ref=b->baseref;
- b->pos=0;
- b->end=b->pos+b->ref->length;
- b->ptr=b->ref->buffer->data+b->ref->begin;
- }
-}
-
-static void _positionF(oggbyte_buffer *b,int pos){
- /* scan forward for position */
- while(pos>=b->end){
- /* just seek forward */
- b->pos+=b->ref->length;
- b->ref=b->ref->next;
- b->end=b->ref->length+b->pos;
- b->ptr=b->ref->buffer->data+b->ref->begin;
- }
-}
-
-static int oggbyte_init(oggbyte_buffer *b,ogg_reference *or){
- memset(b,0,sizeof(*b));
- if(or){
- b->ref=b->baseref=or;
- b->pos=0;
- b->end=b->ref->length;
- b->ptr=b->ref->buffer->data+b->ref->begin;
- return 0;
- }else
- return -1;
-}
-
-static void oggbyte_set4(oggbyte_buffer *b,ogg_uint32_t val,int pos){
- int i;
- _positionB(b,pos);
- for(i=0;i<4;i++){
- _positionF(b,pos);
- b->ptr[pos-b->pos]=val;
- val>>=8;
- ++pos;
- }
+ogg_uint32_t ogg_page_serialno(const ogg_page *og){
+ return(og->header[14] |
+ (og->header[15]<<8) |
+ (og->header[16]<<16) |
+ (og->header[17]<<24));
}
-static unsigned char oggbyte_read1(oggbyte_buffer *b,int pos){
- _positionB(b,pos);
- _positionF(b,pos);
- return b->ptr[pos-b->pos];
-}
-
-static ogg_uint32_t oggbyte_read4(oggbyte_buffer *b,int pos){
- ogg_uint32_t ret;
- _positionB(b,pos);
- _positionF(b,pos);
- ret=b->ptr[pos-b->pos];
- _positionF(b,++pos);
- ret|=b->ptr[pos-b->pos]<<8;
- _positionF(b,++pos);
- ret|=b->ptr[pos-b->pos]<<16;
- _positionF(b,++pos);
- ret|=b->ptr[pos-b->pos]<<24;
- return ret;
+long ogg_page_pageno(const ogg_page *og){
+ return(og->header[18] |
+ (og->header[19]<<8) |
+ (og->header[20]<<16) |
+ (og->header[21]<<24));
}
-static ogg_int64_t oggbyte_read8(oggbyte_buffer *b,int pos){
- ogg_int64_t ret;
- unsigned char t[7];
- int i;
- _positionB(b,pos);
- for(i=0;i<7;i++){
- _positionF(b,pos);
- t[i]=b->ptr[pos++ -b->pos];
- }
- _positionF(b,pos);
- ret=b->ptr[pos-b->pos];
- for(i=6;i>=0;--i)
- ret= ret<<8 | t[i];
+/* returns the number of packets that are completed on this page (if
+ the leading packet is begun on a previous page, but ends on this
+ page, it's counted */
- return ret;
-}
+/* NOTE:
+If a page consists of a packet begun on a previous page, and a new
+packet begun (but not completed) on this page, the return will be:
+ ogg_page_packets(page) ==1,
+ ogg_page_continued(page) !=0
-/* Now we get to the actual framing code */
-
-int ogg_page_version(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read1(&ob,4);
-}
+If a page happens to be a single packet that was begun on a
+previous page, and spans to the next page (in the case of a three or
+more page packet), the return will be:
+ ogg_page_packets(page) ==0,
+ ogg_page_continued(page) !=0
+*/
-int ogg_page_continued(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read1(&ob,5)&0x01;
+int ogg_page_packets(const ogg_page *og){
+ int i,n=og->header[26],count=0;
+ for(i=0;i<n;i++)
+ if(og->header[27+i]<255)count++;
+ return(count);
}
-int ogg_page_bos(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read1(&ob,5)&0x02;
-}
-int ogg_page_eos(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read1(&ob,5)&0x04;
-}
+#if 0
+/* helper to initialize lookup for direct-table CRC (illustrative; we
+ use the static init below) */
-ogg_int64_t ogg_page_granulepos(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read8(&ob,6);
-}
+static ogg_uint32_t _ogg_crc_entry(unsigned long index){
+ int i;
+ unsigned long r;
-ogg_uint32_t ogg_page_serialno(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read4(&ob,14);
-}
-
-ogg_uint32_t ogg_page_pageno(ogg_page *og){
- oggbyte_buffer ob;
- oggbyte_init(&ob,og->header);
- return oggbyte_read4(&ob,18);
+ r = index << 24;
+ for (i=0; i<8; i++)
+ if (r & 0x80000000UL)
+ r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ else
+ r<<=1;
+ return (r & 0xffffffffUL);
}
-
-/* Static CRC calculation table. See older code in CVS for dead
- run-time initialization code. */
+#endif
static const ogg_uint32_t crc_lookup[256] ICONST_ATTR = {
0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
@@ -538,92 +183,462 @@ static const ogg_uint32_t crc_lookup[256] ICONST_ATTR = {
0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
-ogg_sync_state *ogg_sync_create(void){
- ogg_sync_state *oy=_ogg_calloc(1,sizeof(*oy));
- memset(oy,0,sizeof(*oy));
- oy->bufferpool=ogg_buffer_create();
- return oy;
+/* init the encode/decode logical stream state */
+
+int ogg_stream_init(ogg_stream_state *os,int serialno){
+ if(os){
+ memset(os,0,sizeof(*os));
+ os->body_storage=16*1024;
+ os->lacing_storage=1024;
+
+ os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
+ os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
+ os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
+
+ if(!os->body_data || !os->lacing_vals || !os->granule_vals){
+ ogg_stream_clear(os);
+ return -1;
+ }
+
+ os->serialno=serialno;
+
+ return(0);
+ }
+ return(-1);
+}
+
+/* async/delayed error detection for the ogg_stream_state */
+int ogg_stream_check(ogg_stream_state *os){
+ if(!os || !os->body_data) return -1;
+ return 0;
}
-int ogg_sync_destroy(ogg_sync_state *oy){
- if(oy){
- ogg_sync_reset(oy);
- ogg_buffer_destroy(oy->bufferpool);
- memset(oy,0,sizeof(*oy));
- _ogg_free(oy);
+/* _clear does not free os, only the non-flat storage within */
+int ogg_stream_clear(ogg_stream_state *os){
+ if(os){
+ if(os->body_data)_ogg_free(os->body_data);
+ if(os->lacing_vals)_ogg_free(os->lacing_vals);
+ if(os->granule_vals)_ogg_free(os->granule_vals);
+
+ memset(os,0,sizeof(*os));
+ }
+ return(0);
+}
+
+int ogg_stream_destroy(ogg_stream_state *os){
+ if(os){
+ ogg_stream_clear(os);
+ _ogg_free(os);
+ }
+ return(0);
+}
+
+/* Helpers for ogg_stream_encode; this keeps the structure and
+ what's happening fairly clear */
+
+static int _os_body_expand(ogg_stream_state *os,int needed){
+ if(os->body_storage<=os->body_fill+needed){
+ void *ret;
+ ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
+ sizeof(*os->body_data));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->body_storage+=(needed+1024);
+ os->body_data=ret;
}
- return OGG_SUCCESS;
+ return 0;
}
-unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long bytes){
-
- /* [allocate and] expose a buffer for data submission.
-
- If there is no head fragment
- allocate one and expose it
- else
- if the current head fragment has sufficient unused space
- expose it
- else
- if the current head fragment is unused
- resize and expose it
- else
- allocate new fragment and expose it
- */
-
- /* base case; fifo uninitialized */
- if(!oy->fifo_head){
- oy->fifo_head=oy->fifo_tail=ogg_buffer_alloc(oy->bufferpool,bytes);
- return oy->fifo_head->buffer->data;
+static int _os_lacing_expand(ogg_stream_state *os,int needed){
+ if(os->lacing_storage<=os->lacing_fill+needed){
+ void *ret;
+ ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)*
+ sizeof(*os->lacing_vals));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->lacing_vals=ret;
+ ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)*
+ sizeof(*os->granule_vals));
+ if(!ret){
+ ogg_stream_clear(os);
+ return -1;
+ }
+ os->granule_vals=ret;
+ os->lacing_storage+=(needed+32);
}
-
- /* space left in current fragment case */
- if(oy->fifo_head->buffer->size-
- oy->fifo_head->length-
- oy->fifo_head->begin >= bytes)
- return oy->fifo_head->buffer->data+
- oy->fifo_head->length+oy->fifo_head->begin;
-
- /* current fragment is unused, but too small */
- if(!oy->fifo_head->length){
- ogg_buffer_realloc(oy->fifo_head,bytes);
- return oy->fifo_head->buffer->data+oy->fifo_head->begin;
+ return 0;
+}
+
+/* checksum the page */
+/* Direct table CRC; note that this will be faster in the future if we
+ perform the checksum simultaneously with other copies */
+
+void ogg_page_checksum_set(ogg_page *og){
+ if(og){
+ ogg_uint32_t crc_reg=0;
+ int i;
+
+ /* safety; needed for API behavior, but not framing code */
+ og->header[22]=0;
+ og->header[23]=0;
+ og->header[24]=0;
+ og->header[25]=0;
+
+ for(i=0;i<og->header_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
+ for(i=0;i<og->body_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
+
+ og->header[22]=(unsigned char)(crc_reg&0xff);
+ og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
+ og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
+ og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
}
-
- /* current fragment used/full; get new fragment */
+}
+
+#if 0
+/* submit data to the internal buffer of the framing engine */
+int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
+ long e_o_s, ogg_int64_t granulepos){
+
+ int bytes = 0, lacing_vals, i;
+
+ if(ogg_stream_check(os)) return -1;
+ if(!iov) return 0;
+
+ for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len;
+ lacing_vals=bytes/255+1;
+
+ if(os->body_returned){
+ /* advance packet data according to the body_returned pointer. We
+ had to keep it around to return a pointer into the buffer last
+ call */
+
+ os->body_fill-=os->body_returned;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+os->body_returned,
+ os->body_fill);
+ os->body_returned=0;
+ }
+
+ /* make sure we have the buffer storage */
+ if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
+ return -1;
+
+ /* Copy in the submitted packet. Yes, the copy is a waste; this is
+ the liability of overly clean abstraction for the time being. It
+ will actually be fairly easy to eliminate the extra copy in the
+ future */
+
+ for (i = 0; i < count; ++i) {
+ memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
+ os->body_fill += (int)iov[i].iov_len;
+ }
+
+ /* Store lacing vals for this packet */
+ for(i=0;i<lacing_vals-1;i++){
+ os->lacing_vals[os->lacing_fill+i]=255;
+ os->granule_vals[os->lacing_fill+i]=os->granulepos;
+ }
+ os->lacing_vals[os->lacing_fill+i]=bytes%255;
+ os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
+
+ /* flag the first segment as the beginning of the packet */
+ os->lacing_vals[os->lacing_fill]|= 0x100;
+
+ os->lacing_fill+=lacing_vals;
+
+ /* for the sake of completeness */
+ os->packetno++;
+
+ if(e_o_s)os->e_o_s=1;
+
+ return(0);
+}
+
+int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
+ ogg_iovec_t iov;
+ iov.iov_base = op->packet;
+ iov.iov_len = op->bytes;
+ return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
+}
+
+
+/* Conditionally flush a page; force==0 will only flush nominal-size
+ pages, force==1 forces us to flush a page regardless of page size
+ so long as there's any data available at all. */
+static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
+ int i;
+ int vals=0;
+ int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
+ int bytes=0;
+ long acc=0;
+ ogg_int64_t granule_pos=-1;
+
+ if(ogg_stream_check(os)) return(0);
+ if(maxvals==0) return(0);
+
+ /* construct a page */
+ /* decide how many segments to include */
+
+ /* If this is the initial header case, the first page must only include
+ the initial header packet */
+ if(os->b_o_s==0){ /* 'initial header page' case */
+ granule_pos=0;
+ for(vals=0;vals<maxvals;vals++){
+ if((os->lacing_vals[vals]&0x0ff)<255){
+ vals++;
+ break;
+ }
+ }
+ }else{
+
+ /* The extra packets_done, packet_just_done logic here attempts to do two things:
+ 1) Don't unneccessarily span pages.
+ 2) Unless necessary, don't flush pages if there are less than four packets on
+ them; this expands page size to reduce unneccessary overhead if incoming packets
+ are large.
+ These are not necessary behaviors, just 'always better than naive flushing'
+ without requiring an application to explicitly request a specific optimized
+ behavior. We'll want an explicit behavior setup pathway eventually as well. */
+
+ int packets_done=0;
+ int packet_just_done=0;
+ for(vals=0;vals<maxvals;vals++){
+ if(acc>nfill && packet_just_done>=4){
+ force=1;
+ break;
+ }
+ acc+=os->lacing_vals[vals]&0x0ff;
+ if((os->lacing_vals[vals]&0xff)<255){
+ granule_pos=os->granule_vals[vals];
+ packet_just_done=++packets_done;
+ }else
+ packet_just_done=0;
+ }
+ if(vals==255)force=1;
+ }
+
+ if(!force) return(0);
+
+ /* construct the header in temp storage */
+ memcpy(os->header,"OggS",4);
+
+ /* stream structure version */
+ os->header[4]=0x00;
+
+ /* continued packet flag? */
+ os->header[5]=0x00;
+ if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
+ /* first page flag? */
+ if(os->b_o_s==0)os->header[5]|=0x02;
+ /* last page flag? */
+ if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
+ os->b_o_s=1;
+
+ /* 64 bits of PCM position */
+ for(i=6;i<14;i++){
+ os->header[i]=(unsigned char)(granule_pos&0xff);
+ granule_pos>>=8;
+ }
+
+ /* 32 bits of stream serial number */
+ {
+ long serialno=os->serialno;
+ for(i=14;i<18;i++){
+ os->header[i]=(unsigned char)(serialno&0xff);
+ serialno>>=8;
+ }
+ }
+
+ /* 32 bits of page counter (we have both counter and page header
+ because this val can roll over) */
+ if(os->pageno==-1)os->pageno=0; /* because someone called
+ stream_reset; this would be a
+ strange thing to do in an
+ encode stream, but it has
+ plausible uses */
{
- ogg_reference *new=ogg_buffer_alloc(oy->bufferpool,bytes);
- oy->fifo_head->next=new;
- oy->fifo_head=new;
+ long pageno=os->pageno++;
+ for(i=18;i<22;i++){
+ os->header[i]=(unsigned char)(pageno&0xff);
+ pageno>>=8;
+ }
}
- return oy->fifo_head->buffer->data;
+
+ /* zero for computation; filled in later */
+ os->header[22]=0;
+ os->header[23]=0;
+ os->header[24]=0;
+ os->header[25]=0;
+
+ /* segment table */
+ os->header[26]=(unsigned char)(vals&0xff);
+ for(i=0;i<vals;i++)
+ bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
+
+ /* set pointers in the ogg_page struct */
+ og->header=os->header;
+ og->header_len=os->header_fill=vals+27;
+ og->body=os->body_data+os->body_returned;
+ og->body_len=bytes;
+
+ /* advance the lacing data and set the body_returned pointer */
+
+ os->lacing_fill-=vals;
+ memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
+ os->body_returned+=bytes;
+
+ /* calculate the checksum */
+
+ ogg_page_checksum_set(og);
+
+ /* done */
+ return(1);
}
-int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
- if(!oy->fifo_head)return OGG_EINVAL;
- if(oy->fifo_head->buffer->size-oy->fifo_head->length-oy->fifo_head->begin <
- bytes)return OGG_EINVAL;
- oy->fifo_head->length+=bytes;
- oy->fifo_fill+=bytes;
- return OGG_SUCCESS;
+/* This will flush remaining packets into a page (returning nonzero),
+ even if there is not enough data to trigger a flush normally
+ (undersized page). If there are no packets or partial packets to
+ flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
+ try to flush a normal sized page like ogg_stream_pageout; a call to
+ ogg_stream_flush does not guarantee that all packets have flushed.
+ Only a return value of 0 from ogg_stream_flush indicates all packet
+ data is flushed into pages.
+
+ since ogg_stream_flush will flush the last page in a stream even if
+ it's undersized, you almost certainly want to use ogg_stream_pageout
+ (and *not* ogg_stream_flush) unless you specifically need to flush
+ an page regardless of size in the middle of a stream. */
+
+int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
+ return ogg_stream_flush_i(os,og,1,4096);
+}
+
+/* This constructs pages from buffered packet segments. The pointers
+returned are to static buffers; do not free. The returned buffers are
+good only until the next call (using the same ogg_stream_state) */
+
+int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
+ int force=0;
+ if(ogg_stream_check(os)) return 0;
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
+ force=1;
+
+ return(ogg_stream_flush_i(os,og,force,4096));
}
-static ogg_uint32_t _checksum(ogg_reference *or, int bytes){
- ogg_uint32_t crc_reg=0;
- int j,post;
-
- while(or){
- unsigned char *data=or->buffer->data+or->begin;
- post=(bytes<or->length?bytes:or->length);
- for(j=0;j<post;++j)
- crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^data[j]];
- bytes-=j;
- or=or->next;
+/* Like the above, but an argument is provided to adjust the nominal
+page size for applications which are smart enough to provide their
+own delay based flushing */
+
+int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
+ int force=0;
+ if(ogg_stream_check(os)) return 0;
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
+ force=1;
+
+ return(ogg_stream_flush_i(os,og,force,nfill));
+}
+
+int ogg_stream_eos(ogg_stream_state *os){
+ if(ogg_stream_check(os)) return 1;
+ return os->e_o_s;
+}
+#endif
+/* DECODING PRIMITIVES: packet streaming layer **********************/
+
+/* This has two layers to place more of the multi-serialno and paging
+ control in the application's hands. First, we expose a data buffer
+ using ogg_sync_buffer(). The app either copies into the
+ buffer, or passes it directly to read(), etc. We then call
+ ogg_sync_wrote() to tell how many bytes we just added.
+
+ Pages are returned (pointers into the buffer in ogg_sync_state)
+ by ogg_sync_pageout(). The page is then submitted to
+ ogg_stream_pagein() along with the appropriate
+ ogg_stream_state* (ie, matching serialno). We then get raw
+ packets out calling ogg_stream_packetout() with a
+ ogg_stream_state. */
+
+/* initialize the struct to a known state */
+int ogg_sync_init(ogg_sync_state *oy){
+ if(oy){
+ oy->storage = -1; /* used as a readiness flag */
+ memset(oy,0,sizeof(*oy));
}
+ return(0);
+}
+
+/* clear non-flat storage within */
+int ogg_sync_clear(ogg_sync_state *oy){
+ if(oy){
+ if(oy->data)_ogg_free(oy->data);
+ memset(oy,0,sizeof(*oy));
+ }
+ return(0);
+}
+
+int ogg_sync_destroy(ogg_sync_state *oy){
+ if(oy){
+ ogg_sync_clear(oy);
+ _ogg_free(oy);
+ }
+ return(0);
+}
- return crc_reg;
+int ogg_sync_check(ogg_sync_state *oy){
+ if(oy->storage<0) return -1;
+ return 0;
}
+char *ogg_sync_buffer(ogg_sync_state *oy, long size){
+ if(ogg_sync_check(oy)) return NULL;
+
+ /* first, clear out any space that has been previously returned */
+ if(oy->returned){
+ oy->fill-=oy->returned;
+ if(oy->fill>0)
+ memmove(oy->data,oy->data+oy->returned,oy->fill);
+ oy->returned=0;
+ }
+
+ if(size>oy->storage-oy->fill){
+ /* We need to extend the internal buffer */
+ long newsize=size+oy->fill+4096; /* an extra page to be nice */
+ void *ret;
+
+ if(oy->data)
+ ret=_ogg_realloc(oy->data,newsize);
+ else
+ ret=_ogg_malloc(newsize);
+ if(!ret){
+ ogg_sync_clear(oy);
+ return NULL;
+ }
+ oy->data=ret;
+ oy->storage=newsize;
+ }
+
+ /* expose a segment at least as large as requested at the fill mark */
+ return((char *)oy->data+oy->fill);
+}
+
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
+ if(ogg_sync_check(oy))return -1;
+ if(oy->fill+bytes>oy->storage)return -1;
+ oy->fill+=bytes;
+ return(0);
+}
/* sync the stream. This is meant to be useful for finding page
boundaries.
@@ -636,248 +651,130 @@ static ogg_uint32_t _checksum(ogg_reference *or, int bytes){
*/
long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
- oggbyte_buffer page;
- long bytes,ret=0;
-
- ogg_page_release(og);
-
- bytes=oy->fifo_fill;
- oggbyte_init(&page,oy->fifo_tail);
+ unsigned char *page=oy->data+oy->returned;
+ unsigned char *next;
+ long bytes=oy->fill-oy->returned;
+ if(ogg_sync_check(oy))return 0;
+
if(oy->headerbytes==0){
- if(bytes<27)goto sync_out; /* not enough for even a minimal header */
+ int headerbytes,i;
+ if(bytes<27)return(0); /* not enough for a header */
/* verify capture pattern */
- if(oggbyte_read1(&page,0)!=(int)'O' ||
- oggbyte_read1(&page,1)!=(int)'g' ||
- oggbyte_read1(&page,2)!=(int)'g' ||
- oggbyte_read1(&page,3)!=(int)'S' ) goto sync_fail;
-
- oy->headerbytes=oggbyte_read1(&page,26)+27;
- }
- if(bytes<oy->headerbytes)goto sync_out; /* not enough for header +
- seg table */
- if(oy->bodybytes==0){
- int i;
+ if(memcmp(page,"OggS",4))goto sync_fail;
+
+ headerbytes=page[26]+27;
+ if(bytes<headerbytes)return(0); /* not enough for header + seg table */
+
/* count up body length in the segment table */
- for(i=0;i<oy->headerbytes-27;i++)
- oy->bodybytes+=oggbyte_read1(&page,27+i);
+
+ for(i=0;i<page[26];i++)
+ oy->bodybytes+=page[27+i];
+ oy->headerbytes=headerbytes;
}
- if(oy->bodybytes+oy->headerbytes>bytes)goto sync_out;
-
- /* we have what appears to be a complete page; last test: verify
- checksum */
+ if(oy->bodybytes+oy->headerbytes>bytes)return(0);
+
+ /* The whole test page is buffered. Verify the checksum */
{
- ogg_uint32_t chksum=oggbyte_read4(&page,22);
- oggbyte_set4(&page,0,22);
-
- /* Compare checksums; memory continues to be common access */
- if(chksum!=_checksum(oy->fifo_tail,oy->bodybytes+oy->headerbytes)){
-
+ /* Grab the checksum bytes, set the header field to zero */
+ char chksum[4];
+ ogg_page log;
+
+ memcpy(chksum,page+22,4);
+ memset(page+22,0,4);
+
+ /* set up a temp page struct and recompute the checksum */
+ log.header=page;
+ log.header_len=oy->headerbytes;
+ log.body=page+oy->headerbytes;
+ log.body_len=oy->bodybytes;
+ ogg_page_checksum_set(&log);
+
+ /* Compare */
+ if(memcmp(chksum,page+22,4)){
/* D'oh. Mismatch! Corrupt page (or miscapture and not a page
- at all). replace the computed checksum with the one actually
- read in; remember all the memory is common access */
+ at all) */
+ /* replace the computed checksum with the one actually read in */
+ memcpy(page+22,chksum,4);
- oggbyte_set4(&page,chksum,22);
+ /* Bad checksum. Lose sync */
goto sync_fail;
}
- oggbyte_set4(&page,chksum,22);
- }
-
- /* We have a page. Set up page return. */
- if(og){
- /* set up page output */
- og->header=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->headerbytes);
- og->header_len=oy->headerbytes;
- og->body=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->bodybytes);
- og->body_len=oy->bodybytes;
- }else{
- /* simply advance */
- oy->fifo_tail=
- ogg_buffer_pretruncate(oy->fifo_tail,oy->headerbytes+oy->bodybytes);
- if(!oy->fifo_tail)oy->fifo_head=0;
}
- ret=oy->headerbytes+oy->bodybytes;
- oy->unsynced=0;
- oy->headerbytes=0;
- oy->bodybytes=0;
- oy->fifo_fill-=ret;
+ /* yes, have a whole page all ready to go */
+ {
+ unsigned char *page=oy->data+oy->returned;
+ long bytes;
+
+ if(og){
+ og->header=page;
+ og->header_len=oy->headerbytes;
+ og->body=page+oy->headerbytes;
+ og->body_len=oy->bodybytes;
+ }
- return ret;
+ oy->unsynced=0;
+ oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(bytes);
+ }
sync_fail:
-
+
oy->headerbytes=0;
oy->bodybytes=0;
- oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,1);
- ret--;
- /* search forward through fragments for possible capture */
- while(oy->fifo_tail){
- /* invariant: fifo_cursor points to a position in fifo_tail */
- unsigned char *now=oy->fifo_tail->buffer->data+oy->fifo_tail->begin;
- unsigned char *next=memchr(now, 'O', oy->fifo_tail->length);
-
- if(next){
- /* possible capture in this segment */
- long bytes=next-now;
- oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
- ret-=bytes;
- break;
- }else{
- /* no capture. advance to next segment */
- long bytes=oy->fifo_tail->length;
- ret-=bytes;
- oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
- }
- }
- if(!oy->fifo_tail)oy->fifo_head=0;
- oy->fifo_fill+=ret;
+ /* search for possible capture */
+ next=memchr(page+1,'O',bytes-1);
+ if(!next)
+ next=oy->data+oy->fill;
- sync_out:
- return ret;
+ oy->returned=(int)(next-oy->data);
+ return((long)-(next-page));
}
-/* clear things to an initial state. Good to call, eg, before seeking */
-int ogg_sync_reset(ogg_sync_state *oy){
+/* sync the stream and get a page. Keep trying until we find a page.
+ Suppress 'sync errors' after reporting the first.
- ogg_buffer_release(oy->fifo_tail);
- oy->fifo_tail=0;
- oy->fifo_head=0;
- oy->fifo_fill=0;
+ return values:
+ -1) recapture (hole in data)
+ 0) need more data
+ 1) page returned
- oy->unsynced=0;
- oy->headerbytes=0;
- oy->bodybytes=0;
- return OGG_SUCCESS;
-}
+ Returns pointers into buffered data; invalidated by next call to
+ _stream, _clear, _init, or _buffer */
-ogg_stream_state *ogg_stream_create(int serialno){
- ogg_stream_state *os=_ogg_calloc(1,sizeof(*os));
- os->serialno=serialno;
- os->pageno=-1;
- return os;
-}
+int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
-int ogg_stream_destroy(ogg_stream_state *os){
- if(os){
- ogg_buffer_release(os->header_tail);
- ogg_buffer_release(os->body_tail);
- memset(os,0,sizeof(*os));
- _ogg_free(os);
- }
- return OGG_SUCCESS;
-}
+ if(ogg_sync_check(oy))return 0;
+ /* all we need to do is verify a page at the head of the stream
+ buffer. If it doesn't verify, we look for the next potential
+ frame */
-#define FINFLAG 0x80000000UL
-#define FINMASK 0x7fffffffUL
-
-static void _next_lace(oggbyte_buffer *ob,ogg_stream_state *os){
- /* search ahead one lace */
- os->body_fill_next=0;
- while(os->laceptr<os->lacing_fill){
- int val=oggbyte_read1(ob,27+os->laceptr++);
- os->body_fill_next+=val;
- if(val<255){
- os->body_fill_next|=FINFLAG;
- os->clearflag=1;
- break;
+ for(;;){
+ long ret=ogg_sync_pageseek(oy,og);
+ if(ret>0){
+ /* have a page */
+ return(1);
+ }
+ if(ret==0){
+ /* need more data */
+ return(0);
}
- }
-}
-
-STATICIRAM_NOT_MDCT void _span_queued_page(ogg_stream_state *os)
- ICODE_ATTR_TREMOR_NOT_MDCT;
-STATICIRAM_NOT_MDCT void _span_queued_page(ogg_stream_state *os){
- while( !(os->body_fill&FINFLAG) ){
-
- if(!os->header_tail)break;
-
- /* first flush out preceeding page header (if any). Body is
- flushed as it's consumed, so that's not done here. */
-
- if(os->lacing_fill>=0)
- os->header_tail=ogg_buffer_pretruncate(os->header_tail,
- os->lacing_fill+27);
- os->lacing_fill=0;
- os->laceptr=0;
- os->clearflag=0;
-
- if(!os->header_tail){
- os->header_head=0;
- break;
- }else{
-
- /* process/prepare next page, if any */
-
- long pageno;
- oggbyte_buffer ob;
- ogg_page og; /* only for parsing header values */
- og.header=os->header_tail; /* only for parsing header values */
- pageno=ogg_page_pageno(&og);
-
- oggbyte_init(&ob,os->header_tail);
- os->lacing_fill=oggbyte_read1(&ob,26);
-
- /* are we in sequence? */
- if(pageno!=os->pageno){
- if(os->pageno==-1) /* indicates seek or reset */
- os->holeflag=1; /* set for internal use */
- else
- os->holeflag=2; /* set for external reporting */
-
- os->body_tail=ogg_buffer_pretruncate(os->body_tail,
- os->body_fill);
- if(os->body_tail==0)os->body_head=0;
- os->body_fill=0;
-
- }
- if(ogg_page_continued(&og)){
- if(os->body_fill==0){
- /* continued packet, but no preceeding data to continue */
- /* dump the first partial packet on the page */
- _next_lace(&ob,os);
- os->body_tail=
- ogg_buffer_pretruncate(os->body_tail,os->body_fill_next&FINMASK);
- if(os->body_tail==0)os->body_head=0;
- /* set span flag */
- if(!os->spanflag && !os->holeflag)os->spanflag=2;
- }
- }else{
- if(os->body_fill>0){
- /* preceeding data to continue, but not a continued page */
- /* dump body_fill */
- os->body_tail=ogg_buffer_pretruncate(os->body_tail,
- os->body_fill);
- if(os->body_tail==0)os->body_head=0;
- os->body_fill=0;
-
- /* set espan flag */
- if(!os->spanflag && !os->holeflag)os->spanflag=2;
- }
- }
-
- if(os->laceptr<os->lacing_fill){
- os->granulepos=ogg_page_granulepos(&og);
+ /* head did not start a synced page... skipped some bytes */
+ if(!oy->unsynced){
+ oy->unsynced=1;
+ return(-1);
+ }
- /* get current packet size & flag */
- _next_lace(&ob,os);
- os->body_fill+=os->body_fill_next; /* addition handles the flag fine;
- unsigned on purpose */
- /* ...and next packet size & flag */
- _next_lace(&ob,os);
+ /* loop. keep looking */
- }
-
- os->pageno=pageno+1;
- os->e_o_s=ogg_page_eos(&og);
- os->b_o_s=ogg_page_bos(&og);
-
- }
}
}
@@ -885,45 +782,156 @@ STATICIRAM_NOT_MDCT void _span_queued_page(ogg_stream_state *os){
into packet segments here as well. */
int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
+ unsigned char *header=og->header;
+ unsigned char *body=og->body;
+ long bodysize=og->body_len;
+ int segptr=0;
- int serialno=ogg_page_serialno(og);
int version=ogg_page_version(og);
+ int continued=ogg_page_continued(og);
+ int bos=ogg_page_bos(og);
+ int eos=ogg_page_eos(og);
+ ogg_int64_t granulepos=ogg_page_granulepos(og);
+ ogg_uint32_t serialno=ogg_page_serialno(og);
+ long pageno=ogg_page_pageno(og);
+ int segments=header[26];
+
+ if(ogg_stream_check(os)) return -1;
+
+ /* clean up 'returned data' */
+ {
+ long lr=os->lacing_returned;
+ long br=os->body_returned;
+
+ /* body data */
+ if(br){
+ os->body_fill-=br;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+br,os->body_fill);
+ os->body_returned=0;
+ }
+
+ if(lr){
+ /* segment table */
+ if(os->lacing_fill-lr){
+ memmove(os->lacing_vals,os->lacing_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->granule_vals));
+ }
+ os->lacing_fill-=lr;
+ os->lacing_packet-=lr;
+ os->lacing_returned=0;
+ }
+ }
/* check the serial number */
- if(serialno!=os->serialno){
- ogg_page_release(og);
- return OGG_ESERIAL;
+ if(serialno!=os->serialno)return(-1);
+ if(version>0)return(-1);
+
+ if(_os_lacing_expand(os,segments+1)) return -1;
+
+ /* are we in sequence? */
+ if(pageno!=os->pageno){
+ int i;
+
+ /* unroll previous partial packet (if any) */
+ for(i=os->lacing_packet;i<os->lacing_fill;i++)
+ os->body_fill-=os->lacing_vals[i]&0xff;
+ os->lacing_fill=os->lacing_packet;
+
+ /* make a note of dropped data in segment table */
+ if(os->pageno!=-1){
+ os->lacing_vals[os->lacing_fill++]=0x400;
+ os->lacing_packet++;
+ }
+ }
+
+ /* are we a 'continued packet' page? If so, we may need to skip
+ some segments */
+ if(continued){
+ if(os->lacing_fill<1 ||
+ os->lacing_vals[os->lacing_fill-1]==0x400){
+ bos=0;
+ for(;segptr<segments;segptr++){
+ int val=header[27+segptr];
+ body+=val;
+ bodysize-=val;
+ if(val<255){
+ segptr++;
+ break;
+ }
+ }
+ }
}
- if(version>0){
- ogg_page_release(og);
- return OGG_EVERSION;
+
+ if(bodysize){
+ if(_os_body_expand(os,bodysize)) return -1;
+ memcpy(os->body_data+os->body_fill,body,bodysize);
+ os->body_fill+=bodysize;
}
- /* add to fifos */
- if(!os->body_tail){
- os->body_tail=og->body;
- os->body_head=ogg_buffer_walk(og->body);
- }else{
- os->body_head=ogg_buffer_cat(os->body_head,og->body);
+ {
+ int saved=-1;
+ while(segptr<segments){
+ int val=header[27+segptr];
+ os->lacing_vals[os->lacing_fill]=val;
+ os->granule_vals[os->lacing_fill]=-1;
+
+ if(bos){
+ os->lacing_vals[os->lacing_fill]|=0x100;
+ bos=0;
+ }
+
+ if(val<255)saved=os->lacing_fill;
+
+ os->lacing_fill++;
+ segptr++;
+
+ if(val<255)os->lacing_packet=os->lacing_fill;
+ }
+
+ /* set the granulepos on the last granuleval of the last full packet */
+ if(saved!=-1){
+ os->granule_vals[saved]=granulepos;
+ }
+
}
- if(!os->header_tail){
- os->header_tail=og->header;
- os->header_head=ogg_buffer_walk(og->header);
- os->lacing_fill=-27;
- }else{
- os->header_head=ogg_buffer_cat(os->header_head,og->header);
+
+ if(eos){
+ os->e_o_s=1;
+ if(os->lacing_fill>0)
+ os->lacing_vals[os->lacing_fill-1]|=0x200;
}
- memset(og,0,sizeof(*og));
- return OGG_SUCCESS;
+ os->pageno=pageno+1;
+
+ return(0);
+}
+
+/* clear things to an initial state. Good to call, eg, before seeking */
+int ogg_sync_reset(ogg_sync_state *oy){
+ if(ogg_sync_check(oy))return -1;
+
+ oy->fill=0;
+ oy->returned=0;
+ oy->unsynced=0;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(0);
}
int ogg_stream_reset(ogg_stream_state *os){
+ if(ogg_stream_check(os)) return -1;
+
+ os->body_fill=0;
+ os->body_returned=0;
- ogg_buffer_release(os->header_tail);
- ogg_buffer_release(os->body_tail);
- os->header_tail=os->header_head=0;
- os->body_tail=os->body_head=0;
+ os->lacing_fill=0;
+ os->lacing_packet=0;
+ os->lacing_returned=0;
+
+/* os->header_fill=0; */
os->e_o_s=0;
os->b_o_s=0;
@@ -931,137 +939,1159 @@ int ogg_stream_reset(ogg_stream_state *os){
os->packetno=0;
os->granulepos=0;
- os->body_fill=0;
- os->lacing_fill=0;
-
- os->holeflag=0;
- os->spanflag=0;
- os->clearflag=0;
- os->laceptr=0;
- os->body_fill_next=0;
-
- return OGG_SUCCESS;
+ return(0);
}
int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
+ if(ogg_stream_check(os)) return -1;
ogg_stream_reset(os);
os->serialno=serialno;
- return OGG_SUCCESS;
+ return(0);
}
-STATICIRAM_NOT_MDCT int _packetout(ogg_stream_state *os,ogg_packet *op,int adv)
+static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv)
ICODE_ATTR_TREMOR_NOT_MDCT;
-STATICIRAM_NOT_MDCT int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
+static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
- ogg_packet_release(op);
- _span_queued_page(os);
+ /* The last part of decode. We have the stream broken into packet
+ segments. Now we need to group them into packets (or return the
+ out of sync markers) */
- if(os->holeflag){
- int temp=os->holeflag;
- if(os->clearflag)
- os->holeflag=0;
- else
- os->holeflag=1;
- if(temp==2){
- os->packetno++;
- return OGG_HOLE;
- }
- }
- if(os->spanflag){
- int temp=os->spanflag;
- if(os->clearflag)
- os->spanflag=0;
- else
- os->spanflag=1;
- if(temp==2){
- os->packetno++;
- return OGG_SPAN;
- }
+ int ptr=os->lacing_returned;
+
+ if(os->lacing_packet<=ptr)return(0);
+
+ if(os->lacing_vals[ptr]&0x400){
+ /* we need to tell the codec there's a gap; it might need to
+ handle previous packet dependencies. */
+ os->lacing_returned++;
+ os->packetno++;
+ return(-1);
}
- if(!(os->body_fill&FINFLAG)) return 0;
- if(!op && !adv)return 1; /* just using peek as an inexpensive way
+ if(!op && !adv)return(1); /* just using peek as an inexpensive way
to ask if there's a whole packet
waiting */
- if(op){
- op->b_o_s=os->b_o_s;
- if(os->e_o_s && os->body_fill_next==0)
- op->e_o_s=os->e_o_s;
- else
- op->e_o_s=0;
- if( (os->body_fill&FINFLAG) && !(os->body_fill_next&FINFLAG) )
- op->granulepos=os->granulepos;
- else
- op->granulepos=-1;
- op->packetno=os->packetno;
- }
- if(adv){
- oggbyte_buffer ob;
- oggbyte_init(&ob,os->header_tail);
+ /* Gather the whole packet. We'll have no holes or a partial packet */
+ {
+ int size=os->lacing_vals[ptr]&0xff;
+ long bytes=size;
+ int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
+ int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
+
+ while(size==255){
+ int val=os->lacing_vals[++ptr];
+ size=val&0xff;
+ if(val&0x200)eos=0x200;
+ bytes+=size;
+ }
- /* split the body contents off */
if(op){
- op->packet=ogg_buffer_split(&os->body_tail,&os->body_head,
- os->body_fill&FINMASK);
- op->bytes=os->body_fill&FINMASK;
- }else{
- os->body_tail=ogg_buffer_pretruncate(os->body_tail,
- os->body_fill&FINMASK);
- if(os->body_tail==0)os->body_head=0;
+ op->e_o_s=eos;
+ op->b_o_s=bos;
+ op->packet=os->body_data+os->body_returned;
+ op->packetno=os->packetno;
+ op->granulepos=os->granule_vals[ptr];
+ op->bytes=bytes;
}
- /* update lacing pointers */
- os->body_fill=os->body_fill_next;
- _next_lace(&ob,os);
- }else{
- if(op){
- op->packet=ogg_buffer_sub(os->body_tail,0,os->body_fill&FINMASK);
- op->bytes=os->body_fill&FINMASK;
+ if(adv){
+ os->body_returned+=bytes;
+ os->lacing_returned=ptr+1;
+ os->packetno++;
}
}
-
- if(adv){
- os->packetno++;
- os->b_o_s=0;
- }
-
- return 1;
+ return(1);
}
int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op)
ICODE_ATTR_TREMOR_NOT_MDCT;
int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
+ if(ogg_stream_check(os)) return 0;
return _packetout(os,op,1);
}
int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op)
ICODE_ATTR_TREMOR_NOT_MDCT;
int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
+ if(ogg_stream_check(os)) return 0;
return _packetout(os,op,0);
}
-int ogg_packet_release(ogg_packet *op) {
- if(op){
- ogg_buffer_release(op->packet);
- memset(op, 0, sizeof(*op));
+void ogg_packet_clear(ogg_packet *op) {
+ _ogg_free(op->packet);
+ memset(op, 0, sizeof(*op));
+}
+
+#ifdef _V_SELFTEST
+#include <stdio.h>
+
+ogg_stream_state os_en, os_de;
+ogg_sync_state oy;
+
+void checkpacket(ogg_packet *op,long len, int no, long pos){
+ long j;
+ static int sequence=0;
+ static int lastno=0;
+
+ if(op->bytes!=len){
+ fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
+ exit(1);
+ }
+ if(op->granulepos!=pos){
+ fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
+ exit(1);
+ }
+
+ /* packet number just follows sequence/gap; adjust the input number
+ for that */
+ if(no==0){
+ sequence=0;
+ }else{
+ sequence++;
+ if(no>lastno+1)
+ sequence++;
+ }
+ lastno=no;
+ if(op->packetno!=sequence){
+ fprintf(stderr,"incorrect packet sequence %ld != %d\n",
+ (long)(op->packetno),sequence);
+ exit(1);
}
- return OGG_SUCCESS;
+
+ /* Test data */
+ for(j=0;j<op->bytes;j++)
+ if(op->packet[j]!=((j+no)&0xff)){
+ fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
+ j,op->packet[j],(j+no)&0xff);
+ exit(1);
+ }
}
-int ogg_page_release(ogg_page *og) {
- if(og){
- ogg_buffer_release(og->header);
- ogg_buffer_release(og->body);
- memset(og, 0, sizeof(*og));
+void check_page(unsigned char *data,const int *header,ogg_page *og){
+ long j;
+ /* Test data */
+ for(j=0;j<og->body_len;j++)
+ if(og->body[j]!=data[j]){
+ fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
+ j,data[j],og->body[j]);
+ exit(1);
+ }
+
+ /* Test header */
+ for(j=0;j<og->header_len;j++){
+ if(og->header[j]!=header[j]){
+ fprintf(stderr,"header content mismatch at pos %ld:\n",j);
+ for(j=0;j<header[26]+27;j++)
+ fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
+ fprintf(stderr,"\n");
+ exit(1);
+ }
}
- return OGG_SUCCESS;
+ if(og->header_len!=header[26]+27){
+ fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
+ og->header_len,header[26]+27);
+ exit(1);
+ }
+}
+
+void print_header(ogg_page *og){
+ int j;
+ fprintf(stderr,"\nHEADER:\n");
+ fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
+ og->header[0],og->header[1],og->header[2],og->header[3],
+ (int)og->header[4],(int)og->header[5]);
+
+ fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
+ (og->header[9]<<24)|(og->header[8]<<16)|
+ (og->header[7]<<8)|og->header[6],
+ (og->header[17]<<24)|(og->header[16]<<16)|
+ (og->header[15]<<8)|og->header[14],
+ ((long)(og->header[21])<<24)|(og->header[20]<<16)|
+ (og->header[19]<<8)|og->header[18]);
+
+ fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
+ (int)og->header[22],(int)og->header[23],
+ (int)og->header[24],(int)og->header[25],
+ (int)og->header[26]);
+
+ for(j=27;j<og->header_len;j++)
+ fprintf(stderr,"%d ",(int)og->header[j]);
+ fprintf(stderr,")\n\n");
}
-void ogg_page_dup(ogg_page *dup,ogg_page *orig){
- dup->header_len=orig->header_len;
- dup->body_len=orig->body_len;
- dup->header=ogg_buffer_dup(orig->header);
- dup->body=ogg_buffer_dup(orig->body);
+void copy_page(ogg_page *og){
+ unsigned char *temp=_ogg_malloc(og->header_len);
+ memcpy(temp,og->header,og->header_len);
+ og->header=temp;
+
+ temp=_ogg_malloc(og->body_len);
+ memcpy(temp,og->body,og->body_len);
+ og->body=temp;
+}
+
+void free_page(ogg_page *og){
+ _ogg_free (og->header);
+ _ogg_free (og->body);
+}
+
+void error(void){
+ fprintf(stderr,"error!\n");
+ exit(1);
+}
+
+/* 17 only */
+const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x15,0xed,0xec,0x91,
+ 1,
+ 17};
+
+/* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x59,0x10,0x6c,0x2c,
+ 1,
+ 17};
+const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x89,0x33,0x85,0xce,
+ 13,
+ 254,255,0,255,1,255,245,255,255,0,
+ 255,255,90};
+
+/* nil packets; beginning,middle,end */
+const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x5c,0x3f,0x66,0xcb,
+ 17,
+ 17,254,255,0,0,255,1,0,255,245,255,255,0,
+ 255,255,90,0};
+
+/* large initial packet */
+const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x01,0x27,0x31,0xaa,
+ 18,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10};
+
+const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x7f,0x4e,0x8a,0xd2,
+ 4,
+ 255,4,255,0};
+
+
+/* continuing packet test */
+const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xf8,0x3c,0x19,0x79,
+ 255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255};
+
+const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x38,0xe6,0xb6,0x28,
+ 6,
+ 255,220,255,4,255,0};
+
+
+/* spill expansion test */
+const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xce,0x8f,0x17,0x1a,
+ 23,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
+
+
+const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x9b,0xb2,0x50,0xa1,
+ 1,
+ 0};
+
+/* page with the 255 segment limit */
+const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xed,0x2a,0x2e,0xa7,
+ 255,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10};
+
+const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x6c,0x3b,0x82,0x3d,
+ 1,
+ 50};
+
+
+/* packet that overspans over an entire page */
+const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x68,0x22,0x7c,0x3d,
+ 255,
+ 100,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255};
+
+const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xf4,0x87,0xba,0xf3,
+ 255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255};
+
+const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,3,0,0,0,
+ 0xf7,0x2f,0x6c,0x60,
+ 5,
+ 254,255,4,255,0};
+
+/* packet that overspans over an entire page */
+const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x68,0x22,0x7c,0x3d,
+ 255,
+ 100,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255};
+
+const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xd4,0xe0,0x60,0xe5,
+ 1,
+ 0};
+
+void test_pack(const int *pl, const int **headers, int byteskip,
+ int pageskip, int packetskip){
+ unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
+ long inptr=0;
+ long outptr=0;
+ long deptr=0;
+ long depacket=0;
+ long granule_pos=7,pageno=0;
+ int i,j,packets,pageout=pageskip;
+ int eosflag=0;
+ int bosflag=0;
+
+ int byteskipcount=0;
+
+ ogg_stream_reset(&os_en);
+ ogg_stream_reset(&os_de);
+ ogg_sync_reset(&oy);
+
+ for(packets=0;packets<packetskip;packets++)
+ depacket+=pl[packets];
+
+ for(packets=0;;packets++)if(pl[packets]==-1)break;
+
+ for(i=0;i<packets;i++){
+ /* construct a test packet */
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=granule_pos;
+
+ granule_pos+=1024;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+
+ /* submit the test packet */
+ ogg_stream_packetin(&os_en,&op);
+
+ /* retrieve any finished pages */
+ {
+ ogg_page og;
+
+ while(ogg_stream_pageout(&os_en,&og)){
+ /* We have a page. Check it carefully */
+
+ fprintf(stderr,"%ld, ",pageno);
+
+ if(headers[pageno]==NULL){
+ fprintf(stderr,"coded too many pages!\n");
+ exit(1);
+ }
+
+ check_page(data+outptr,headers[pageno],&og);
+
+ outptr+=og.body_len;
+ pageno++;
+ if(pageskip){
+ bosflag=1;
+ pageskip--;
+ deptr+=og.body_len;
+ }
+
+ /* have a complete page; submit it to sync/decode */
+
+ {
+ ogg_page og_de;
+ ogg_packet op_de,op_de2;
+ char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
+ char *next=buf;
+ byteskipcount+=og.header_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.header,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ byteskipcount+=og.body_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.body,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ ogg_sync_wrote(&oy,next-buf);
+
+ while(1){
+ int ret=ogg_sync_pageout(&oy,&og_de);
+ if(ret==0)break;
+ if(ret<0)continue;
+ /* got a page. Happy happy. Verify that it's good. */
+
+ fprintf(stderr,"(%d), ",pageout);
+
+ check_page(data+deptr,headers[pageout],&og_de);
+ deptr+=og_de.body_len;
+ pageout++;
+
+ /* submit it to deconstitution */
+ ogg_stream_pagein(&os_de,&og_de);
+
+ /* packets out? */
+ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
+ ogg_stream_packetpeek(&os_de,NULL);
+ ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
+
+ /* verify peek and out match */
+ if(memcmp(&op_de,&op_de2,sizeof(op_de))){
+ fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+
+ /* verify the packet! */
+ /* check data */
+ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
+ fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+ /* check bos flag */
+ if(bosflag==0 && op_de.b_o_s==0){
+ fprintf(stderr,"b_o_s flag not set on packet!\n");
+ exit(1);
+ }
+ if(bosflag && op_de.b_o_s){
+ fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
+ exit(1);
+ }
+ bosflag=1;
+ depacket+=op_de.bytes;
+
+ /* check eos flag */
+ if(eosflag){
+ fprintf(stderr,"Multiple decoded packets with eos flag!\n");
+ exit(1);
+ }
+
+ if(op_de.e_o_s)eosflag=1;
+
+ /* check granulepos flag */
+ if(op_de.granulepos!=-1){
+ fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ _ogg_free(data);
+ if(headers[pageno]!=NULL){
+ fprintf(stderr,"did not write last page!\n");
+ exit(1);
+ }
+ if(headers[pageout]!=NULL){
+ fprintf(stderr,"did not decode last page!\n");
+ exit(1);
+ }
+ if(inptr!=outptr){
+ fprintf(stderr,"encoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=deptr){
+ fprintf(stderr,"decoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=depacket){
+ fprintf(stderr,"decoded packet data incomplete!\n");
+ exit(1);
+ }
+ if(!eosflag){
+ fprintf(stderr,"Never got a packet with EOS set!\n");
+ exit(1);
+ }
+ fprintf(stderr,"ok.\n");
+}
+
+int main(void){
+
+ ogg_stream_init(&os_en,0x04030201);
+ ogg_stream_init(&os_de,0x04030201);
+ ogg_sync_init(&oy);
+
+ /* Exercise each code path in the framing code. Also verify that
+ the checksums are working. */
+
+ {
+ /* 17 only */
+ const int packets[]={17, -1};
+ const int *headret[]={head1_0,NULL};
+
+ fprintf(stderr,"testing single page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
+ const int *headret[]={head1_1,head2_1,NULL};
+
+ fprintf(stderr,"testing basic page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* nil packets; beginning,middle,end */
+ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
+ const int *headret[]={head1_2,head2_2,NULL};
+
+ fprintf(stderr,"testing basic nil packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* large initial packet */
+ const int packets[]={4345,259,255,-1};
+ const int *headret[]={head1_3,head2_3,NULL};
+
+ fprintf(stderr,"testing initial-packet lacing > 4k... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* continuing packet test; with page spill expansion, we have to
+ overflow the lacing table. */
+ const int packets[]={0,65500,259,255,-1};
+ const int *headret[]={head1_4,head2_4,head3_4,NULL};
+
+ fprintf(stderr,"testing single packet page span... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* spill expand packet test */
+ const int packets[]={0,4345,259,255,0,0,-1};
+ const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
+
+ fprintf(stderr,"testing page spill expansion... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ /* page with the 255 segment limit */
+ {
+
+ const int packets[]={0,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,50,-1};
+ const int *headret[]={head1_5,head2_5,head3_5,NULL};
+
+ fprintf(stderr,"testing max packet segments... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* packet that overspans over an entire page */
+ const int packets[]={0,100,130049,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing very large packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* test for the libogg 1.1.1 resync in large continuation bug
+ found by Josh Coalson) */
+ const int packets[]={0,100,130049,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing continuation resync in very large packets... ");
+ test_pack(packets,headret,100,2,3);
+ }
+
+ {
+ /* term only page. why not? */
+ const int packets[]={0,100,64770,-1};
+ const int *headret[]={head1_7,head2_7,head3_7,NULL};
+
+ fprintf(stderr,"testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+
+
+ {
+ /* build a bunch of pages for testing */
+ unsigned char *data=_ogg_malloc(1024*1024);
+ int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
+ int inptr=0,i,j;
+ ogg_page og[5];
+
+ ogg_stream_reset(&os_en);
+
+ for(i=0;pl[i]!=-1;i++){
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=(i+1)*1000;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+ ogg_stream_packetin(&os_en,&op);
+ }
+
+ _ogg_free(data);
+
+ /* retrieve finished pages */
+ for(i=0;i<5;i++){
+ if(ogg_stream_pageout(&os_en,&og[i])==0){
+ fprintf(stderr,"Too few pages output building sync tests!\n");
+ exit(1);
+ }
+ copy_page(&og[i]);
+ }
+
+ /* Test lost pages on pagein/packetout: no rollback */
+ {
+ ogg_page temp;
+ ogg_packet test;
+
+ fprintf(stderr,"Testing loss of pages... ");
+
+ ogg_sync_reset(&oy);
+ ogg_stream_reset(&os_de);
+ for(i=0;i<5;i++){
+ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+ og[i].header_len);
+ ogg_sync_wrote(&oy,og[i].header_len);
+ memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+ ogg_sync_wrote(&oy,og[i].body_len);
+ }
+
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ /* skip */
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+
+ /* do we get the expected results/packets? */
+
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,0,0,0);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,1,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,2,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,98,3,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,4,5000);
+ if(ogg_stream_packetout(&os_de,&test)!=-1){
+ fprintf(stderr,"Error: loss of page did not return error\n");
+ exit(1);
+ }
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,76,9,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,34,10,-1);
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test lost pages on pagein/packetout: rollback with continuation */
+ {
+ ogg_page temp;
+ ogg_packet test;
+
+ fprintf(stderr,"Testing loss of pages (rollback required)... ");
+
+ ogg_sync_reset(&oy);
+ ogg_stream_reset(&os_de);
+ for(i=0;i<5;i++){
+ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+ og[i].header_len);
+ ogg_sync_wrote(&oy,og[i].header_len);
+ memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+ ogg_sync_wrote(&oy,og[i].body_len);
+ }
+
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ /* skip */
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+
+ /* do we get the expected results/packets? */
+
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,0,0,0);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,1,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,2,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,98,3,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,4,5000);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,5,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,1,6,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,2954,7,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,2057,8,9000);
+ if(ogg_stream_packetout(&os_de,&test)!=-1){
+ fprintf(stderr,"Error: loss of page did not return error\n");
+ exit(1);
+ }
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,300,17,18000);
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* the rest only test sync */
+ {
+ ogg_page og_de;
+ /* Test fractional page inputs: incomplete capture */
+ fprintf(stderr,"Testing sync on partial inputs... ");
+ ogg_sync_reset(&oy);
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 3);
+ ogg_sync_wrote(&oy,3);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete fixed header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
+ 5);
+ ogg_sync_wrote(&oy,5);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete body */
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
+ og[1].header_len-28);
+ ogg_sync_wrote(&oy,og[1].header_len-28);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
+ ogg_sync_wrote(&oy,1000);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
+ og[1].body_len-1000);
+ ogg_sync_wrote(&oy,og[1].body_len-1000);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test fractional page inputs: page + incomplete capture */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing sync on 1+partial inputs... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
+ og[1].header_len-20);
+ ogg_sync_wrote(&oy,og[1].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing search for capture... ");
+ ogg_sync_reset(&oy);
+
+ /* 'garbage' */
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
+ og[2].header_len-20);
+ ogg_sync_wrote(&oy,og[2].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len);
+ ogg_sync_wrote(&oy,og[2].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: page + garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing recapture... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len-5);
+ ogg_sync_wrote(&oy,og[2].body_len-5);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
+ og[3].header_len);
+ ogg_sync_wrote(&oy,og[3].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
+ og[3].body_len);
+ ogg_sync_wrote(&oy,og[3].body_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Free page data that was previously copied */
+ {
+ for(i=0;i<5;i++){
+ free_page(&og[i]);
+ }
+ }
+ }
+
+ return(0);
}
+#endif
+
+
+
+
diff --git a/apps/codecs/libtremor/info.c b/apps/codecs/libtremor/info.c
index 9bfa7d03b0..f3ac5f87f6 100644
--- a/apps/codecs/libtremor/info.c
+++ b/apps/codecs/libtremor/info.c
@@ -240,7 +240,7 @@ int vorbis_synthesis_idheader(ogg_packet *op){
char buffer[6];
if(op){
- oggpack_readinit(&opb,op->packet);
+ oggpack_readinit(&opb,op->packet,op->bytes);
if(!op->b_o_s)
return(0); /* Not the initial packet */
@@ -268,7 +268,7 @@ int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op)
oggpack_buffer opb;
if(op){
- oggpack_readinit(&opb,op->packet);
+ oggpack_readinit(&opb,op->packet,op->bytes);
/* Which of the three types of header is this? */
/* Also verify header-ness, vorbis */
diff --git a/apps/codecs/libtremor/ivorbisfile.h b/apps/codecs/libtremor/ivorbisfile.h
index 39a648961a..1aeb0ca84b 100644
--- a/apps/codecs/libtremor/ivorbisfile.h
+++ b/apps/codecs/libtremor/ivorbisfile.h
@@ -56,7 +56,7 @@ typedef struct OggVorbis_File {
int seekable;
ogg_int64_t offset;
ogg_int64_t end;
- ogg_sync_state *oy;
+ ogg_sync_state oy;
/* If the FILE handle isn't seekable (eg, a pipe), only the current
stream appears */
@@ -77,7 +77,7 @@ typedef struct OggVorbis_File {
ogg_int64_t bittrack;
ogg_int64_t samptrack;
- ogg_stream_state *os; /* take physical pages, weld into a logical
+ ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
@@ -87,13 +87,11 @@ typedef struct OggVorbis_File {
} OggVorbis_File;
extern int ov_clear(OggVorbis_File *vf);
- //extern int ov_open(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
- char *initial, long ibytes, ov_callbacks callbacks);
+ const char *initial, long ibytes, ov_callbacks callbacks);
- //extern int ov_test(FILE *f,OggVorbis_File *vf,char *initial,long ibytes);
extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf,
- char *initial, long ibytes, ov_callbacks callbacks);
+ const char *initial, long ibytes, ov_callbacks callbacks);
extern int ov_test_open(OggVorbis_File *vf);
extern long ov_bitrate(OggVorbis_File *vf,int i);
diff --git a/apps/codecs/libtremor/ogg.h b/apps/codecs/libtremor/ogg.h
index 15ca46b3cd..da072184b4 100644
--- a/apps/codecs/libtremor/ogg.h
+++ b/apps/codecs/libtremor/ogg.h
@@ -1,17 +1,17 @@
/********************************************************************
* *
- * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
- * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE 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-2003 *
- * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
- function: subsumed libogg includes
+ function: toplevel libogg include
+ last mod: $Id$
********************************************************************/
#ifndef _OGG_H
@@ -21,241 +21,238 @@
extern "C" {
#endif
+#include <stddef.h>
#include "os_types.h"
-typedef struct ogg_buffer_state{
- struct ogg_buffer *unused_buffers;
- struct ogg_reference *unused_references;
- int outstanding;
- int shutdown;
-} ogg_buffer_state;
-
-typedef struct ogg_buffer {
- unsigned char *data;
- long size;
- int refcount;
-
- union {
- ogg_buffer_state *owner;
- struct ogg_buffer *next;
- } ptr;
-} ogg_buffer;
-
-typedef struct ogg_reference {
- ogg_buffer *buffer;
- long begin;
- long length;
-
- struct ogg_reference *next;
-} ogg_reference;
-
-typedef struct oggpack_buffer {
- int headbit;
- unsigned char *headptr;
- long headend;
-
- /* memory management */
- ogg_reference *head;
- ogg_reference *tail;
-
- /* render the byte/bit counter API constant time */
- long count; /* doesn't count the tail */
-} oggpack_buffer;
+extern const unsigned long mask[] ICONST_ATTR;
-typedef struct oggbyte_buffer {
- ogg_reference *baseref;
+typedef struct {
+ void *iov_base;
+ size_t iov_len;
+} ogg_iovec_t;
+
+typedef struct {
+ long endbyte;
+ int endbit;
- ogg_reference *ref;
+ unsigned char *buffer;
unsigned char *ptr;
- long pos;
- long end;
-} oggbyte_buffer;
+ long storage;
+} oggpack_buffer;
-typedef struct ogg_sync_state {
- /* decode memory management pool */
- ogg_buffer_state *bufferpool;
+/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
- /* stream buffers */
- ogg_reference *fifo_head;
- ogg_reference *fifo_tail;
- long fifo_fill;
+typedef struct {
+ unsigned char *header;
+ long header_len;
+ unsigned char *body;
+ long body_len;
+} ogg_page;
- /* stream sync management */
- int unsynced;
- int headerbytes;
- int bodybytes;
+/* ogg_stream_state contains the current encode/decode state of a logical
+ Ogg bitstream **********************************************************/
-} ogg_sync_state;
+typedef struct {
+ unsigned char *body_data; /* bytes from packet bodies */
+ long body_storage; /* storage elements allocated */
+ long body_fill; /* elements stored; fill mark */
+ long body_returned; /* elements of fill returned */
+
+
+ int *lacing_vals; /* The values that will go to the segment table */
+ ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
+ this way, but it is simple coupled to the
+ lacing fifo */
+ long lacing_storage;
+ long lacing_fill;
+ long lacing_packet;
+ long lacing_returned;
+
+#if 0
+ unsigned char header[282]; /* working space for header encode */
+ int header_fill;
+#endif
+ int e_o_s; /* set when we have buffered the last packet in the
+ logical bitstream */
+ int b_o_s; /* set after we've written the initial page
+ of a logical bitstream */
+ ogg_uint32_t serialno;
+ long pageno;
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a separate abstraction
+ layer) also knows about the gap */
+ ogg_int64_t granulepos;
-typedef struct ogg_stream_state {
- ogg_reference *header_head;
- ogg_reference *header_tail;
- ogg_reference *body_head;
- ogg_reference *body_tail;
-
- int e_o_s; /* set when we have buffered the last
- packet in the logical bitstream */
- int b_o_s; /* set after we've written the initial page
- of a logical bitstream */
- long serialno;
- long pageno;
- ogg_int64_t packetno; /* sequence number for decode; the framing
- knows where there's a hole in the data,
- but we need coupling so that the codec
- (which is in a seperate abstraction
- layer) also knows about the gap */
- ogg_int64_t granulepos;
-
- int lacing_fill;
- ogg_uint32_t body_fill;
-
- /* decode-side state data */
- int holeflag;
- int spanflag;
- int clearflag;
- int laceptr;
- ogg_uint32_t body_fill_next;
-
} ogg_stream_state;
+/* ogg_packet is used to encapsulate the data and metadata belonging
+ to a single raw Ogg/Vorbis packet *************************************/
+
typedef struct {
- ogg_reference *packet;
- long bytes;
- long b_o_s;
- long e_o_s;
- ogg_int64_t granulepos;
- ogg_int64_t packetno; /* sequence number for decode; the framing
- knows where there's a hole in the data,
- but we need coupling so that the codec
- (which is in a seperate abstraction
- layer) also knows about the gap */
+ unsigned char *packet;
+ long bytes;
+ long b_o_s;
+ long e_o_s;
+
+ ogg_int64_t granulepos;
+
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a separate abstraction
+ layer) also knows about the gap */
} ogg_packet;
typedef struct {
- ogg_reference *header;
- int header_len;
- ogg_reference *body;
- long body_len;
-} ogg_page;
+ unsigned char *data;
+ int storage;
+ int fill;
+ int returned;
+
+ int unsynced;
+ int headerbytes;
+ int bodybytes;
+} ogg_sync_state;
/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
+/*
+extern void oggpack_writeinit(oggpack_buffer *b);
+extern int oggpack_writecheck(oggpack_buffer *b);
+extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpack_writealign(oggpack_buffer *b);
+extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpack_reset(oggpack_buffer *b);
+extern void oggpack_writeclear(oggpack_buffer *b); */
+extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+/* extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); */
+
+//extern long oggpack_look(oggpack_buffer *b,int bits);
+static inline long oggpack_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ unsigned long m;
+
+ if(bits<0 || bits>32) return -1;
+ m=mask[bits];
+ bits+=b->endbit;
+
+ if(b->endbyte >= b->storage-4){
+ /* not the main path */
+ if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
+ /* special case to avoid reading b->ptr[0], which might be past the end of
+ the buffer; also skips some useless accounting */
+ else if(!bits)return(0L);
+ }
-extern void oggpack_readinit(oggpack_buffer *b,ogg_reference *r);
-extern long oggpack_look_full(oggpack_buffer *b,int bits);
-extern long oggpack_read(oggpack_buffer *b,register int bits);
-
-/* Inline a few, often called functions */
-
-/* mark read process as having run off the end */
-static inline void _adv_halt(oggpack_buffer *b){
- b->headptr=b->head->buffer->data+b->head->begin+b->head->length;
- b->headend=-1;
- b->headbit=0;
-}
-
-/* spans forward, skipping as many bytes as headend is negative; if
- headend is zero, simply finds next byte. If we're up to the end
- of the buffer, leaves headend at zero. If we've read past the end,
- halt the decode process. */
-static inline void _span(oggpack_buffer *b){
- while(b->headend<1){
- if(b->head->next){
- b->count+=b->head->length;
- b->head=b->head->next;
- b->headptr=b->head->buffer->data+b->head->begin-b->headend;
- b->headend+=b->head->length;
- }else{
- /* we've either met the end of decode, or gone past it. halt
- only if we're past */
- if(b->headend<0 || b->headbit)
- /* read has fallen off the end */
- _adv_halt(b);
-
- break;
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
}
}
+ return(m&ret);
}
-/* limited to 32 at a time */
+extern long oggpack_look1(oggpack_buffer *b);
+
+//extern void oggpack_adv(oggpack_buffer *b,int bits);
static inline void oggpack_adv(oggpack_buffer *b,int bits){
- bits+=b->headbit;
- b->headbit=bits&7;
- b->headptr+=bits/8;
- if((b->headend-=((unsigned)bits)/8)<1)_span(b);
-}
+ bits+=b->endbit;
-static inline long oggpack_look(oggpack_buffer *b, int bits){
- if(bits+b->headbit < b->headend<<3){
- extern const unsigned long oggpack_mask[];
- unsigned long m=oggpack_mask[bits];
- unsigned long ret=-1;
-
- bits+=b->headbit;
- ret=b->headptr[0]>>b->headbit;
- if(bits>8){
- ret|=b->headptr[1]<<(8-b->headbit);
- if(bits>16){
- ret|=b->headptr[2]<<(16-b->headbit);
- if(bits>24){
- ret|=b->headptr[3]<<(24-b->headbit);
- if(bits>32 && b->headbit)
- ret|=b->headptr[4]<<(32-b->headbit);
- }
- }
- }
- return ret&m;
- }else{
- return oggpack_look_full(b, bits);
- }
+ if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return;
+
+ overflow:
+ b->ptr=NULL;
+ b->endbyte=b->storage;
+ b->endbit=1;
}
+extern void oggpack_adv1(oggpack_buffer *b);
+extern long oggpack_read(oggpack_buffer *b,int bits);
+extern long oggpack_read1(oggpack_buffer *b);
+#if 0
+extern long oggpack_bytes(oggpack_buffer *b);
+extern long oggpack_bits(oggpack_buffer *b);
+extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
+
+extern void oggpackB_writeinit(oggpack_buffer *b);
+extern int oggpackB_writecheck(oggpack_buffer *b);
+extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpackB_writealign(oggpack_buffer *b);
+extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpackB_reset(oggpack_buffer *b);
+extern void oggpackB_writeclear(oggpack_buffer *b);
+extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpackB_look(oggpack_buffer *b,int bits);
+extern long oggpackB_look1(oggpack_buffer *b);
+extern void oggpackB_adv(oggpack_buffer *b,int bits);
+extern void oggpackB_adv1(oggpack_buffer *b);
+extern long oggpackB_read(oggpack_buffer *b,int bits);
+extern long oggpackB_read1(oggpack_buffer *b);
+extern long oggpackB_bytes(oggpack_buffer *b);
+extern long oggpackB_bits(oggpack_buffer *b);
+extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
+# endif
+/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
+#if 0
+extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
+extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
+ int count, long e_o_s, ogg_int64_t granulepos);
+extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
+extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
+#endif
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
-extern ogg_sync_state *ogg_sync_create(void);
-extern int ogg_sync_destroy(ogg_sync_state *oy);
+extern int ogg_sync_init(ogg_sync_state *oy);
+extern int ogg_sync_clear(ogg_sync_state *oy);
extern int ogg_sync_reset(ogg_sync_state *oy);
+extern int ogg_sync_destroy(ogg_sync_state *oy);
+extern int ogg_sync_check(ogg_sync_state *oy);
-extern unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long size);
+extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
+extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
/* Ogg BITSTREAM PRIMITIVES: general ***************************/
-extern ogg_stream_state *ogg_stream_create(int serialno);
-extern int ogg_stream_destroy(ogg_stream_state *os);
+extern int ogg_stream_init(ogg_stream_state *os,int serialno);
+extern int ogg_stream_clear(ogg_stream_state *os);
extern int ogg_stream_reset(ogg_stream_state *os);
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
+extern int ogg_stream_destroy(ogg_stream_state *os);
+extern int ogg_stream_check(ogg_stream_state *os);
extern int ogg_stream_eos(ogg_stream_state *os);
-extern int ogg_page_checksum_set(ogg_page *og);
-
-extern int ogg_page_version(ogg_page *og);
-extern int ogg_page_continued(ogg_page *og);
-extern int ogg_page_bos(ogg_page *og);
-extern int ogg_page_eos(ogg_page *og);
-extern ogg_int64_t ogg_page_granulepos(ogg_page *og);
-extern ogg_uint32_t ogg_page_serialno(ogg_page *og);
-extern ogg_uint32_t ogg_page_pageno(ogg_page *og);
-extern int ogg_page_getbuffer(ogg_page *og, unsigned char **buffer);
-
-extern int ogg_packet_release(ogg_packet *op);
-extern int ogg_page_release(ogg_page *og);
-
-extern void ogg_page_dup(ogg_page *d, ogg_page *s);
-
-/* Ogg BITSTREAM PRIMITIVES: return codes ***************************/
+extern void ogg_page_checksum_set(ogg_page *og);
-#define OGG_SUCCESS 0
+extern int ogg_page_version(const ogg_page *og);
+extern int ogg_page_continued(const ogg_page *og);
+extern int ogg_page_bos(const ogg_page *og);
+extern int ogg_page_eos(const ogg_page *og);
+extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
+extern ogg_uint32_t ogg_page_serialno(const ogg_page *og);
+extern long ogg_page_pageno(const ogg_page *og);
+extern int ogg_page_packets(const ogg_page *og);
-#define OGG_HOLE -10
-#define OGG_SPAN -11
-#define OGG_EVERSION -12
-#define OGG_ESERIAL -13
-#define OGG_EINVAL -14
-#define OGG_EEOS -15
+extern void ogg_packet_clear(ogg_packet *op);
#ifdef __cplusplus
diff --git a/apps/codecs/libtremor/synthesis.c b/apps/codecs/libtremor/synthesis.c
index 69180b7acf..c47f381592 100644
--- a/apps/codecs/libtremor/synthesis.c
+++ b/apps/codecs/libtremor/synthesis.c
@@ -37,7 +37,7 @@ static inline int _vorbis_synthesis1(vorbis_block *vb,ogg_packet *op,int decodep
/* first things first. Make sure decode is ready */
_vorbis_block_ripcord(vb);
- oggpack_readinit(opb,op->packet);
+ oggpack_readinit(opb,op->packet,op->bytes);
/* Check the packet type */
if(oggpack_read(opb,1)!=0){
@@ -102,6 +102,8 @@ int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){
return _vorbis_synthesis1(vb,op,1);
}
+/* used to track pcm position without actually performing decode.
+ Useful for sequential 'fast forward' */
int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){
return _vorbis_synthesis1(vb,op,0);
}
@@ -111,7 +113,7 @@ long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
oggpack_buffer opb;
int mode;
- oggpack_readinit(&opb,op->packet);
+ oggpack_readinit(&opb,op->packet,op->bytes);
/* Check the packet type */
if(oggpack_read(&opb,1)!=0){
diff --git a/apps/codecs/libtremor/vorbisfile.c b/apps/codecs/libtremor/vorbisfile.c
index 50a57affbd..9365ba344b 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);
}
}
}
+