1 /********************************************************************
3 * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
5 * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
6 * PLEASE READ THESE TERMS DISTRIBUTING. *
8 * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
9 * by Monty <monty@xiph.org> and the XIPHOPHORUS Company *
10 * http://www.xiph.org/ *
12 ********************************************************************
14 function: code raw [Vorbis] packets into framed OggSquish stream and
15 decode Ogg streams back into raw packets
16 last mod: $Id: framing.c,v 1.14 2000/01/12 11:34:40 xiphmont Exp $
18 note: The CRC code is directly derived from public domain code by
19 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
22 ********************************************************************/
26 #include "vorbis/codec.h"
28 /* A complete description of Ogg framing exists in docs/framing.html */
30 int ogg_page_version(ogg_page *og){
31 return((int)(og->header[4]));
34 int ogg_page_continued(ogg_page *og){
35 return((int)(og->header[5]&0x01));
38 int ogg_page_bos(ogg_page *og){
39 return((int)(og->header[5]&0x02));
42 int ogg_page_eos(ogg_page *og){
43 return((int)(og->header[5]&0x04));
46 int64_t ogg_page_frameno(ogg_page *og){
47 unsigned char *page=og->header;
48 int64_t pcmpos=page[13]&(0xff);
49 pcmpos= (pcmpos<<8)|(page[12]&0xff);
50 pcmpos= (pcmpos<<8)|(page[11]&0xff);
51 pcmpos= (pcmpos<<8)|(page[10]&0xff);
52 pcmpos= (pcmpos<<8)|(page[9]&0xff);
53 pcmpos= (pcmpos<<8)|(page[8]&0xff);
54 pcmpos= (pcmpos<<8)|(page[7]&0xff);
55 pcmpos= (pcmpos<<8)|(page[6]&0xff);
59 int ogg_page_serialno(ogg_page *og){
60 return(og->header[14] |
62 (og->header[16]<<16) |
63 (og->header[17]<<24));
66 int ogg_page_pageno(ogg_page *og){
67 return(og->header[18] |
69 (og->header[20]<<16) |
70 (og->header[21]<<24));
73 /* helper to initialize lookup for direct-table CRC */
75 static u_int32_t crc_lookup[256];
76 static int crc_ready=0;
78 static u_int32_t _ogg_crc_entry(unsigned long index){
85 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
86 polynomial, although we use an
87 unreflected alg and an init/final
88 of 0, not 0xffffffff */
91 return (r & 0xffffffffUL);
94 /* mind this in threaded code; sync_init and stream_init call it.
95 It's thread safe only after the first time it returns */
97 static void _ogg_crc_init(void){
99 /* initialize the crc_lookup table */
102 crc_lookup[i]=_ogg_crc_entry((unsigned long)i);
107 /* init the encode/decode logical stream state */
109 int ogg_stream_init(ogg_stream_state *os,int serialno){
111 memset(os,0,sizeof(ogg_stream_state));
112 os->body_storage=16*1024;
113 os->body_data=malloc(os->body_storage*sizeof(char));
115 os->lacing_storage=1024;
116 os->lacing_vals=malloc(os->lacing_storage*sizeof(int));
117 os->pcm_vals=malloc(os->lacing_storage*sizeof(int64_t));
119 /* initialize the crc_lookup table if not done */
122 os->serialno=serialno;
129 /* _clear does not free os, only the non-flat storage within */
130 int ogg_stream_clear(ogg_stream_state *os){
132 if(os->body_data)free(os->body_data);
133 if(os->lacing_vals)free(os->lacing_vals);
134 if(os->pcm_vals)free(os->pcm_vals);
136 memset(os,0,sizeof(ogg_stream_state));
141 int ogg_stream_destroy(ogg_stream_state *os){
143 ogg_stream_clear(os);
149 /* Helpers for ogg_stream_encode; this keeps the structure and
150 what's happening fairly clear */
152 static void _os_body_expand(ogg_stream_state *os,int needed){
153 if(os->body_storage<=os->body_fill+needed){
154 os->body_storage+=(needed+1024);
155 os->body_data=realloc(os->body_data,os->body_storage);
159 static void _os_lacing_expand(ogg_stream_state *os,int needed){
160 if(os->lacing_storage<=os->lacing_fill+needed){
161 os->lacing_storage+=(needed+32);
162 os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int));
163 os->pcm_vals=realloc(os->pcm_vals,os->lacing_storage*sizeof(int64_t));
167 /* checksum the page */
168 /* Direct table CRC; note that this will be faster in the future if we
169 perform the checksum silmultaneously with other copies */
171 static void _os_checksum(ogg_page *og){
175 for(i=0;i<og->header_len;i++)
176 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
177 for(i=0;i<og->body_len;i++)
178 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
180 og->header[22]=crc_reg&0xff;
181 og->header[23]=(crc_reg>>8)&0xff;
182 og->header[24]=(crc_reg>>16)&0xff;
183 og->header[25]=(crc_reg>>24)&0xff;
186 /* submit data to the internal buffer of the framing engine */
187 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
188 int lacing_vals=op->bytes/255+1,i;
190 /* make sure we have the buffer storage */
191 _os_body_expand(os,op->bytes);
192 _os_lacing_expand(os,lacing_vals);
194 /* Copy in the submitted packet. Yes, the copy is a waste; this is
195 the liability of overly clean abstraction for the time being. It
196 will actually be fairly easy to eliminate the extra copy in the
199 memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
200 os->body_fill+=op->bytes;
202 /* Store lacing vals for this packet */
203 for(i=0;i<lacing_vals-1;i++){
204 os->lacing_vals[os->lacing_fill+i]=255;
205 os->pcm_vals[os->lacing_fill+i]=os->pcmpos;
207 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
208 os->pcmpos=os->pcm_vals[os->lacing_fill+i]=op->frameno;
210 /* flag the first segment as the beginning of the packet */
211 os->lacing_vals[os->lacing_fill]|= 0x100;
213 os->lacing_fill+=lacing_vals;
215 /* for the sake of completeness */
218 if(op->e_o_s)os->e_o_s=1;
223 /* This constructs pages from buffered packet segments. The pointers
224 returned are to static buffers; do not free. The returned buffers are
225 good only until the next call (using the same ogg_stream_state) */
227 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
230 if(os->body_returned){
231 /* advance packet data according to the body_returned pointer. We
232 had to keep it around to return a pointer into the buffer last
235 os->body_fill-=os->body_returned;
237 memmove(os->body_data,os->body_data+os->body_returned,
238 os->body_fill*sizeof(char));
242 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
243 os->body_fill > 4096 || /* 'page nominal size' case */
244 os->lacing_fill>=255 || /* 'segment table full' case */
245 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
248 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
250 int64_t pcm_pos=os->pcm_vals[0];
252 /* construct a page */
253 /* decide how many segments to include */
255 /* If this is the initial header case, the first page must only include
256 the initial header packet */
257 if(os->b_o_s==0){ /* 'initial header page' case */
259 for(vals=0;vals<maxvals;vals++){
260 if((os->lacing_vals[vals]&0x0ff)<255){
266 for(vals=0;vals<maxvals;vals++){
268 acc+=os->lacing_vals[vals]&0x0ff;
269 pcm_pos=os->pcm_vals[vals];
273 /* construct the header in temp storage */
274 memcpy(os->header,"OggS",4);
276 /* stream structure version */
279 /* continued packet flag? */
281 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
282 /* first page flag? */
283 if(os->b_o_s==0)os->header[5]|=0x02;
284 /* last page flag? */
285 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
288 /* 64 bits of PCM position */
290 os->header[i]=(pcm_pos&0xff);
294 /* 32 bits of stream serial number */
296 long serialno=os->serialno;
298 os->header[i]=(serialno&0xff);
303 /* 32 bits of page counter (we have both counter and page header
304 because this val can roll over) */
306 long pageno=os->pageno++;
308 os->header[i]=(pageno&0xff);
313 /* zero for computation; filled in later */
320 os->header[26]=vals&0xff;
322 bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
324 /* advance the lacing data and set the body_returned pointer */
326 os->lacing_fill-=vals;
327 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int));
328 memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(int64_t));
329 os->body_returned=bytes;
331 /* set pointers in the ogg_page struct */
332 og->header=os->header;
333 og->header_len=os->header_fill=vals+27;
334 og->body=os->body_data;
337 /* calculate the checksum */
344 /* not enough data to construct a page and not end of stream */
348 int ogg_stream_eof(ogg_stream_state *os){
352 /* DECODING PRIMITIVES: packet streaming layer **********************/
354 /* This has two layers to place more of the multi-serialno and paging
355 control in the application's hands. First, we expose a data buffer
356 using ogg_decode_buffer(). The app either copies into the
357 buffer, or passes it directly to read(), etc. We then call
358 ogg_decode_wrote() to tell how many bytes we just added.
360 Pages are returned (pointers into the buffer in ogg_sync_state)
361 by ogg_decode_stream(). The page is then submitted to
362 ogg_decode_page() along with the appropriate
363 ogg_stream_state* (ie, matching serialno). We then get raw
364 packets out calling ogg_stream_packet() with a
365 ogg_stream_state. See the 'frame-prog.txt' docs for details and
368 /* initialize the struct to a known state */
369 int ogg_sync_init(ogg_sync_state *oy){
371 memset(oy,0,sizeof(ogg_sync_state));
377 /* clear non-flat storage within */
378 int ogg_sync_clear(ogg_sync_state *oy){
380 if(oy->data)free(oy->data);
386 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
388 /* first, clear out any space that has been previously returned */
390 oy->fill-=oy->returned;
392 memmove(oy->data,oy->data+oy->returned,
393 (oy->fill)*sizeof(char));
397 if(size>oy->storage-oy->fill){
398 /* We need to extend the internal buffer */
399 long newsize=size+oy->fill+4096; /* an extra page to be nice */
402 oy->data=realloc(oy->data,newsize);
404 oy->data=malloc(newsize);
408 /* expose a segment at least as large as requested at the fill mark */
409 return((char *)oy->data+oy->fill);
412 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
413 if(oy->fill+bytes>oy->storage)return(-1);
418 /* sync the stream. This is meant to be useful for finding page
421 return values for this:
423 0) page not ready; more data (no bytes skipped)
424 n) page synced at current location; page length n bytes
428 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
429 unsigned char *page=oy->data+oy->returned;
431 long bytes=oy->fill-oy->returned;
433 if(oy->headerbytes==0){
435 if(bytes<27)return(0); /* not enough for a header */
437 /* verify capture pattern */
438 if(memcmp(page,"OggS",4))goto sync_fail;
440 headerbytes=page[26]+27;
441 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
443 /* count up body length in the segment table */
445 for(i=0;i<page[26];i++)
446 oy->bodybytes+=page[27+i];
447 oy->headerbytes=headerbytes;
450 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
452 /* The whole test page is buffered. Verify the checksum */
454 /* Grab the checksum bytes, set the header field to zero */
458 memcpy(chksum,page+22,4);
461 /* set up a temp page struct and recompute the checksum */
463 log.header_len=oy->headerbytes;
464 log.body=page+oy->headerbytes;
465 log.body_len=oy->bodybytes;
469 if(memcmp(chksum,page+22,4)){
470 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
472 /* replace the computed checksum with the one actually read in */
473 memcpy(page+22,chksum,4);
475 /* Bad checksum. Lose sync */
480 /* yes, have a whole page all ready to go */
482 unsigned char *page=oy->data+oy->returned;
487 og->header_len=oy->headerbytes;
488 og->body=page+oy->headerbytes;
489 og->body_len=oy->bodybytes;
493 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
504 /* search for possible capture */
505 next=memchr(page+1,'O',bytes-1);
507 next=oy->data+oy->fill;
509 oy->returned=next-oy->data;
510 return(-(next-page));
513 /* sync the stream and get a page. Keep trying until we find a page.
514 Supress 'sync errors' after reporting the first.
517 -1) recapture (hole in data)
521 Returns pointers into buffered data; invalidated by next call to
522 _stream, _clear, _init, or _buffer */
524 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
526 /* all we need to do is verify a page at the head of the stream
527 buffer. If it doesn't verify, we look for the next potential
531 long ret=ogg_sync_pageseek(oy,og);
541 /* head did not start a synced page... skipped some bytes */
547 /* loop. keep looking */
552 /* add the incoming page to the stream state; we decompose the page
553 into packet segments here as well. */
555 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
556 unsigned char *header=og->header;
557 unsigned char *body=og->body;
558 long bodysize=og->body_len;
561 int version=ogg_page_version(og);
562 int continued=ogg_page_continued(og);
563 int bos=ogg_page_bos(og);
564 int eos=ogg_page_eos(og);
565 int64_t pcmpos=ogg_page_frameno(og);
566 int serialno=ogg_page_serialno(og);
567 int pageno=ogg_page_pageno(og);
568 int segments=header[26];
570 /* clean up 'returned data' */
572 long lr=os->lacing_returned;
573 long br=os->body_returned;
579 memmove(os->body_data,os->body_data+br,os->body_fill);
585 if(os->lacing_fill-lr){
586 memmove(os->lacing_vals,os->lacing_vals+lr,
587 (os->lacing_fill-lr)*sizeof(int));
588 memmove(os->pcm_vals,os->pcm_vals+lr,
589 (os->lacing_fill-lr)*sizeof(int64_t));
592 os->lacing_packet-=lr;
593 os->lacing_returned=0;
597 /* check the serial number */
598 if(serialno!=os->serialno)return(-1);
599 if(version>0)return(-1);
601 _os_lacing_expand(os,segments+1);
603 /* are we in sequence? */
604 if(pageno!=os->pageno){
607 /* unroll previous partial packet (if any) */
608 for(i=os->lacing_packet;i<os->lacing_fill;i++)
609 os->body_fill-=os->lacing_vals[i]&0xff;
610 os->lacing_fill=os->lacing_packet;
612 /* make a note of dropped data in segment table */
613 os->lacing_vals[os->lacing_fill++]=0x400;
616 /* are we a 'continued packet' page? If so, we'll need to skip
620 for(;segptr<segments;segptr++){
621 int val=header[27+segptr];
633 _os_body_expand(os,bodysize);
634 memcpy(os->body_data+os->body_fill,body,bodysize);
635 os->body_fill+=bodysize;
640 while(segptr<segments){
641 int val=header[27+segptr];
642 os->lacing_vals[os->lacing_fill]=val;
643 os->pcm_vals[os->lacing_fill]=-1;
646 os->lacing_vals[os->lacing_fill]|=0x100;
650 if(val<255)saved=os->lacing_fill;
655 if(val<255)os->lacing_packet=os->lacing_fill;
658 /* set the pcmpos on the last pcmval of the last full packet */
660 os->pcm_vals[saved]=pcmpos;
667 if(os->lacing_fill>0)
668 os->lacing_vals[os->lacing_fill-1]|=0x200;
676 /* clear things to an initial state. Good to call, eg, before seeking */
677 int ogg_sync_reset(ogg_sync_state *oy){
686 int ogg_stream_reset(ogg_stream_state *os,long expected_pageno){
692 os->lacing_returned=0;
698 os->pageno=expected_pageno;
705 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
707 /* The last part of decode. We have the stream broken into packet
708 segments. Now we need to group them into packets (or return the
709 out of sync markers) */
711 int ptr=os->lacing_returned;
713 if(os->lacing_packet<=ptr)return(0);
715 if(os->lacing_vals[ptr]&0x400){
716 /* We lost sync here; let the app know */
717 os->lacing_returned++;
719 /* we need to tell the codec there's a gap; it might need to
720 handle previous packet dependencies. */
725 /* Gather the whole packet. We'll have no holes or a partial packet */
727 int size=os->lacing_vals[ptr]&0xff;
730 op->packet=os->body_data+os->body_returned;
731 op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
732 op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
736 int val=os->lacing_vals[++ptr];
738 if(val&0x200)op->e_o_s=0x200;
742 op->packetno=os->packetno;
743 op->frameno=os->pcm_vals[ptr];
746 os->body_returned+=bytes;
747 os->lacing_returned=ptr+1;
756 ogg_stream_state os_en, os_de;
759 void checkpacket(ogg_packet *op,int len, int no, int pos){
761 static int sequence=0;
765 fprintf(stderr,"incorrect packet length!\n");
768 if(op->frameno!=pos){
769 fprintf(stderr,"incorrect packet position!\n");
773 /* packet number just follows sequence/gap; adjust the input number
783 if(op->packetno!=sequence){
784 fprintf(stderr,"incorrect packet sequence %ld != %d\n",op->packetno,sequence);
789 for(j=0;j<op->bytes;j++)
790 if(op->packet[j]!=((j+no)&0xff)){
791 fprintf(stderr,"body data mismatch at pos %ld: %x!=%lx!\n\n",
792 j,op->packet[j],(j+no)&0xff);
797 void check_page(unsigned char *data,int *header,ogg_page *og){
800 for(j=0;j<og->body_len;j++)
801 if(og->body[j]!=data[j]){
802 fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
803 j,data[j],og->body[j]);
808 for(j=0;j<og->header_len;j++){
809 if(og->header[j]!=header[j]){
810 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
811 for(j=0;j<header[26]+27;j++)
812 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
813 fprintf(stderr,"\n");
817 if(og->header_len!=header[26]+27){
818 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
819 og->header_len,header[26]+27);
824 void print_header(ogg_page *og){
826 fprintf(stderr,"\nHEADER:\n");
827 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
828 og->header[0],og->header[1],og->header[2],og->header[3],
829 (int)og->header[4],(int)og->header[5]);
831 fprintf(stderr," pcmpos: %d serialno: %d pageno: %d\n",
832 (og->header[9]<<24)|(og->header[8]<<16)|
833 (og->header[7]<<8)|og->header[6],
834 (og->header[17]<<24)|(og->header[16]<<16)|
835 (og->header[15]<<8)|og->header[14],
836 (og->header[21]<<24)|(og->header[20]<<16)|
837 (og->header[19]<<8)|og->header[18]);
839 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
840 (int)og->header[22],(int)og->header[23],
841 (int)og->header[24],(int)og->header[25],
842 (int)og->header[26]);
844 for(j=27;j<og->header_len;j++)
845 fprintf(stderr,"%d ",(int)og->header[j]);
846 fprintf(stderr,")\n\n");
849 void copy_page(ogg_page *og){
850 char *temp=malloc(og->header_len);
851 memcpy(temp,og->header,og->header_len);
854 temp=malloc(og->body_len);
855 memcpy(temp,og->body,og->body_len);
860 fprintf(stderr,"error!\n");
864 void test_pack(int *pl, int **headers){
865 unsigned char *data=malloc(1024*1024); /* for scripted test cases only */
871 int i,j,packets,pageno=0,pageout=0;
875 ogg_stream_reset(&os_en,0);
876 ogg_stream_reset(&os_de,0);
879 for(packets=0;;packets++)if(pl[packets]==-1)break;
881 for(i=0;i<packets;i++){
882 /* construct a test packet */
886 op.packet=data+inptr;
888 op.e_o_s=(pl[i+1]<0?1:0);
893 for(j=0;j<len;j++)data[inptr++]=i+j;
895 /* submit the test packet */
896 ogg_stream_packetin(&os_en,&op);
898 /* retrieve any finished pages */
902 while(ogg_stream_pageout(&os_en,&og)){
903 /* We have a page. Check it carefully */
905 fprintf(stderr,"%d, ",pageno);
907 if(headers[pageno]==NULL){
908 fprintf(stderr,"coded too many pages!\n");
912 check_page(data+outptr,headers[pageno],&og);
917 /* have a complete page; submit it to sync/decode */
922 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
923 memcpy(buf,og.header,og.header_len);
924 memcpy(buf+og.header_len,og.body,og.body_len);
925 ogg_sync_wrote(&oy,og.header_len+og.body_len);
927 while(ogg_sync_pageout(&oy,&og_de)>0){
928 /* got a page. Happy happy. Verify that it's good. */
930 check_page(data+deptr,headers[pageout],&og_de);
931 deptr+=og_de.body_len;
934 /* submit it to deconstitution */
935 ogg_stream_pagein(&os_de,&og_de);
938 while(ogg_stream_packetout(&os_de,&op_de)>0){
940 /* verify the packet! */
942 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
943 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
948 if(bosflag==0 && op_de.b_o_s==0){
949 fprintf(stderr,"b_o_s flag not set on packet!\n");
952 if(bosflag && op_de.b_o_s){
953 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
957 depacket+=op_de.bytes;
961 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
965 if(op_de.e_o_s)eosflag=1;
967 /* check pcmpos flag */
968 if(op_de.frameno!=-1){
969 fprintf(stderr," pcm:%ld ",(long)op_de.frameno);
978 if(headers[pageno]!=NULL){
979 fprintf(stderr,"did not write last page!\n");
982 if(headers[pageout]!=NULL){
983 fprintf(stderr,"did not decode last page!\n");
987 fprintf(stderr,"encoded page data incomplete!\n");
991 fprintf(stderr,"decoded page data incomplete!\n");
995 fprintf(stderr,"decoded packet data incomplete!\n");
999 fprintf(stderr,"Never got a packet with EOS set!\n");
1002 fprintf(stderr,"ok.\n");
1007 ogg_stream_init(&os_en,0x04030201);
1008 ogg_stream_init(&os_de,0x04030201);
1011 /* Exercise each code path in the framing code. Also verify that
1012 the checksums are working. */
1016 int packets[]={17, -1};
1017 int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
1018 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1019 0x01,0x02,0x03,0x04,0,0,0,0,
1020 0x15,0xed,0xec,0x91,
1023 int *headret[]={head1,NULL};
1025 fprintf(stderr,"testing single page encoding... ");
1026 test_pack(packets,headret);
1030 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1031 int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1032 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1033 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1034 0x01,0x02,0x03,0x04,0,0,0,0,
1035 0x59,0x10,0x6c,0x2c,
1038 int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1039 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1040 0x01,0x02,0x03,0x04,1,0,0,0,
1041 0x89,0x33,0x85,0xce,
1043 254,255,0,255,1,255,245,255,255,0,
1045 int *headret[]={head1,head2,NULL};
1047 fprintf(stderr,"testing basic page encoding... ");
1048 test_pack(packets,headret);
1052 /* nil packets; beginning,middle,end */
1053 int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1055 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1056 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1057 0x01,0x02,0x03,0x04,0,0,0,0,
1058 0xff,0x7b,0x23,0x17,
1061 int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1062 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1063 0x01,0x02,0x03,0x04,1,0,0,0,
1064 0x5c,0x3f,0x66,0xcb,
1066 17,254,255,0,0,255,1,0,255,245,255,255,0,
1068 int *headret[]={head1,head2,NULL};
1070 fprintf(stderr,"testing basic nil packets... ");
1071 test_pack(packets,headret);
1075 /* large initial packet */
1076 int packets[]={4345,259,255,-1};
1078 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1079 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1080 0x01,0x02,0x03,0x04,0,0,0,0,
1081 0x01,0x27,0x31,0xaa,
1083 255,255,255,255,255,255,255,255,
1084 255,255,255,255,255,255,255,255,255,10};
1086 int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1087 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1088 0x01,0x02,0x03,0x04,1,0,0,0,
1089 0x7f,0x4e,0x8a,0xd2,
1092 int *headret[]={head1,head2,NULL};
1094 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1095 test_pack(packets,headret);
1099 /* continuing packet test */
1100 int packets[]={0,4345,259,255,-1};
1102 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1103 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1104 0x01,0x02,0x03,0x04,0,0,0,0,
1105 0xff,0x7b,0x23,0x17,
1109 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1110 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1111 0x01,0x02,0x03,0x04,1,0,0,0,
1112 0x34,0x24,0xd5,0x29,
1114 255,255,255,255,255,255,255,255,
1115 255,255,255,255,255,255,255,255,255};
1117 int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
1118 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1119 0x01,0x02,0x03,0x04,2,0,0,0,
1120 0xc8,0xc3,0xcb,0xed,
1123 int *headret[]={head1,head2,head3,NULL};
1125 fprintf(stderr,"testing single packet page span... ");
1126 test_pack(packets,headret);
1129 /* page with the 255 segment limit */
1132 int packets[]={0,10,10,10,10,10,10,10,10,
1133 10,10,10,10,10,10,10,10,
1134 10,10,10,10,10,10,10,10,
1135 10,10,10,10,10,10,10,10,
1136 10,10,10,10,10,10,10,10,
1137 10,10,10,10,10,10,10,10,
1138 10,10,10,10,10,10,10,10,
1139 10,10,10,10,10,10,10,10,
1140 10,10,10,10,10,10,10,10,
1141 10,10,10,10,10,10,10,10,
1142 10,10,10,10,10,10,10,10,
1143 10,10,10,10,10,10,10,10,
1144 10,10,10,10,10,10,10,10,
1145 10,10,10,10,10,10,10,10,
1146 10,10,10,10,10,10,10,10,
1147 10,10,10,10,10,10,10,10,
1148 10,10,10,10,10,10,10,10,
1149 10,10,10,10,10,10,10,10,
1150 10,10,10,10,10,10,10,10,
1151 10,10,10,10,10,10,10,10,
1152 10,10,10,10,10,10,10,10,
1153 10,10,10,10,10,10,10,10,
1154 10,10,10,10,10,10,10,10,
1155 10,10,10,10,10,10,10,10,
1156 10,10,10,10,10,10,10,10,
1157 10,10,10,10,10,10,10,10,
1158 10,10,10,10,10,10,10,10,
1159 10,10,10,10,10,10,10,10,
1160 10,10,10,10,10,10,10,10,
1161 10,10,10,10,10,10,10,10,
1162 10,10,10,10,10,10,10,10,
1163 10,10,10,10,10,10,10,50,-1};
1165 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1166 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1167 0x01,0x02,0x03,0x04,0,0,0,0,
1168 0xff,0x7b,0x23,0x17,
1172 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1173 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1174 0x01,0x02,0x03,0x04,1,0,0,0,
1175 0xed,0x2a,0x2e,0xa7,
1177 10,10,10,10,10,10,10,10,
1178 10,10,10,10,10,10,10,10,
1179 10,10,10,10,10,10,10,10,
1180 10,10,10,10,10,10,10,10,
1181 10,10,10,10,10,10,10,10,
1182 10,10,10,10,10,10,10,10,
1183 10,10,10,10,10,10,10,10,
1184 10,10,10,10,10,10,10,10,
1185 10,10,10,10,10,10,10,10,
1186 10,10,10,10,10,10,10,10,
1187 10,10,10,10,10,10,10,10,
1188 10,10,10,10,10,10,10,10,
1189 10,10,10,10,10,10,10,10,
1190 10,10,10,10,10,10,10,10,
1191 10,10,10,10,10,10,10,10,
1192 10,10,10,10,10,10,10,10,
1193 10,10,10,10,10,10,10,10,
1194 10,10,10,10,10,10,10,10,
1195 10,10,10,10,10,10,10,10,
1196 10,10,10,10,10,10,10,10,
1197 10,10,10,10,10,10,10,10,
1198 10,10,10,10,10,10,10,10,
1199 10,10,10,10,10,10,10,10,
1200 10,10,10,10,10,10,10,10,
1201 10,10,10,10,10,10,10,10,
1202 10,10,10,10,10,10,10,10,
1203 10,10,10,10,10,10,10,10,
1204 10,10,10,10,10,10,10,10,
1205 10,10,10,10,10,10,10,10,
1206 10,10,10,10,10,10,10,10,
1207 10,10,10,10,10,10,10,10,
1208 10,10,10,10,10,10,10};
1210 int head3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1211 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1212 0x01,0x02,0x03,0x04,2,0,0,0,
1213 0x6c,0x3b,0x82,0x3d,
1216 int *headret[]={head1,head2,head3,NULL};
1218 fprintf(stderr,"testing max packet segments... ");
1219 test_pack(packets,headret);
1223 /* packet that overspans over an entire page */
1225 int packets[]={0,100,9000,259,255,-1};
1227 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1228 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1229 0x01,0x02,0x03,0x04,0,0,0,0,
1230 0xff,0x7b,0x23,0x17,
1234 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1235 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1236 0x01,0x02,0x03,0x04,1,0,0,0,
1237 0x3c,0xd9,0x4d,0x3f,
1239 100,255,255,255,255,255,255,255,255,
1240 255,255,255,255,255,255,255,255};
1242 int head3[] = {0x4f,0x67,0x67,0x53,0,0x01,
1243 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1244 0x01,0x02,0x03,0x04,2,0,0,0,
1245 0xbd,0xd5,0xb5,0x8b,
1247 255,255,255,255,255,255,255,255,
1248 255,255,255,255,255,255,255,255,255};
1250 int head4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1251 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1252 0x01,0x02,0x03,0x04,3,0,0,0,
1253 0xef,0xdd,0x88,0xde,
1255 255,255,75,255,4,255,0};
1256 int *headret[]={head1,head2,head3,head4,NULL};
1258 fprintf(stderr,"testing very large packets... ");
1259 test_pack(packets,headret);
1263 /* term only page. why not? */
1265 int packets[]={0,100,4080,-1};
1267 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1268 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1269 0x01,0x02,0x03,0x04,0,0,0,0,
1270 0xff,0x7b,0x23,0x17,
1274 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1275 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1276 0x01,0x02,0x03,0x04,1,0,0,0,
1277 0x3c,0xd9,0x4d,0x3f,
1279 100,255,255,255,255,255,255,255,255,
1280 255,255,255,255,255,255,255,255};
1282 int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
1283 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1284 0x01,0x02,0x03,0x04,2,0,0,0,
1285 0xd4,0xe0,0x60,0xe5,
1288 int *headret[]={head1,head2,head3,NULL};
1290 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1291 test_pack(packets,headret);
1297 /* build a bunch of pages for testing */
1298 unsigned char *data=malloc(1024*1024);
1299 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1303 ogg_stream_reset(&os_en,0);
1305 for(i=0;pl[i]!=-1;i++){
1309 op.packet=data+inptr;
1311 op.e_o_s=(pl[i+1]<0?1:0);
1312 op.frameno=(i+1)*1000;
1314 for(j=0;j<len;j++)data[inptr++]=i+j;
1315 ogg_stream_packetin(&os_en,&op);
1320 /* retrieve finished pages */
1322 if(ogg_stream_pageout(&os_en,&og[i])==0){
1323 fprintf(stderr,"Too few pages output building sync tests!\n");
1329 /* Test lost pages on pagein/packetout: no rollback */
1334 fprintf(stderr,"Testing loss of pages... ");
1336 ogg_sync_reset(&oy);
1337 ogg_stream_reset(&os_de,0);
1339 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1341 ogg_sync_wrote(&oy,og[i].header_len);
1342 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1343 ogg_sync_wrote(&oy,og[i].body_len);
1346 ogg_sync_pageout(&oy,&temp);
1347 ogg_stream_pagein(&os_de,&temp);
1348 ogg_sync_pageout(&oy,&temp);
1349 ogg_stream_pagein(&os_de,&temp);
1350 ogg_sync_pageout(&oy,&temp);
1352 ogg_sync_pageout(&oy,&temp);
1353 ogg_stream_pagein(&os_de,&temp);
1355 /* do we get the expected results/packets? */
1357 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1358 checkpacket(&test,0,0,0);
1359 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1360 checkpacket(&test,100,1,-1);
1361 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1362 checkpacket(&test,4079,2,3000);
1363 if(ogg_stream_packetout(&os_de,&test)!=-1){
1364 fprintf(stderr,"Error: loss of page did not return error\n");
1367 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1368 checkpacket(&test,76,5,-1);
1369 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1370 checkpacket(&test,34,6,-1);
1371 fprintf(stderr,"ok.\n");
1374 /* Test lost pages on pagein/packetout: rollback with continuation */
1379 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1381 ogg_sync_reset(&oy);
1382 ogg_stream_reset(&os_de,0);
1384 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1386 ogg_sync_wrote(&oy,og[i].header_len);
1387 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1388 ogg_sync_wrote(&oy,og[i].body_len);
1391 ogg_sync_pageout(&oy,&temp);
1392 ogg_stream_pagein(&os_de,&temp);
1393 ogg_sync_pageout(&oy,&temp);
1394 ogg_stream_pagein(&os_de,&temp);
1395 ogg_sync_pageout(&oy,&temp);
1396 ogg_stream_pagein(&os_de,&temp);
1397 ogg_sync_pageout(&oy,&temp);
1399 ogg_sync_pageout(&oy,&temp);
1400 ogg_stream_pagein(&os_de,&temp);
1402 /* do we get the expected results/packets? */
1404 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1405 checkpacket(&test,0,0,0);
1406 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1407 checkpacket(&test,100,1,-1);
1408 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1409 checkpacket(&test,4079,2,3000);
1410 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1411 checkpacket(&test,2956,3,4000);
1412 if(ogg_stream_packetout(&os_de,&test)!=-1){
1413 fprintf(stderr,"Error: loss of page did not return error\n");
1416 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1417 checkpacket(&test,300,13,14000);
1418 fprintf(stderr,"ok.\n");
1421 /* the rest only test sync */
1424 /* Test fractional page inputs: incomplete capture */
1425 fprintf(stderr,"Testing sync on partial inputs... ");
1426 ogg_sync_reset(&oy);
1427 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1429 ogg_sync_wrote(&oy,3);
1430 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1432 /* Test fractional page inputs: incomplete fixed header */
1433 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1435 ogg_sync_wrote(&oy,20);
1436 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1438 /* Test fractional page inputs: incomplete header */
1439 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1441 ogg_sync_wrote(&oy,5);
1442 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1444 /* Test fractional page inputs: incomplete body */
1446 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1447 og[1].header_len-28);
1448 ogg_sync_wrote(&oy,og[1].header_len-28);
1449 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1451 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1452 ogg_sync_wrote(&oy,1000);
1453 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1455 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1456 og[1].body_len-1000);
1457 ogg_sync_wrote(&oy,og[1].body_len-1000);
1458 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1460 fprintf(stderr,"ok.\n");
1463 /* Test fractional page inputs: page + incomplete capture */
1466 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1467 ogg_sync_reset(&oy);
1469 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1471 ogg_sync_wrote(&oy,og[1].header_len);
1473 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1475 ogg_sync_wrote(&oy,og[1].body_len);
1477 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1479 ogg_sync_wrote(&oy,20);
1480 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1481 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1483 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1484 og[1].header_len-20);
1485 ogg_sync_wrote(&oy,og[1].header_len-20);
1486 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1488 ogg_sync_wrote(&oy,og[1].body_len);
1489 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1491 fprintf(stderr,"ok.\n");
1494 /* Test recapture: garbage + page */
1497 fprintf(stderr,"Testing search for capture... ");
1498 ogg_sync_reset(&oy);
1501 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1503 ogg_sync_wrote(&oy,og[1].body_len);
1505 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1507 ogg_sync_wrote(&oy,og[1].header_len);
1509 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1511 ogg_sync_wrote(&oy,og[1].body_len);
1513 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1515 ogg_sync_wrote(&oy,20);
1516 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1517 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1518 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1520 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1521 og[2].header_len-20);
1522 ogg_sync_wrote(&oy,og[2].header_len-20);
1523 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1525 ogg_sync_wrote(&oy,og[2].body_len);
1526 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1528 fprintf(stderr,"ok.\n");
1531 /* Test recapture: page + garbage + page */
1534 fprintf(stderr,"Testing recapture... ");
1535 ogg_sync_reset(&oy);
1537 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1539 ogg_sync_wrote(&oy,og[1].header_len);
1541 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1543 ogg_sync_wrote(&oy,og[1].body_len);
1545 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1547 ogg_sync_wrote(&oy,og[2].header_len);
1549 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1551 ogg_sync_wrote(&oy,og[2].header_len);
1553 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1555 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1557 ogg_sync_wrote(&oy,og[2].body_len-5);
1559 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1561 ogg_sync_wrote(&oy,og[3].header_len);
1563 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1565 ogg_sync_wrote(&oy,og[3].body_len);
1567 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1568 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1570 fprintf(stderr,"ok.\n");