From 99c8220f4f49cbe65b234b5127017d2958fd6f54 Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 22 Jul 1999 10:52:11 +0000 Subject: [PATCH] Finished all unit tests for framing; passes all tests Monty 19990722 svn path=/trunk/vorbis/; revision=9 --- lib/codec.h | 83 ++-- lib/framing.c | 1184 +++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 846 insertions(+), 421 deletions(-) diff --git a/lib/codec.h b/lib/codec.h index a4c8f35..f1bef8b 100644 --- a/lib/codec.h +++ b/lib/codec.h @@ -71,7 +71,7 @@ typedef struct { long header_len; unsigned char *body; long body_len; -} vorbis_page; +} ogg_page; typedef struct { @@ -111,7 +111,7 @@ typedef struct { long pageno; size64 pcmpos; -} vorbis_stream_state; +} ogg_stream_state; typedef struct { unsigned char *packet; @@ -121,10 +121,10 @@ typedef struct { size64 pcm_pos; -} vorbis_packet; +} ogg_packet; typedef struct { - char *data; + unsigned char *data; int storage; int fill; int returned; @@ -132,11 +132,11 @@ typedef struct { int unsynced; int headerbytes; int bodybytes; -} vorbis_sync_state; +} ogg_sync_state; /* libvorbis encodes in two abstraction layers; first we perform DSP and produce a packet (see docs/analysis.txt). The packet is then - coded into a framed bitstream by the second layer (see + coded into a framed OggSquish bitstream by the second layer (see docs/framing.txt). Decode is the reverse process; we sync/frame the bitstream and extract individual packets, then decode the packet back into PCM audio. @@ -146,53 +146,52 @@ typedef struct { packetization aren't necessary as they're provided by the transport and the streaming layer is not used */ -/* ENCODING PRIMITIVES: analysis/DSP layer **************************/ +/* OggSquish BITSREAM PRIMITIVES: encoding **************************/ -extern int vorbis_analysis_init(vorbis_dsp_state *vd,vorbis_info *i); -extern void vorbis_dsp_state_free(vorbis_dsp_state *vd); -extern int vorbis_analysis_input(vorbis_dsp_state *vd,double **pcm,int vals); -extern int vorbis_analysis(vorbis_dsp_state *vd,vorbis_packet *vp); - -/* GENERAL PRIMITIVES: packet streaming layer ***********************/ +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); -extern int vorbis_stream_init(vorbis_stream_state *vs,int serialno); -extern int vorbis_stream_clear(vorbis_stream_state *vs); -extern int vorbis_stream_destroy(vorbis_stream_state *vs); -extern int vorbis_stream_eof(vorbis_stream_state *vs); +/* OggSquish BITSREAM PRIMITIVES: decoding **************************/ -extern int vorbis_page_version(vorbis_page *vg); -extern int vorbis_page_continued(vorbis_page *vg); -extern int vorbis_page_bos(vorbis_page *vg); -extern int vorbis_page_eos(vorbis_page *vg); -extern size64 vorbis_page_pcmpos(vorbis_page *vg); -extern int vorbis_page_serialno(vorbis_page *vg); -extern int vorbis_page_pageno(vorbis_page *vg); +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); -/* ENCODING PRIMITIVES: packet streaming layer **********************/ +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +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 vorbis_stream_encode(vorbis_stream_state *vs,vorbis_packet *vp); -extern int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg); +/* OggSquish BITSREAM PRIMITIVES: general ***************************/ -/* DECODING PRIMITIVES: packet streaming layer **********************/ +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_destroy(ogg_stream_state *os); +extern int ogg_stream_eof(ogg_stream_state *os); -extern int vorbis_sync_init(vorbis_sync_state *vs); -extern int vorbis_sync_clear(vorbis_sync_state *vs); -extern int vorbis_sync_destroy(vorbis_sync_state *vs); +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 size64 ogg_page_frameno(ogg_page *og); +extern int ogg_page_serialno(ogg_page *og); +extern int ogg_page_pageno(ogg_page *og); -extern char *vorbis_decode_buffer(vorbis_sync_state *vs, long size); -extern int vorbis_decode_wrote(vorbis_sync_state *vs, long bytes); -extern int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg); -extern int vorbis_decode_page(vorbis_stream_state *vs, vorbis_page *vg); -extern int vorbis_stream_packet(vorbis_stream_state *vs,vorbis_packet *vp); +/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ -extern int vorbis_sync_reset(vorbis_sync_state *vs); -extern int vorbis_stream_reset(vorbis_stream_state *vs); +extern int vorbis_analysis_init(vorbis_dsp_state *vd,vorbis_info *vi); +extern void vorbis_dsp_state_free(vorbis_dsp_state *vd); +extern int vorbis_analysis_input(vorbis_dsp_state *vd,double **pcm,int vals); +extern int vorbis_analysis(vorbis_dsp_state *vd,ogg_packet *op); -/* DECODING PRIMITIVES: synthesis layer *****************************/ +/* Vorbis PRIMITIVES: synthesis layer *******************************/ -extern int vorbis_synthesis_info(vorbis_dsp_state *vd,vorbis_info *vi); -extern int vorbis_synthesis(vorbis_dsp_state *vd,vorbis_packet *vp); -extern int vorbis_synthesis_output(vorbis_dsp_state *vd,double **pcm); +extern int vorbis_synthesis_info(vorbis_dsp_state *vd,vorbis_info *vi); +extern int vorbis_synthesis_packet(vorbis_dsp_state *vd,ogg_packet *op); +extern int vorbis_synthesis_output(vorbis_dsp_state *vd,double **pcm); #endif diff --git a/lib/framing.c b/lib/framing.c index 1a9fdb1..3000d8f 100644 --- a/lib/framing.c +++ b/lib/framing.c @@ -11,11 +11,11 @@ * * ******************************************************************** - 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 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 @@ -27,49 +27,49 @@ #include #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 */ @@ -77,7 +77,7 @@ int vorbis_page_pageno(vorbis_page *vg){ 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; @@ -96,73 +96,73 @@ static unsigned size32 _vorbis_crc_entry(unsigned long index){ /* 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)); } } @@ -170,116 +170,117 @@ static void _vs_lacing_expand(vorbis_stream_state *vs,int needed){ /* 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;iheader_len;i++) - crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^vg->header[i]]; - for(i=0;ibody_len;i++) - crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^vg->body[i]]; + for(i=0;iheader_len;i++) + crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]]; + for(i=0;ibody_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;ilacing_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;vals4096)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; } } @@ -287,40 +288,40 @@ int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg){ /* 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;iheader[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); } @@ -329,73 +330,73 @@ int vorbis_stream_page(vorbis_stream_state *vs, vorbis_page *vg){ 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); } @@ -406,17 +407,17 @@ int vorbis_decode_wrote(vorbis_sync_state *vs, long bytes){ 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 */ @@ -429,27 +430,27 @@ int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){ /* count up body length in the segment table */ for(i=0;ibodybytes+=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)){ @@ -463,33 +464,33 @@ int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){ } } - 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); } @@ -501,62 +502,66 @@ int vorbis_decode_stream(vorbis_sync_state *vs, vorbis_page *vg){ /* 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;ilacing_fill;i++) - vs->body_fill-=vs->lacing_vals[i]&0xff; - vs->lacing_fill=vs->lacing_packet; + for(i=os->lacing_packet;ilacing_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 */ @@ -575,101 +580,113 @@ int vorbis_decode_page(vorbis_stream_state *vs, vorbis_page *vg){ } 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(segptrlacing_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(segptrlacing_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); } @@ -677,37 +694,135 @@ int vorbis_stream_packet(vorbis_stream_state *vs,vorbis_packet *vp){ #ifdef _V_SELFTEST #include -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;jbytes;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;jbody_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;jheader_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;jheader[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;jheader_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;i0){ + /* 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++; } } } @@ -750,15 +902,34 @@ void test_pack(vorbis_stream_state *vs,int *pl, int **headers){ 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. */ @@ -766,90 +937,81 @@ int main(void){ { /* 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); } @@ -889,10 +1051,10 @@ int main(void){ 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, @@ -927,18 +1089,16 @@ int main(void){ 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); } { @@ -946,64 +1106,330 @@ int main(void){ 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;j0)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); } -- 2.7.4