* *
********************************************************************
- function: code raw Vorbis packets into framed vorbis stream and
- decode vorbis streams back into raw packets
+ function: code raw [Vorbis] packets into framed OggSquish stream and
+ decode Ogg streams back into raw packets
author: Monty <xiphmont@mit.edu>
modifications by: Monty
- last modification date: Jul 13 1999
+ last modification date: Jul 22 1999
note: The CRC code is directly derived from public domain code by
Ross Williams (ross@guest.adelaide.edu.au). See framing.txt for
#include <string.h>
#include "codec.h"
-/* A complete description of Vorbis framing exists in docs/framing.txt */
+/* A complete description of Ogg framing exists in docs/framing.html */
-int vorbis_page_version(vorbis_page *vg){
- return((int)(vg->header[4]));
+int ogg_page_version(ogg_page *og){
+ return((int)(og->header[4]));
}
-int vorbis_page_continued(vorbis_page *vg){
- return((int)(vg->header[5]&0x01));
+int ogg_page_continued(ogg_page *og){
+ return((int)(og->header[5]&0x01));
}
-int vorbis_page_bos(vorbis_page *vg){
- return((int)(vg->header[5]&0x02));
+int ogg_page_bos(ogg_page *og){
+ return((int)(og->header[5]&0x02));
}
-int vorbis_page_eos(vorbis_page *vg){
- return((int)(vg->header[5]&0x04));
+int ogg_page_eos(ogg_page *og){
+ return((int)(og->header[5]&0x04));
}
-size64 vorbis_page_pcmpos(vorbis_page *vg){
- char *page=vg->header;
- size64 pcmpos=page[13];
- pcmpos= (pcmpos<<8)|page[12];
- pcmpos= (pcmpos<<8)|page[11];
- pcmpos= (pcmpos<<8)|page[10];
- pcmpos= (pcmpos<<8)|page[9];
- pcmpos= (pcmpos<<8)|page[8];
- pcmpos= (pcmpos<<8)|page[7];
- pcmpos= (pcmpos<<8)|page[6];
+size64 ogg_page_frameno(ogg_page *og){
+ unsigned char *page=og->header;
+ size64 pcmpos=page[13]&(0xff);
+ pcmpos= (pcmpos<<8)|(page[12]&0xff);
+ pcmpos= (pcmpos<<8)|(page[11]&0xff);
+ pcmpos= (pcmpos<<8)|(page[10]&0xff);
+ pcmpos= (pcmpos<<8)|(page[9]&0xff);
+ pcmpos= (pcmpos<<8)|(page[8]&0xff);
+ pcmpos= (pcmpos<<8)|(page[7]&0xff);
+ pcmpos= (pcmpos<<8)|(page[6]&0xff);
return(pcmpos);
}
-int vorbis_page_serialno(vorbis_page *vg){
- return(vg->header[14] |
- (vg->header[15]<<8) |
- (vg->header[16]<<16) |
- (vg->header[17]<<24));
+int ogg_page_serialno(ogg_page *og){
+ return(og->header[14] |
+ (og->header[15]<<8) |
+ (og->header[16]<<16) |
+ (og->header[17]<<24));
}
-int vorbis_page_pageno(vorbis_page *vg){
- return(vg->header[18] |
- (vg->header[19]<<8) |
- (vg->header[20]<<16) |
- (vg->header[21]<<24));
+int ogg_page_pageno(ogg_page *og){
+ return(og->header[18] |
+ (og->header[19]<<8) |
+ (og->header[20]<<16) |
+ (og->header[21]<<24));
}
/* helper to initialize lookup for direct-table CRC */
static unsigned size32 crc_lookup[256];
static int crc_ready=0;
-static unsigned size32 _vorbis_crc_entry(unsigned long index){
+static unsigned size32 _ogg_crc_entry(unsigned long index){
int i;
unsigned long r;
/* mind this in threaded code; sync_init and stream_init call it.
It's thread safe only after the first time it returns */
-static void _vorbis_crc_init(void){
+static void _ogg_crc_init(void){
if(!crc_ready){
/* initialize the crc_lookup table */
int i;
for (i=0;i<256;i++)
- crc_lookup[i]=_vorbis_crc_entry((unsigned long)i);
+ crc_lookup[i]=_ogg_crc_entry((unsigned long)i);
crc_ready=0;
}
}
/* init the encode/decode logical stream state */
-int vorbis_stream_init(vorbis_stream_state *vs,int serialno){
- if(vs){
- memset(vs,0,sizeof(vorbis_stream_state));
- vs->body_storage=16*1024;
- vs->body_data=malloc(vs->body_storage*sizeof(char));
+int ogg_stream_init(ogg_stream_state *os,int serialno){
+ if(os){
+ memset(os,0,sizeof(ogg_stream_state));
+ os->body_storage=16*1024;
+ os->body_data=malloc(os->body_storage*sizeof(char));
- vs->lacing_storage=1024;
- vs->lacing_vals=malloc(vs->lacing_storage*sizeof(int));
- vs->pcm_vals=malloc(vs->lacing_storage*sizeof(size64));
+ os->lacing_storage=1024;
+ os->lacing_vals=malloc(os->lacing_storage*sizeof(int));
+ os->pcm_vals=malloc(os->lacing_storage*sizeof(size64));
/* initialize the crc_lookup table if not done */
- _vorbis_crc_init();
+ _ogg_crc_init();
- vs->serialno=serialno;
+ os->serialno=serialno;
return(0);
}
return(-1);
}
-/* _clear does not free vs, only the non-flat storage within */
-int vorbis_stream_clear(vorbis_stream_state *vs){
- if(vs){
- if(vs->body_data)free(vs->body_data);
- if(vs->lacing_vals)free(vs->lacing_vals);
- if(vs->pcm_vals)free(vs->pcm_vals);
+/* _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)free(os->body_data);
+ if(os->lacing_vals)free(os->lacing_vals);
+ if(os->pcm_vals)free(os->pcm_vals);
- memset(vs,0,sizeof(vorbis_stream_state));
+ memset(os,0,sizeof(ogg_stream_state));
}
return(0);
}
-int vorbis_stream_destroy(vorbis_stream_state *vs){
- if(vs){
- vorbis_stream_clear(vs);
- free(vs);
+int ogg_stream_destroy(ogg_stream_state *os){
+ if(os){
+ ogg_stream_clear(os);
+ free(os);
}
return(0);
}
-/* Helpers for vorbis_stream_encode; this keeps the structure and
+/* Helpers for ogg_stream_encode; this keeps the structure and
what's happening fairly clear */
-static void _vs_body_expand(vorbis_stream_state *vs,int needed){
- if(vs->body_storage<=vs->body_fill+needed){
- vs->body_storage+=(needed+1024);
- vs->body_data=realloc(vs->body_data,vs->body_storage);
+static void _os_body_expand(ogg_stream_state *os,int needed){
+ if(os->body_storage<=os->body_fill+needed){
+ os->body_storage+=(needed+1024);
+ os->body_data=realloc(os->body_data,os->body_storage);
}
}
-static void _vs_lacing_expand(vorbis_stream_state *vs,int needed){
- if(vs->lacing_storage<=vs->lacing_fill+needed){
- vs->lacing_storage+=(needed+32);
- vs->lacing_vals=realloc(vs->lacing_vals,vs->lacing_storage*sizeof(int));
- vs->pcm_vals=realloc(vs->pcm_vals,vs->lacing_storage*sizeof(size64));
+static void _os_lacing_expand(ogg_stream_state *os,int needed){
+ if(os->lacing_storage<=os->lacing_fill+needed){
+ os->lacing_storage+=(needed+32);
+ os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int));
+ os->pcm_vals=realloc(os->pcm_vals,os->lacing_storage*sizeof(size64));
}
}
/* Direct table CRC; note that this will be faster in the future if we
perform the checksum silmultaneously with other copies */
-static void _vs_checksum(vorbis_page *vg){
+static void _os_checksum(ogg_page *og){
unsigned size32 crc_reg=0;
int i;
- for(i=0;i<vg->header_len;i++)
- crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^vg->header[i]];
- for(i=0;i<vg->body_len;i++)
- crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^vg->body[i]];
+ 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]];
- vg->header[22]=crc_reg&0xff;
- vg->header[23]=(crc_reg>>8)&0xff;
- vg->header[24]=(crc_reg>>16)&0xff;
- vg->header[25]=(crc_reg>>24)&0xff;
+ og->header[22]=crc_reg&0xff;
+ og->header[23]=(crc_reg>>8)&0xff;
+ og->header[24]=(crc_reg>>16)&0xff;
+ og->header[25]=(crc_reg>>24)&0xff;
}
/* submit data to the internal buffer of the framing engine */
-int vorbis_stream_encode(vorbis_stream_state *vs,vorbis_packet *vp){
- int lacing_vals=vp->bytes/255+1,i;
+int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
+ int lacing_vals=op->bytes/255+1,i;
/* make sure we have the buffer storage */
- _vs_body_expand(vs,vp->bytes);
- _vs_lacing_expand(vs,lacing_vals);
+ _os_body_expand(os,op->bytes);
+ _os_lacing_expand(os,lacing_vals);
/* 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 */
- memcpy(vs->body_data+vs->body_fill,vp->packet,vp->bytes);
- vs->body_fill+=vp->bytes;
+ memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
+ os->body_fill+=op->bytes;
/* Store lacing vals for this packet */
for(i=0;i<lacing_vals-1;i++){
- vs->lacing_vals[vs->lacing_fill+i]=255;
- vs->pcm_vals[vs->lacing_fill+i]=vp->pcm_pos;
+ os->lacing_vals[os->lacing_fill+i]=255;
+ os->pcm_vals[os->lacing_fill+i]=os->pcmpos;
}
- vs->lacing_vals[vs->lacing_fill+i]=(vp->bytes)%255;
- vs->pcm_vals[vs->lacing_fill+i]=vp->pcm_pos;
+ os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
+ os->pcmpos=os->pcm_vals[os->lacing_fill+i]=op->pcm_pos;
/* flag the first segment as the beginning of the packet */
- vs->lacing_vals[vs->lacing_fill]|= 0x100;
+ os->lacing_vals[os->lacing_fill]|= 0x100;
- vs->lacing_fill+=lacing_vals;
+ os->lacing_fill+=lacing_vals;
- if(vp->e_o_s)vs->e_o_s=1;
+ if(op->e_o_s)os->e_o_s=1;
return(0);
}
/* 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 vs) */
+good only until the next call (using the same os) */
-int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg){
+int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
int i;
- if(vs->body_returned){
+ 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 */
- vs->body_fill-=vs->body_returned;
- memmove(vs->body_data,vs->body_data+vs->body_returned,
- (vs->body_fill-vs->body_returned)*sizeof(char));
- vs->body_returned=0;
+ os->body_fill-=os->body_returned;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+os->body_returned,
+ os->body_fill*sizeof(char));
+ os->body_returned=0;
}
- if((vs->e_o_s&&vs->lacing_fill) ||
- vs->body_fill > 4096 ||
- vs->lacing_fill>=255){
+ if((os->e_o_s&&os->lacing_fill) ||
+ os->body_fill > 4096 ||
+ os->lacing_fill>=255){
int vals=0,bytes=0;
- int maxvals=(vs->lacing_fill>255?255:vs->lacing_fill);
+ int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
long acc=0;
- size64 pcm_pos=vs->pcm_vals[0];
+ size64 pcm_pos=os->pcm_vals[0];
/* construct a page */
/* decide how many segments to include */
for(vals=0;vals<maxvals;vals++){
if(acc>4096)break;
- acc+=vs->lacing_vals[vals]&0x0ff;
- if((vs->lacing_vals[vals]&0x0ff)<255)pcm_pos=vs->pcm_vals[vals];
+ acc+=os->lacing_vals[vals]&0x0ff;
+ if((os->lacing_vals[vals]&0x0ff)<255)pcm_pos=os->pcm_vals[vals];
}
/* construct the header in temp storage */
- memcpy(vs->header,"OggS",4);
+ memcpy(os->header,"OggS",4);
/* stream structure version */
- vs->header[4]=0x00;
+ os->header[4]=0x00;
- vs->header[5]=0x00;
+ os->header[5]=0x00;
/* continued packet flag? */
- if((vs->lacing_vals[0]&0x100)==0)vs->header[5]|=0x01;
+ if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
/* first page flag? */
- if(vs->b_o_s==0)vs->header[5]|=0x02;
+ if(os->b_o_s==0)os->header[5]|=0x02;
/* last page flag? */
- if(vs->e_o_s && vs->lacing_fill==vals)vs->header[5]|=0x04;
- vs->b_o_s=1;
+ 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++){
- vs->header[i]=(pcm_pos&0xff);
+ os->header[i]=(pcm_pos&0xff);
pcm_pos>>=8;
}
/* 32 bits of stream serial number */
{
- long serialno=vs->serialno;
+ long serialno=os->serialno;
for(i=14;i<18;i++){
- vs->header[i]=(serialno&0xff);
+ os->header[i]=(serialno&0xff);
serialno>>=8;
}
}
/* 32 bits of page counter (we have both counter and page header
because this val can roll over) */
{
- long pageno=vs->pageno++;
+ long pageno=os->pageno++;
for(i=18;i<22;i++){
- vs->header[i]=(pageno&0xff);
+ os->header[i]=(pageno&0xff);
pageno>>=8;
}
}
/* zero for computation; filled in later */
- vs->header[22]=0;
- vs->header[23]=0;
- vs->header[24]=0;
- vs->header[25]=0;
+ os->header[22]=0;
+ os->header[23]=0;
+ os->header[24]=0;
+ os->header[25]=0;
/* segment table */
- vs->header[26]=vals&0xff;
+ os->header[26]=vals&0xff;
for(i=0;i<vals;i++)
- bytes+=vs->header[i+27]=(vs->lacing_vals[i]&0xff);
+ bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
/* advance the lacing data and set the body_returned pointer */
- vs->lacing_fill-=vals;
- memmove(vs->lacing_vals,vs->lacing_vals+vals,vs->lacing_fill*sizeof(int));
- memmove(vs->pcm_vals,vs->pcm_vals+vals,vs->lacing_fill*sizeof(size64));
- vs->body_returned=bytes;
+ os->lacing_fill-=vals;
+ memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int));
+ memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(size64));
+ os->body_returned=bytes;
- /* set pointers in the vorbis_page struct */
- vg->header=vs->header;
- vg->header_len=vs->header_fill=vals+27;
- vg->body=vs->body_data;
- vg->body_len=bytes;
+ /* set pointers in the ogg_page struct */
+ og->header=os->header;
+ og->header_len=os->header_fill=vals+27;
+ og->body=os->body_data;
+ og->body_len=bytes;
/* calculate the checksum */
- _vs_checksum(vg);
+ _os_checksum(og);
return(1);
}
return(0);
}
-int vorbis_stream_eof(vorbis_stream_state *vs){
- return vs->e_o_s;
+int ogg_stream_eof(ogg_stream_state *os){
+ return os->e_o_s;
}
/* 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 vorbis_decode_buffer(). The app either copies into the
+ using ogg_decode_buffer(). The app either copies into the
buffer, or passes it directly to read(), etc. We then call
- vorbis_decode_wrote() to tell how many bytes we just added.
-
- Pages are returned (pointers into the buffer in vorbis_sync_state)
- by vorbis_decode_stream(). The page is then submitted to
- vorbis_decode_page() along with the appropriate
- vorbis_stream_state* (ie, matching serialno). We then get raw
- packets out calling vorbis_stream_packet() with a
- vorbis_stream_state. See the 'frame-prog.txt' docs for details and
+ ogg_decode_wrote() to tell how many bytes we just added.
+
+ Pages are returned (pointers into the buffer in ogg_sync_state)
+ by ogg_decode_stream(). The page is then submitted to
+ ogg_decode_page() along with the appropriate
+ ogg_stream_state* (ie, matching serialno). We then get raw
+ packets out calling ogg_stream_packet() with a
+ ogg_stream_state. See the 'frame-prog.txt' docs for details and
example code. */
/* initialize the struct to a known state */
-int vorbis_sync_init(vorbis_sync_state *vs){
- if(vs){
- memset(vs,0,sizeof(vorbis_sync_state));
- _vorbis_crc_init();
+int ogg_sync_init(ogg_sync_state *oy){
+ if(oy){
+ memset(oy,0,sizeof(ogg_sync_state));
+ _ogg_crc_init();
}
return(0);
}
/* clear non-flat storage within */
-int vorbis_sync_clear(vorbis_sync_state *vs){
- if(vs){
- if(vs->data)free(vs->data);
- vorbis_sync_init(vs);
+int ogg_sync_clear(ogg_sync_state *oy){
+ if(oy){
+ if(oy->data)free(oy->data);
+ ogg_sync_init(oy);
}
return(0);
}
-char *vorbis_decode_buffer(vorbis_sync_state *vs, long size){
+char *ogg_sync_buffer(ogg_sync_state *oy, long size){
/* first, clear out any space that has been previously returned */
- if(vs->returned){
- vs->fill-=vs->returned;
- if(vs->fill-vs->returned>0)
- memmove(vs->data,vs->data+vs->returned,
- (vs->fill-vs->returned)*sizeof(char));
- vs->returned=0;
+ if(oy->returned){
+ oy->fill-=oy->returned;
+ if(oy->fill>0)
+ memmove(oy->data,oy->data+oy->returned,
+ (oy->fill)*sizeof(char));
+ oy->returned=0;
}
- if(size>vs->storage-vs->fill){
+ if(size>oy->storage-oy->fill){
/* We need to extend the internal buffer */
- long newsize=size+vs->fill+4096; /* an extra page to be nice */
+ long newsize=size+oy->fill+4096; /* an extra page to be nice */
- if(vs->data)
- vs->data=realloc(vs->data,newsize);
+ if(oy->data)
+ oy->data=realloc(oy->data,newsize);
else
- vs->data=malloc(newsize);
- vs->storage=newsize;
+ oy->data=malloc(newsize);
+ oy->storage=newsize;
}
/* expose a segment at least as large as requested at the fill mark */
- return(vs->data+vs->fill);
+ return(oy->data+oy->fill);
}
-int vorbis_decode_wrote(vorbis_sync_state *vs, long bytes){
- if(vs->fill+bytes>vs->storage)return(-1);
- vs->fill+=bytes;
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
+ if(oy->fill+bytes>oy->storage)return(-1);
+ oy->fill+=bytes;
return(0);
}
Returns pointers into buffered data; invalidated by next call to
_stream, _clear, _init, or _buffer */
-int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){
+int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
/* 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 */
while(1){
- char *page=vs->data+vs->returned;
- long bytes=vs->fill-vs->returned;
+ unsigned char *page=oy->data+oy->returned;
+ long bytes=oy->fill-oy->returned;
- if(vs->headerbytes==0){
+ if(oy->headerbytes==0){
int headerbytes,i;
if(bytes<27)return(0); /* not enough for a header */
/* count up body length in the segment table */
for(i=0;i<page[26];i++)
- vs->bodybytes+=page[27+i];
- vs->headerbytes=headerbytes;
+ oy->bodybytes+=page[27+i];
+ oy->headerbytes=headerbytes;
}
- if(vs->bodybytes+vs->headerbytes>bytes)return(0);
+ if(oy->bodybytes+oy->headerbytes>bytes)return(0);
/* The whole test page is buffered. Verify the checksum */
{
/* Grab the checksum bytes, set the header field to zero */
char chksum[4];
- vorbis_page lvg;
+ ogg_page log;
memcpy(chksum,page+22,4);
memset(page+22,0,4);
/* set up a temp page struct and recompute the checksum */
- lvg.header=page;
- lvg.header_len=vs->headerbytes;
- lvg.body=page+vs->headerbytes;
- lvg.body_len=vs->bodybytes;
- _vs_checksum(&lvg);
+ log.header=page;
+ log.header_len=oy->headerbytes;
+ log.body=page+oy->headerbytes;
+ log.body_len=oy->bodybytes;
+ _os_checksum(&log);
/* Compare */
if(memcmp(chksum,page+22,4)){
}
}
- vg->header=page;
- vg->header_len=vs->headerbytes;
- vg->body=page+vs->headerbytes;
- vg->body_len=vs->bodybytes;
+ og->header=page;
+ og->header_len=oy->headerbytes;
+ og->body=page+oy->headerbytes;
+ og->body_len=oy->bodybytes;
- vs->unsynced=0;
- vs->returned+=vs->headerbytes+vs->bodybytes;
- vs->headerbytes=0;
- vs->bodybytes=0;
+ oy->unsynced=0;
+ oy->returned+=oy->headerbytes+oy->bodybytes;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
return(1);
sync_fail:
- vs->headerbytes=0;
- vs->bodybytes=0;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
/* search for possible capture */
page=memchr(page+1,'O',bytes-1);
if(page)
- vs->returned=page-vs->data;
+ oy->returned=page-oy->data;
else
- vs->returned=vs->fill;
+ oy->returned=oy->fill;
- if(!vs->unsynced){
- vs->unsynced=1;
+ if(!oy->unsynced){
+ oy->unsynced=1;
return(-1);
}
/* add the incoming page to the stream state; we decompose the page
into packet segments here as well. */
-int vorbis_decode_page(vorbis_stream_state *vs, vorbis_page *vg){
- unsigned char *header=vg->header;
- unsigned char *body=vg->body;
- long bodysize=vg->body_len;
- int segptr=0;
-
- int version=vorbis_page_version(vg);
- int continued=vorbis_page_continued(vg);
- int bos=vorbis_page_bos(vg);
- int eos=vorbis_page_eos(vg);
- size64 pcmpos=vorbis_page_pcmpos(vg);
- int serialno=vorbis_page_serialno(vg);
- int pageno=vorbis_page_pageno(vg);
+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 version=ogg_page_version(og);
+ int continued=ogg_page_continued(og);
+ int bos=ogg_page_bos(og);
+ int eos=ogg_page_eos(og);
+ size64 pcmpos=ogg_page_frameno(og);
+ int serialno=ogg_page_serialno(og);
+ int pageno=ogg_page_pageno(og);
int segments=header[26];
/* clean up 'returned data' */
{
- long lr=vs->lacing_returned;
- long br=vs->body_returned;
+ long lr=os->lacing_returned;
+ long br=os->body_returned;
/* body data */
- if(vs->body_fill-br)
- memmove(vs->body_data,vs->body_data+br,vs->body_fill-br);
- vs->body_fill-=br;
- vs->body_returned=0;
+ 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;
+ }
- /* segment table */
- if(vs->lacing_fill-lr){
- memmove(vs->lacing_vals,vs->lacing_vals+lr,
- (vs->lacing_fill-lr)*sizeof(int));
- memmove(vs->pcm_vals,vs->pcm_vals+lr,
- (vs->lacing_fill-lr)*sizeof(size64));
+ if(lr){
+ /* segment table */
+ if(os->lacing_fill-lr){
+ memmove(os->lacing_vals,os->lacing_vals+lr,
+ (os->lacing_fill-lr)*sizeof(int));
+ memmove(os->pcm_vals,os->pcm_vals+lr,
+ (os->lacing_fill-lr)*sizeof(size64));
+ }
+ os->lacing_fill-=lr;
+ os->lacing_packet-=lr;
+ os->lacing_returned=0;
}
- vs->lacing_fill-=lr;
- vs->lacing_packet-=lr;
- vs->lacing_returned=0;
}
/* check the serial number */
- if(serialno!=vs->serialno)return(-1);
+ if(serialno!=os->serialno)return(-1);
if(version>0)return(-1);
- _vs_lacing_expand(vs,segments+1);
+ _os_lacing_expand(os,segments+1);
/* are we in sequence? */
- if(pageno!=vs->pageno){
+ if(pageno!=os->pageno){
int i;
/* unroll previous partial packet (if any) */
- for(i=vs->lacing_packet;i<vs->lacing_fill;i++)
- vs->body_fill-=vs->lacing_vals[i]&0xff;
- vs->lacing_fill=vs->lacing_packet;
+ 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 */
- vs->lacing_vals[vs->lacing_fill++]=0x400;
- vs->lacing_packet++;
+ os->lacing_vals[os->lacing_fill++]=0x400;
+ os->lacing_packet++;
/* are we a 'continued packet' page? If so, we'll need to skip
some segments */
}
if(bodysize){
- _vs_body_expand(vs,bodysize);
- memcpy(vs->body_data+vs->body_fill,body,bodysize);
- vs->body_fill+=bodysize;
+ _os_body_expand(os,bodysize);
+ memcpy(os->body_data+os->body_fill,body,bodysize);
+ os->body_fill+=bodysize;
}
- while(segptr<segments){
- int val=header[27+segptr];
- vs->lacing_vals[vs->lacing_fill]=val;
- vs->pcm_vals[vs->lacing_fill]=pcmpos;
-
- if(bos){
- vs->lacing_vals[vs->lacing_fill]|=0x100;
- bos=0;
+ {
+ int saved=-1;
+ while(segptr<segments){
+ int val=header[27+segptr];
+ os->lacing_vals[os->lacing_fill]=val;
+ os->pcm_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 pcmpos on the last pcmval of the last full packet */
+ if(saved!=-1){
+ os->pcm_vals[saved]=pcmpos;
}
- vs->lacing_fill++;
- segptr++;
-
- if(val<255)vs->lacing_packet=vs->lacing_fill;
}
+
if(eos){
- vs->e_o_s=1;
- if(vs->lacing_fill>0)
- vs->lacing_vals[vs->lacing_fill-1]|=0x200;
+ os->e_o_s=1;
+ if(os->lacing_fill>0)
+ os->lacing_vals[os->lacing_fill-1]|=0x200;
}
- vs->pageno=pageno;
+ os->pageno=pageno+1;
return(0);
}
/* clear things to an initial state. Good to call, eg, before seeking */
-int vorbis_sync_reset(vorbis_sync_state *vs){
- vs->fill=0;
- vs->returned=0;
- vs->unsynced=0;
- vs->headerbytes=0;
- vs->bodybytes=0;
+int ogg_sync_reset(ogg_sync_state *oy){
+ oy->fill=0;
+ oy->returned=0;
+ oy->unsynced=0;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
return(0);
}
-int vorbis_stream_reset(vorbis_stream_state *vs){
- vs->body_fill=0;
- vs->body_returned=0;
+int ogg_stream_reset(ogg_stream_state *os){
+ os->body_fill=0;
+ os->body_returned=0;
- vs->lacing_fill=0;
- vs->lacing_packet=0;
- vs->lacing_returned=0;
+ os->lacing_fill=0;
+ os->lacing_packet=0;
+ os->lacing_returned=0;
- vs->header_fill=0;
+ os->header_fill=0;
- vs->e_o_s=0;
- vs->b_o_s=0;
- vs->pageno=0;
- vs->pcmpos=0;
+ os->e_o_s=0;
+ os->b_o_s=0;
+ os->pageno=0;
+ os->pcmpos=0;
return(0);
}
-int vorbis_stream_packet(vorbis_stream_state *vs,vorbis_packet *vp){
+int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
/* 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) */
- int ptr=vs->lacing_returned;
+ int ptr=os->lacing_returned;
- if(vs->lacing_packet<=ptr)return(0);
- if(vs->lacing_vals[ptr]&=0x400){
+ if(os->lacing_packet<=ptr)return(0);
+ if(os->lacing_vals[ptr]&0x400){
/* We lost sync here; let the app know */
- vs->lacing_returned++;
+ os->lacing_returned++;
return(-1);
}
/* Gather the whole packet. We'll have no holes or a partial packet */
{
- int size=vs->lacing_vals[ptr]&0xff;
+ int size=os->lacing_vals[ptr]&0xff;
int bytes=0;
- vp->packet=vs->body_data+vs->body_returned;
- vp->e_o_s=vs->lacing_vals[ptr]&0x200; /* last packet of the stream? */
- vp->b_o_s=vs->lacing_vals[ptr]&0x100; /* first packet of the stream? */
+ op->packet=os->body_data+os->body_returned;
+ op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
+ op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
bytes+=size;
while(size==255){
- int val=vs->lacing_vals[++ptr];
+ int val=os->lacing_vals[++ptr];
size=val&0xff;
- if(val&0x200)vp->e_o_s=0x200;
+ if(val&0x200)op->e_o_s=0x200;
bytes+=size;
}
- vp->pcm_pos=vs->pcm_vals[ptr];
- vp->bytes=bytes;
+ op->pcm_pos=os->pcm_vals[ptr];
+ op->bytes=bytes;
- vs->body_returned+=bytes;
- vs->lacing_returned=ptr+1;
+ os->body_returned+=bytes;
+ os->lacing_returned=ptr+1;
}
return(1);
}
#ifdef _V_SELFTEST
#include <stdio.h>
-void test_pack(vorbis_stream_state *vs,int *pl, int **headers){
+ogg_stream_state os_en, os_de;
+ogg_sync_state oy;
+
+void checkpacket(ogg_packet *op,int len, int no, int pos){
+ long j;
+ if(op->bytes!=len){
+ fprintf(stderr,"incorrect packet length!\n");
+ exit(1);
+ }
+ if(op->pcm_pos!=pos){
+ fprintf(stderr,"incorrect packet position!\n");
+ exit(1);
+ }
+
+ /* Test data */
+ for(j=0;j<op->bytes;j++)
+ if(op->packet[j]!=((j+no)&0xff)){
+ fprintf(stderr,"body data mismatch at pos %ld: %x!=%lx!\n\n",
+ j,op->packet[j],(j+no)&0xff);
+ exit(1);
+ }
+}
+
+void check_page(unsigned char *data,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 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);
+ }
+ }
+ 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," pcmpos: %d serialno: %d pageno: %d\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],
+ (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 copy_page(ogg_page *og){
+ char *temp=malloc(og->header_len);
+ memcpy(temp,og->header,og->header_len);
+ og->header=temp;
+
+ temp=malloc(og->body_len);
+ memcpy(temp,og->body,og->body_len);
+ og->body=temp;
+}
+
+void error(void){
+ fprintf(stderr,"error!\n");
+ exit(1);
+}
+
+void test_pack(int *pl, int **headers){
unsigned char *data=malloc(1024*1024); /* for scripted test cases only */
long inptr=0;
long outptr=0;
- long pcm_pos=0;
- int i,j,packets,pageno=0;
+ long deptr=0;
+ long depacket=0;
+ long pcm_pos=7;
+ int i,j,packets,pageno=0,pageout=0;
+ int eosflag=0;
+ int bosflag=0;
+
+ ogg_stream_reset(&os_en);
+ ogg_stream_reset(&os_de);
+ ogg_sync_reset(&oy);
for(packets=0;;packets++)if(pl[packets]==-1)break;
for(i=0;i<packets;i++){
/* construct a test packet */
- vorbis_packet vp;
+ ogg_packet op;
int len=pl[i];
- vp.packet=data+inptr;
- vp.bytes=len;
- vp.e_o_s=(pl[i+1]<0?1:0);
- vp.pcm_pos=pcm_pos;
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.pcm_pos=pcm_pos;
pcm_pos+=1024;
for(j=0;j<len;j++)data[inptr++]=i+j;
/* submit the test packet */
- vorbis_stream_encode(vs,&vp);
+ ogg_stream_packetin(&os_en,&op);
/* retrieve any finished pages */
{
- vorbis_page vg;
+ ogg_page og;
- while(vorbis_stream_page(vs,&vg)){
+ while(ogg_stream_pageout(&os_en,&og)){
/* We have a page. Check it carefully */
fprintf(stderr,"%d, ",pageno);
exit(1);
}
- /* Test data */
- for(j=0;j<vg.body_len;j++)
- if(vg.body[j]!=(data+outptr)[j]){
- fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
- outptr+j,(data+outptr)[j],vg.body[j]);
- exit(1);
- }
- outptr+=vg.body_len;
-
- /* Test header */
- for(j=0;j<vg.header_len;j++){
- if(vg.header[j]!=headers[pageno][j]){
- fprintf(stderr,"header content mismatch at pos %ld:\n",j);
- for(j=0;j<headers[pageno][26]+27;j++)
- fprintf(stderr," (%d)%02x:%02x",j,headers[pageno][j],vg.header[j]);
- fprintf(stderr,"\n");
- exit(1);
+ check_page(data+outptr,headers[pageno],&og);
+
+ outptr+=og.body_len;
+ pageno++;
+
+ /* have a complete page; submit it to sync/decode */
+
+ {
+ ogg_page og_de;
+ ogg_packet op_de;
+ char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
+ memcpy(buf,og.header,og.header_len);
+ memcpy(buf+og.header_len,og.body,og.body_len);
+ ogg_sync_wrote(&oy,og.header_len+og.body_len);
+
+ while(ogg_sync_pageout(&oy,&og_de)>0){
+ /* got a page. Happy happy. Verify that it's good. */
+
+ 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_packetout(&os_de,&op_de)>0){
+
+ /* 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 pcmpos flag */
+ if(op_de.pcm_pos!=-1){
+ fprintf(stderr," pcm:%ld ",(long)op_de.pcm_pos);
+ }
+ }
}
}
- if(vg.header_len!=headers[pageno][26]+27){
- fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
- vg.header_len,headers[pageno][26]+27);
- exit(1);
- }
- pageno++;
}
}
}
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,"packet data incomplete!\n");
+ 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){
- vorbis_stream_state vs;
+
+ 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, 254, 255, 256, 500, 510, 600 byte, pad */
int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0,
- 0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0x7e,0xea,0x18,0xd0,
+ 0x46,0x39,0xee,0xcb,
14,
17,254,255,0,255,1,255,245,255,255,0,
255,255,90};
int *headret[]={head1,NULL};
- vorbis_stream_init(&vs,0x04030201);
fprintf(stderr,"testing basic page encoding... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ test_pack(packets,headret);
}
{
/* nil packets; beginning,middle,end */
int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0,
- 0x00,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0xcf,0x70,0xa4,0x1b,
+ 0xf6,0x56,0x56,0x9e,
18,
0,17,254,255,0,0,255,1,0,255,245,255,255,0,
255,255,90,0};
int *headret[]={head1,NULL};
- vorbis_stream_init(&vs,0x04030201);
fprintf(stderr,"testing basic nil packets... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ test_pack(packets,headret);
}
{
/* starting new page with first segment */
int packets[]={4345,259,255,-1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0xe7,0xdc,0x6d,0x09,
+ 0x7e,0x3e,0xa9,0x86,
17,
255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255};
- int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
- 0x00,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head2[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,1,0,0,0,
- 0x5f,0x54,0x07,0x69,
+ 0x28,0x26,0x8c,0x6a,
5,
10,255,4,255,0};
int *headret[]={head1,head2,NULL};
- vorbis_stream_init(&vs,0x04030201);
fprintf(stderr,"testing single-packet page span... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ test_pack(packets,headret);
}
{
- /* starting new page with first segment */
int packets[]={100,4345,259,255,-1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
- 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0x6f,0xac,0x43,0x67,
+ 0x9f,0x45,0x89,0x8c,
17,
100,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255};
- int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
- 0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head2[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,1,0,0,0,
- 0xe7,0xa3,0x34,0x53,
+ 0xe6,0x35,0xfc,0xb7,
6,
255,10,255,4,255,0};
int *headret[]={head1,head2,NULL};
- vorbis_stream_init(&vs,0x04030201);
fprintf(stderr,"testing multi-packet page span... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ test_pack(packets,headret);
}
10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,50,-1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
- 0x00,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x07,0xf8,0x03,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0xb1,0xd0,0xab,0xbc,
+ 0x2f,0xe5,0xf5,0x43,
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};
- int head2[] = {0x4f,0x67,0x67,0x53,0,0x01,
- 0x00,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,1,0,0,0,
- 0xb1,0x1e,0x4f,0x41,
+ 0x46,0x8b,0x88,0x90,
1,
50};
int *headret[]={head1,head2,NULL};
- vorbis_stream_init(&vs,0x04030201);
fprintf(stderr,"testing max packet segments... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ test_pack(packets,headret);
}
{
int packets[]={100,9000,259,255,-1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
- 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0x6f,0xac,0x43,0x67,
+ 0x9f,0x45,0x89,0x8c,
17,
100,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255};
- int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
- 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head2[] = {0x4f,0x67,0x67,0x53,0,0x01,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,1,0,0,0,
- 0x65,0x4e,0xbd,0x96,
+ 0xaf,0x9d,0xf1,0x76,
17,
255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255};
- int head3[] = {0x4f,0x67,0x67,0x53,0,0x02,
- 0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,2,0,0,0,
- 0x84,0x86,0x86,0xf4,
+ 0xe1,0x61,0x9f,0xbd,
7,
255,255,75,255,4,255,0};
int *headret[]={head1,head2,head3,NULL};
- vorbis_stream_init(&vs,0x04030201);
fprintf(stderr,"testing very large packets... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ test_pack(packets,headret);
}
{
- /* nil page. why not? */
+ /* term only page. why not? */
int packets[]={100,4080,-1};
- int head1[] = {0x4f,0x67,0x67,0x53,0,0x00,
- 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,0,0,0,0,
- 0x6f,0xac,0x43,0x67,
+ 0x9f,0x45,0x89,0x8c,
17,
100,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255};
- int head2[] = {0x4f,0x67,0x67,0x53,0,0x02,
- 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ int head2[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
0x01,0x02,0x03,0x04,1,0,0,0,
- 0x71,0xc8,0x17,0x8c,
+ 0xf1,0x29,0xfc,0x4c,
1,0};
int *headret[]={head1,head2,NULL};
- vorbis_stream_init(&vs,0x04030201);
- fprintf(stderr,"testing nil page... ");
- test_pack(&vs,packets,headret);
- vorbis_stream_clear(&vs);
+ fprintf(stderr,"testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret);
}
-
+
+
+ {
+ /* build a bunch of pages for testing */
+ unsigned char *data=malloc(1024*1024);
+ int pl[]={100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
+ int inptr=0,i,j;
+ ogg_page og[4];
+
+ 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.pcm_pos=(i+1)*1000;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+ ogg_stream_packetin(&os_en,&op);
+ }
+
+ free(data);
+
+ /* retrieve finished pages */
+ for(i=0;i<4;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<4;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);
+ /* 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,100,0,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,1,2000);
+ 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,4,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,34,5,-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<4;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,100,0,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,1,2000);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,2956,2,3000);
+ 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,12,13000);
+ 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[0].header_len),og[0].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[0].header_len),og[0].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[0].header_len),og[0].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[0].header_len),og[0].header+28,
+ og[0].header_len-28);
+ ogg_sync_wrote(&oy,og[0].header_len-28);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,1000);
+ ogg_sync_wrote(&oy,1000);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body+1000,
+ og[0].body_len-1000);
+ ogg_sync_wrote(&oy,og[0].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[0].header_len),og[0].header,
+ og[0].header_len);
+ ogg_sync_wrote(&oy,og[0].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+ og[0].body_len);
+ ogg_sync_wrote(&oy,og[0].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[0].body_len),og[0].body,
+ og[0].body_len);
+ ogg_sync_wrote(&oy,og[0].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header,
+ og[0].header_len);
+ ogg_sync_wrote(&oy,og[0].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+ og[0].body_len);
+ ogg_sync_wrote(&oy,og[0].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();
+ 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: page + garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing recapture... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[0].header_len),og[0].header,
+ og[0].header_len);
+ ogg_sync_wrote(&oy,og[0].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[0].body_len),og[0].body,
+ og[0].body_len);
+ ogg_sync_wrote(&oy,og[0].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].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len-5);
+ ogg_sync_wrote(&oy,og[1].body_len-5);
+
+ 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].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();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+ }
return(0);
}