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.17 2000/04/06 15:39:43 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"
29 /* A complete description of Ogg framing exists in docs/framing.html */
31 int ogg_page_version(ogg_page *og){
32 return((int)(og->header[4]));
35 int ogg_page_continued(ogg_page *og){
36 return((int)(og->header[5]&0x01));
39 int ogg_page_bos(ogg_page *og){
40 return((int)(og->header[5]&0x02));
43 int ogg_page_eos(ogg_page *og){
44 return((int)(og->header[5]&0x04));
47 int64_t ogg_page_frameno(ogg_page *og){
48 unsigned char *page=og->header;
49 int64_t pcmpos=page[13]&(0xff);
50 pcmpos= (pcmpos<<8)|(page[12]&0xff);
51 pcmpos= (pcmpos<<8)|(page[11]&0xff);
52 pcmpos= (pcmpos<<8)|(page[10]&0xff);
53 pcmpos= (pcmpos<<8)|(page[9]&0xff);
54 pcmpos= (pcmpos<<8)|(page[8]&0xff);
55 pcmpos= (pcmpos<<8)|(page[7]&0xff);
56 pcmpos= (pcmpos<<8)|(page[6]&0xff);
60 int ogg_page_serialno(ogg_page *og){
61 return(og->header[14] |
63 (og->header[16]<<16) |
64 (og->header[17]<<24));
67 int ogg_page_pageno(ogg_page *og){
68 return(og->header[18] |
70 (og->header[20]<<16) |
71 (og->header[21]<<24));
74 /* helper to initialize lookup for direct-table CRC */
76 static u_int32_t crc_lookup[256];
77 static int crc_ready=0;
79 static u_int32_t _ogg_crc_entry(unsigned long index){
86 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
87 polynomial, although we use an
88 unreflected alg and an init/final
89 of 0, not 0xffffffff */
92 return (r & 0xffffffffUL);
95 /* mind this in threaded code; sync_init and stream_init call it.
96 It's thread safe only after the first time it returns */
98 static void _ogg_crc_init(void){
100 /* initialize the crc_lookup table */
103 crc_lookup[i]=_ogg_crc_entry((unsigned long)i);
108 /* init the encode/decode logical stream state */
110 int ogg_stream_init(ogg_stream_state *os,int serialno){
112 memset(os,0,sizeof(ogg_stream_state));
113 os->body_storage=16*1024;
114 os->body_data=malloc(os->body_storage*sizeof(char));
116 os->lacing_storage=1024;
117 os->lacing_vals=malloc(os->lacing_storage*sizeof(int));
118 os->pcm_vals=malloc(os->lacing_storage*sizeof(int64_t));
120 /* initialize the crc_lookup table if not done */
123 os->serialno=serialno;
130 /* _clear does not free os, only the non-flat storage within */
131 int ogg_stream_clear(ogg_stream_state *os){
133 if(os->body_data)free(os->body_data);
134 if(os->lacing_vals)free(os->lacing_vals);
135 if(os->pcm_vals)free(os->pcm_vals);
137 memset(os,0,sizeof(ogg_stream_state));
142 int ogg_stream_destroy(ogg_stream_state *os){
144 ogg_stream_clear(os);
150 /* Helpers for ogg_stream_encode; this keeps the structure and
151 what's happening fairly clear */
153 static void _os_body_expand(ogg_stream_state *os,int needed){
154 if(os->body_storage<=os->body_fill+needed){
155 os->body_storage+=(needed+1024);
156 os->body_data=realloc(os->body_data,os->body_storage);
160 static void _os_lacing_expand(ogg_stream_state *os,int needed){
161 if(os->lacing_storage<=os->lacing_fill+needed){
162 os->lacing_storage+=(needed+32);
163 os->lacing_vals=realloc(os->lacing_vals,os->lacing_storage*sizeof(int));
164 os->pcm_vals=realloc(os->pcm_vals,os->lacing_storage*sizeof(int64_t));
168 /* checksum the page */
169 /* Direct table CRC; note that this will be faster in the future if we
170 perform the checksum silmultaneously with other copies */
172 static void _os_checksum(ogg_page *og){
176 for(i=0;i<og->header_len;i++)
177 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
178 for(i=0;i<og->body_len;i++)
179 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
181 og->header[22]=crc_reg&0xff;
182 og->header[23]=(crc_reg>>8)&0xff;
183 og->header[24]=(crc_reg>>16)&0xff;
184 og->header[25]=(crc_reg>>24)&0xff;
187 /* submit data to the internal buffer of the framing engine */
188 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
189 int lacing_vals=op->bytes/255+1,i;
191 /* make sure we have the buffer storage */
192 _os_body_expand(os,op->bytes);
193 _os_lacing_expand(os,lacing_vals);
195 /* Copy in the submitted packet. Yes, the copy is a waste; this is
196 the liability of overly clean abstraction for the time being. It
197 will actually be fairly easy to eliminate the extra copy in the
200 memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
201 os->body_fill+=op->bytes;
203 /* Store lacing vals for this packet */
204 for(i=0;i<lacing_vals-1;i++){
205 os->lacing_vals[os->lacing_fill+i]=255;
206 os->pcm_vals[os->lacing_fill+i]=os->pcmpos;
208 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
209 os->pcmpos=os->pcm_vals[os->lacing_fill+i]=op->frameno;
211 /* flag the first segment as the beginning of the packet */
212 os->lacing_vals[os->lacing_fill]|= 0x100;
214 os->lacing_fill+=lacing_vals;
216 /* for the sake of completeness */
219 if(op->e_o_s)os->e_o_s=1;
224 /* This constructs pages from buffered packet segments. The pointers
225 returned are to static buffers; do not free. The returned buffers are
226 good only until the next call (using the same ogg_stream_state) */
228 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
231 if(os->body_returned){
232 /* advance packet data according to the body_returned pointer. We
233 had to keep it around to return a pointer into the buffer last
236 os->body_fill-=os->body_returned;
238 memmove(os->body_data,os->body_data+os->body_returned,
239 os->body_fill*sizeof(char));
243 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
244 os->body_fill > 4096 || /* 'page nominal size' case */
245 os->lacing_fill>=255 || /* 'segment table full' case */
246 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
249 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
251 int64_t pcm_pos=os->pcm_vals[0];
253 /* construct a page */
254 /* decide how many segments to include */
256 /* If this is the initial header case, the first page must only include
257 the initial header packet */
258 if(os->b_o_s==0){ /* 'initial header page' case */
260 for(vals=0;vals<maxvals;vals++){
261 if((os->lacing_vals[vals]&0x0ff)<255){
267 for(vals=0;vals<maxvals;vals++){
269 acc+=os->lacing_vals[vals]&0x0ff;
270 pcm_pos=os->pcm_vals[vals];
274 /* construct the header in temp storage */
275 memcpy(os->header,"OggS",4);
277 /* stream structure version */
280 /* continued packet flag? */
282 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
283 /* first page flag? */
284 if(os->b_o_s==0)os->header[5]|=0x02;
285 /* last page flag? */
286 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
289 /* 64 bits of PCM position */
291 os->header[i]=(pcm_pos&0xff);
295 /* 32 bits of stream serial number */
297 long serialno=os->serialno;
299 os->header[i]=(serialno&0xff);
304 /* 32 bits of page counter (we have both counter and page header
305 because this val can roll over) */
306 if(os->pageno==-1)os->pageno=0; /* because someone called
307 stream_reset; this would be a
308 strange thing to do in an
309 encode stream, but it has
312 long pageno=os->pageno++;
314 os->header[i]=(pageno&0xff);
319 /* zero for computation; filled in later */
326 os->header[26]=vals&0xff;
328 bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
330 /* advance the lacing data and set the body_returned pointer */
332 os->lacing_fill-=vals;
333 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int));
334 memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(int64_t));
335 os->body_returned=bytes;
337 /* set pointers in the ogg_page struct */
338 og->header=os->header;
339 og->header_len=os->header_fill=vals+27;
340 og->body=os->body_data;
343 /* calculate the checksum */
350 /* not enough data to construct a page and not end of stream */
354 int ogg_stream_eof(ogg_stream_state *os){
358 /* DECODING PRIMITIVES: packet streaming layer **********************/
360 /* This has two layers to place more of the multi-serialno and paging
361 control in the application's hands. First, we expose a data buffer
362 using ogg_decode_buffer(). The app either copies into the
363 buffer, or passes it directly to read(), etc. We then call
364 ogg_decode_wrote() to tell how many bytes we just added.
366 Pages are returned (pointers into the buffer in ogg_sync_state)
367 by ogg_decode_stream(). The page is then submitted to
368 ogg_decode_page() along with the appropriate
369 ogg_stream_state* (ie, matching serialno). We then get raw
370 packets out calling ogg_stream_packet() with a
371 ogg_stream_state. See the 'frame-prog.txt' docs for details and
374 /* initialize the struct to a known state */
375 int ogg_sync_init(ogg_sync_state *oy){
377 memset(oy,0,sizeof(ogg_sync_state));
383 /* clear non-flat storage within */
384 int ogg_sync_clear(ogg_sync_state *oy){
386 if(oy->data)free(oy->data);
392 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
394 /* first, clear out any space that has been previously returned */
396 oy->fill-=oy->returned;
398 memmove(oy->data,oy->data+oy->returned,
399 (oy->fill)*sizeof(char));
403 if(size>oy->storage-oy->fill){
404 /* We need to extend the internal buffer */
405 long newsize=size+oy->fill+4096; /* an extra page to be nice */
408 oy->data=realloc(oy->data,newsize);
410 oy->data=malloc(newsize);
414 /* expose a segment at least as large as requested at the fill mark */
415 return((char *)oy->data+oy->fill);
418 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
419 if(oy->fill+bytes>oy->storage)return(-1);
424 /* sync the stream. This is meant to be useful for finding page
427 return values for this:
429 0) page not ready; more data (no bytes skipped)
430 n) page synced at current location; page length n bytes
434 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
435 unsigned char *page=oy->data+oy->returned;
437 long bytes=oy->fill-oy->returned;
439 if(oy->headerbytes==0){
441 if(bytes<27)return(0); /* not enough for a header */
443 /* verify capture pattern */
444 if(memcmp(page,"OggS",4))goto sync_fail;
446 headerbytes=page[26]+27;
447 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
449 /* count up body length in the segment table */
451 for(i=0;i<page[26];i++)
452 oy->bodybytes+=page[27+i];
453 oy->headerbytes=headerbytes;
456 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
458 /* The whole test page is buffered. Verify the checksum */
460 /* Grab the checksum bytes, set the header field to zero */
464 memcpy(chksum,page+22,4);
467 /* set up a temp page struct and recompute the checksum */
469 log.header_len=oy->headerbytes;
470 log.body=page+oy->headerbytes;
471 log.body_len=oy->bodybytes;
475 if(memcmp(chksum,page+22,4)){
476 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
478 /* replace the computed checksum with the one actually read in */
479 memcpy(page+22,chksum,4);
481 /* Bad checksum. Lose sync */
486 /* yes, have a whole page all ready to go */
488 unsigned char *page=oy->data+oy->returned;
493 og->header_len=oy->headerbytes;
494 og->body=page+oy->headerbytes;
495 og->body_len=oy->bodybytes;
499 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
510 /* search for possible capture */
511 next=memchr(page+1,'O',bytes-1);
513 next=oy->data+oy->fill;
515 oy->returned=next-oy->data;
516 return(-(next-page));
519 /* sync the stream and get a page. Keep trying until we find a page.
520 Supress 'sync errors' after reporting the first.
523 -1) recapture (hole in data)
527 Returns pointers into buffered data; invalidated by next call to
528 _stream, _clear, _init, or _buffer */
530 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
532 /* all we need to do is verify a page at the head of the stream
533 buffer. If it doesn't verify, we look for the next potential
537 long ret=ogg_sync_pageseek(oy,og);
547 /* head did not start a synced page... skipped some bytes */
553 /* loop. keep looking */
558 /* add the incoming page to the stream state; we decompose the page
559 into packet segments here as well. */
561 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
562 unsigned char *header=og->header;
563 unsigned char *body=og->body;
564 long bodysize=og->body_len;
567 int version=ogg_page_version(og);
568 int continued=ogg_page_continued(og);
569 int bos=ogg_page_bos(og);
570 int eos=ogg_page_eos(og);
571 int64_t pcmpos=ogg_page_frameno(og);
572 int serialno=ogg_page_serialno(og);
573 int pageno=ogg_page_pageno(og);
574 int segments=header[26];
576 /* clean up 'returned data' */
578 long lr=os->lacing_returned;
579 long br=os->body_returned;
585 memmove(os->body_data,os->body_data+br,os->body_fill);
591 if(os->lacing_fill-lr){
592 memmove(os->lacing_vals,os->lacing_vals+lr,
593 (os->lacing_fill-lr)*sizeof(int));
594 memmove(os->pcm_vals,os->pcm_vals+lr,
595 (os->lacing_fill-lr)*sizeof(int64_t));
598 os->lacing_packet-=lr;
599 os->lacing_returned=0;
603 /* check the serial number */
604 if(serialno!=os->serialno)return(-1);
605 if(version>0)return(-1);
607 _os_lacing_expand(os,segments+1);
609 /* are we in sequence? */
610 if(pageno!=os->pageno){
613 /* unroll previous partial packet (if any) */
614 for(i=os->lacing_packet;i<os->lacing_fill;i++)
615 os->body_fill-=os->lacing_vals[i]&0xff;
616 os->lacing_fill=os->lacing_packet;
618 /* make a note of dropped data in segment table */
620 os->lacing_vals[os->lacing_fill++]=0x400;
624 /* are we a 'continued packet' page? If so, we'll need to skip
628 for(;segptr<segments;segptr++){
629 int val=header[27+segptr];
641 _os_body_expand(os,bodysize);
642 memcpy(os->body_data+os->body_fill,body,bodysize);
643 os->body_fill+=bodysize;
648 while(segptr<segments){
649 int val=header[27+segptr];
650 os->lacing_vals[os->lacing_fill]=val;
651 os->pcm_vals[os->lacing_fill]=-1;
654 os->lacing_vals[os->lacing_fill]|=0x100;
658 if(val<255)saved=os->lacing_fill;
663 if(val<255)os->lacing_packet=os->lacing_fill;
666 /* set the pcmpos on the last pcmval of the last full packet */
668 os->pcm_vals[saved]=pcmpos;
675 if(os->lacing_fill>0)
676 os->lacing_vals[os->lacing_fill-1]|=0x200;
684 /* clear things to an initial state. Good to call, eg, before seeking */
685 int ogg_sync_reset(ogg_sync_state *oy){
694 int ogg_stream_reset(ogg_stream_state *os){
700 os->lacing_returned=0;
713 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
715 /* The last part of decode. We have the stream broken into packet
716 segments. Now we need to group them into packets (or return the
717 out of sync markers) */
719 int ptr=os->lacing_returned;
721 if(os->lacing_packet<=ptr)return(0);
723 if(os->lacing_vals[ptr]&0x400){
724 /* We lost sync here; let the app know */
725 os->lacing_returned++;
727 /* we need to tell the codec there's a gap; it might need to
728 handle previous packet dependencies. */
733 /* Gather the whole packet. We'll have no holes or a partial packet */
735 int size=os->lacing_vals[ptr]&0xff;
738 op->packet=os->body_data+os->body_returned;
739 op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
740 op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
744 int val=os->lacing_vals[++ptr];
746 if(val&0x200)op->e_o_s=0x200;
750 op->packetno=os->packetno;
751 op->frameno=os->pcm_vals[ptr];
754 os->body_returned+=bytes;
755 os->lacing_returned=ptr+1;
764 ogg_stream_state os_en, os_de;
767 void checkpacket(ogg_packet *op,int len, int no, int pos){
769 static int sequence=0;
773 fprintf(stderr,"incorrect packet length!\n");
776 if(op->frameno!=pos){
777 fprintf(stderr,"incorrect packet position!\n");
781 /* packet number just follows sequence/gap; adjust the input number
791 if(op->packetno!=sequence){
792 fprintf(stderr,"incorrect packet sequence %ld != %d\n",op->packetno,sequence);
797 for(j=0;j<op->bytes;j++)
798 if(op->packet[j]!=((j+no)&0xff)){
799 fprintf(stderr,"body data mismatch at pos %ld: %x!=%lx!\n\n",
800 j,op->packet[j],(j+no)&0xff);
805 void check_page(unsigned char *data,int *header,ogg_page *og){
808 for(j=0;j<og->body_len;j++)
809 if(og->body[j]!=data[j]){
810 fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
811 j,data[j],og->body[j]);
816 for(j=0;j<og->header_len;j++){
817 if(og->header[j]!=header[j]){
818 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
819 for(j=0;j<header[26]+27;j++)
820 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
821 fprintf(stderr,"\n");
825 if(og->header_len!=header[26]+27){
826 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
827 og->header_len,header[26]+27);
832 void print_header(ogg_page *og){
834 fprintf(stderr,"\nHEADER:\n");
835 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
836 og->header[0],og->header[1],og->header[2],og->header[3],
837 (int)og->header[4],(int)og->header[5]);
839 fprintf(stderr," pcmpos: %d serialno: %d pageno: %d\n",
840 (og->header[9]<<24)|(og->header[8]<<16)|
841 (og->header[7]<<8)|og->header[6],
842 (og->header[17]<<24)|(og->header[16]<<16)|
843 (og->header[15]<<8)|og->header[14],
844 (og->header[21]<<24)|(og->header[20]<<16)|
845 (og->header[19]<<8)|og->header[18]);
847 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
848 (int)og->header[22],(int)og->header[23],
849 (int)og->header[24],(int)og->header[25],
850 (int)og->header[26]);
852 for(j=27;j<og->header_len;j++)
853 fprintf(stderr,"%d ",(int)og->header[j]);
854 fprintf(stderr,")\n\n");
857 void copy_page(ogg_page *og){
858 char *temp=malloc(og->header_len);
859 memcpy(temp,og->header,og->header_len);
862 temp=malloc(og->body_len);
863 memcpy(temp,og->body,og->body_len);
868 fprintf(stderr,"error!\n");
872 void test_pack(int *pl, int **headers){
873 unsigned char *data=malloc(1024*1024); /* for scripted test cases only */
879 int i,j,packets,pageno=0,pageout=0;
883 ogg_stream_reset(&os_en);
884 ogg_stream_reset(&os_de);
887 for(packets=0;;packets++)if(pl[packets]==-1)break;
889 for(i=0;i<packets;i++){
890 /* construct a test packet */
894 op.packet=data+inptr;
896 op.e_o_s=(pl[i+1]<0?1:0);
901 for(j=0;j<len;j++)data[inptr++]=i+j;
903 /* submit the test packet */
904 ogg_stream_packetin(&os_en,&op);
906 /* retrieve any finished pages */
910 while(ogg_stream_pageout(&os_en,&og)){
911 /* We have a page. Check it carefully */
913 fprintf(stderr,"%d, ",pageno);
915 if(headers[pageno]==NULL){
916 fprintf(stderr,"coded too many pages!\n");
920 check_page(data+outptr,headers[pageno],&og);
925 /* have a complete page; submit it to sync/decode */
930 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
931 memcpy(buf,og.header,og.header_len);
932 memcpy(buf+og.header_len,og.body,og.body_len);
933 ogg_sync_wrote(&oy,og.header_len+og.body_len);
935 while(ogg_sync_pageout(&oy,&og_de)>0){
936 /* got a page. Happy happy. Verify that it's good. */
938 check_page(data+deptr,headers[pageout],&og_de);
939 deptr+=og_de.body_len;
942 /* submit it to deconstitution */
943 ogg_stream_pagein(&os_de,&og_de);
946 while(ogg_stream_packetout(&os_de,&op_de)>0){
948 /* verify the packet! */
950 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
951 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
956 if(bosflag==0 && op_de.b_o_s==0){
957 fprintf(stderr,"b_o_s flag not set on packet!\n");
960 if(bosflag && op_de.b_o_s){
961 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
965 depacket+=op_de.bytes;
969 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
973 if(op_de.e_o_s)eosflag=1;
975 /* check pcmpos flag */
976 if(op_de.frameno!=-1){
977 fprintf(stderr," pcm:%ld ",(long)op_de.frameno);
986 if(headers[pageno]!=NULL){
987 fprintf(stderr,"did not write last page!\n");
990 if(headers[pageout]!=NULL){
991 fprintf(stderr,"did not decode last page!\n");
995 fprintf(stderr,"encoded page data incomplete!\n");
999 fprintf(stderr,"decoded page data incomplete!\n");
1002 if(inptr!=depacket){
1003 fprintf(stderr,"decoded packet data incomplete!\n");
1007 fprintf(stderr,"Never got a packet with EOS set!\n");
1010 fprintf(stderr,"ok.\n");
1015 ogg_stream_init(&os_en,0x04030201);
1016 ogg_stream_init(&os_de,0x04030201);
1019 /* Exercise each code path in the framing code. Also verify that
1020 the checksums are working. */
1024 int packets[]={17, -1};
1025 int head1[] = {0x4f,0x67,0x67,0x53,0,0x06,
1026 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1027 0x01,0x02,0x03,0x04,0,0,0,0,
1028 0x15,0xed,0xec,0x91,
1031 int *headret[]={head1,NULL};
1033 fprintf(stderr,"testing single page encoding... ");
1034 test_pack(packets,headret);
1038 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1039 int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1040 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1041 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1042 0x01,0x02,0x03,0x04,0,0,0,0,
1043 0x59,0x10,0x6c,0x2c,
1046 int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1047 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1048 0x01,0x02,0x03,0x04,1,0,0,0,
1049 0x89,0x33,0x85,0xce,
1051 254,255,0,255,1,255,245,255,255,0,
1053 int *headret[]={head1,head2,NULL};
1055 fprintf(stderr,"testing basic page encoding... ");
1056 test_pack(packets,headret);
1060 /* nil packets; beginning,middle,end */
1061 int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1063 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1064 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1065 0x01,0x02,0x03,0x04,0,0,0,0,
1066 0xff,0x7b,0x23,0x17,
1069 int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1070 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1071 0x01,0x02,0x03,0x04,1,0,0,0,
1072 0x5c,0x3f,0x66,0xcb,
1074 17,254,255,0,0,255,1,0,255,245,255,255,0,
1076 int *headret[]={head1,head2,NULL};
1078 fprintf(stderr,"testing basic nil packets... ");
1079 test_pack(packets,headret);
1083 /* large initial packet */
1084 int packets[]={4345,259,255,-1};
1086 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1087 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1088 0x01,0x02,0x03,0x04,0,0,0,0,
1089 0x01,0x27,0x31,0xaa,
1091 255,255,255,255,255,255,255,255,
1092 255,255,255,255,255,255,255,255,255,10};
1094 int head2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1095 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1096 0x01,0x02,0x03,0x04,1,0,0,0,
1097 0x7f,0x4e,0x8a,0xd2,
1100 int *headret[]={head1,head2,NULL};
1102 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1103 test_pack(packets,headret);
1107 /* continuing packet test */
1108 int packets[]={0,4345,259,255,-1};
1110 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1111 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1112 0x01,0x02,0x03,0x04,0,0,0,0,
1113 0xff,0x7b,0x23,0x17,
1117 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1118 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1119 0x01,0x02,0x03,0x04,1,0,0,0,
1120 0x34,0x24,0xd5,0x29,
1122 255,255,255,255,255,255,255,255,
1123 255,255,255,255,255,255,255,255,255};
1125 int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
1126 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1127 0x01,0x02,0x03,0x04,2,0,0,0,
1128 0xc8,0xc3,0xcb,0xed,
1131 int *headret[]={head1,head2,head3,NULL};
1133 fprintf(stderr,"testing single packet page span... ");
1134 test_pack(packets,headret);
1137 /* page with the 255 segment limit */
1140 int packets[]={0,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,10,
1164 10,10,10,10,10,10,10,10,
1165 10,10,10,10,10,10,10,10,
1166 10,10,10,10,10,10,10,10,
1167 10,10,10,10,10,10,10,10,
1168 10,10,10,10,10,10,10,10,
1169 10,10,10,10,10,10,10,10,
1170 10,10,10,10,10,10,10,10,
1171 10,10,10,10,10,10,10,50,-1};
1173 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1174 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1175 0x01,0x02,0x03,0x04,0,0,0,0,
1176 0xff,0x7b,0x23,0x17,
1180 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1181 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1182 0x01,0x02,0x03,0x04,1,0,0,0,
1183 0xed,0x2a,0x2e,0xa7,
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,10,
1209 10,10,10,10,10,10,10,10,
1210 10,10,10,10,10,10,10,10,
1211 10,10,10,10,10,10,10,10,
1212 10,10,10,10,10,10,10,10,
1213 10,10,10,10,10,10,10,10,
1214 10,10,10,10,10,10,10,10,
1215 10,10,10,10,10,10,10,10,
1216 10,10,10,10,10,10,10};
1218 int head3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1219 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1220 0x01,0x02,0x03,0x04,2,0,0,0,
1221 0x6c,0x3b,0x82,0x3d,
1224 int *headret[]={head1,head2,head3,NULL};
1226 fprintf(stderr,"testing max packet segments... ");
1227 test_pack(packets,headret);
1231 /* packet that overspans over an entire page */
1233 int packets[]={0,100,9000,259,255,-1};
1235 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1236 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1237 0x01,0x02,0x03,0x04,0,0,0,0,
1238 0xff,0x7b,0x23,0x17,
1242 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1243 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1244 0x01,0x02,0x03,0x04,1,0,0,0,
1245 0x3c,0xd9,0x4d,0x3f,
1247 100,255,255,255,255,255,255,255,255,
1248 255,255,255,255,255,255,255,255};
1250 int head3[] = {0x4f,0x67,0x67,0x53,0,0x01,
1251 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1252 0x01,0x02,0x03,0x04,2,0,0,0,
1253 0xbd,0xd5,0xb5,0x8b,
1255 255,255,255,255,255,255,255,255,
1256 255,255,255,255,255,255,255,255,255};
1258 int head4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1259 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1260 0x01,0x02,0x03,0x04,3,0,0,0,
1261 0xef,0xdd,0x88,0xde,
1263 255,255,75,255,4,255,0};
1264 int *headret[]={head1,head2,head3,head4,NULL};
1266 fprintf(stderr,"testing very large packets... ");
1267 test_pack(packets,headret);
1271 /* term only page. why not? */
1273 int packets[]={0,100,4080,-1};
1275 int head1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1276 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1277 0x01,0x02,0x03,0x04,0,0,0,0,
1278 0xff,0x7b,0x23,0x17,
1282 int head2[] = {0x4f,0x67,0x67,0x53,0,0x00,
1283 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1284 0x01,0x02,0x03,0x04,1,0,0,0,
1285 0x3c,0xd9,0x4d,0x3f,
1287 100,255,255,255,255,255,255,255,255,
1288 255,255,255,255,255,255,255,255};
1290 int head3[] = {0x4f,0x67,0x67,0x53,0,0x05,
1291 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1292 0x01,0x02,0x03,0x04,2,0,0,0,
1293 0xd4,0xe0,0x60,0xe5,
1296 int *headret[]={head1,head2,head3,NULL};
1298 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1299 test_pack(packets,headret);
1305 /* build a bunch of pages for testing */
1306 unsigned char *data=malloc(1024*1024);
1307 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1311 ogg_stream_reset(&os_en);
1313 for(i=0;pl[i]!=-1;i++){
1317 op.packet=data+inptr;
1319 op.e_o_s=(pl[i+1]<0?1:0);
1320 op.frameno=(i+1)*1000;
1322 for(j=0;j<len;j++)data[inptr++]=i+j;
1323 ogg_stream_packetin(&os_en,&op);
1328 /* retrieve finished pages */
1330 if(ogg_stream_pageout(&os_en,&og[i])==0){
1331 fprintf(stderr,"Too few pages output building sync tests!\n");
1337 /* Test lost pages on pagein/packetout: no rollback */
1342 fprintf(stderr,"Testing loss of pages... ");
1344 ogg_sync_reset(&oy);
1345 ogg_stream_reset(&os_de);
1347 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1349 ogg_sync_wrote(&oy,og[i].header_len);
1350 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1351 ogg_sync_wrote(&oy,og[i].body_len);
1354 ogg_sync_pageout(&oy,&temp);
1355 ogg_stream_pagein(&os_de,&temp);
1356 ogg_sync_pageout(&oy,&temp);
1357 ogg_stream_pagein(&os_de,&temp);
1358 ogg_sync_pageout(&oy,&temp);
1360 ogg_sync_pageout(&oy,&temp);
1361 ogg_stream_pagein(&os_de,&temp);
1363 /* do we get the expected results/packets? */
1365 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1366 checkpacket(&test,0,0,0);
1367 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1368 checkpacket(&test,100,1,-1);
1369 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1370 checkpacket(&test,4079,2,3000);
1371 if(ogg_stream_packetout(&os_de,&test)!=-1){
1372 fprintf(stderr,"Error: loss of page did not return error\n");
1375 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1376 checkpacket(&test,76,5,-1);
1377 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1378 checkpacket(&test,34,6,-1);
1379 fprintf(stderr,"ok.\n");
1382 /* Test lost pages on pagein/packetout: rollback with continuation */
1387 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1389 ogg_sync_reset(&oy);
1390 ogg_stream_reset(&os_de);
1392 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1394 ogg_sync_wrote(&oy,og[i].header_len);
1395 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1396 ogg_sync_wrote(&oy,og[i].body_len);
1399 ogg_sync_pageout(&oy,&temp);
1400 ogg_stream_pagein(&os_de,&temp);
1401 ogg_sync_pageout(&oy,&temp);
1402 ogg_stream_pagein(&os_de,&temp);
1403 ogg_sync_pageout(&oy,&temp);
1404 ogg_stream_pagein(&os_de,&temp);
1405 ogg_sync_pageout(&oy,&temp);
1407 ogg_sync_pageout(&oy,&temp);
1408 ogg_stream_pagein(&os_de,&temp);
1410 /* do we get the expected results/packets? */
1412 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1413 checkpacket(&test,0,0,0);
1414 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1415 checkpacket(&test,100,1,-1);
1416 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1417 checkpacket(&test,4079,2,3000);
1418 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1419 checkpacket(&test,2956,3,4000);
1420 if(ogg_stream_packetout(&os_de,&test)!=-1){
1421 fprintf(stderr,"Error: loss of page did not return error\n");
1424 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1425 checkpacket(&test,300,13,14000);
1426 fprintf(stderr,"ok.\n");
1429 /* the rest only test sync */
1432 /* Test fractional page inputs: incomplete capture */
1433 fprintf(stderr,"Testing sync on partial inputs... ");
1434 ogg_sync_reset(&oy);
1435 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1437 ogg_sync_wrote(&oy,3);
1438 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1440 /* Test fractional page inputs: incomplete fixed header */
1441 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1443 ogg_sync_wrote(&oy,20);
1444 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1446 /* Test fractional page inputs: incomplete header */
1447 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1449 ogg_sync_wrote(&oy,5);
1450 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1452 /* Test fractional page inputs: incomplete body */
1454 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1455 og[1].header_len-28);
1456 ogg_sync_wrote(&oy,og[1].header_len-28);
1457 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1459 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1460 ogg_sync_wrote(&oy,1000);
1461 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1463 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1464 og[1].body_len-1000);
1465 ogg_sync_wrote(&oy,og[1].body_len-1000);
1466 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1468 fprintf(stderr,"ok.\n");
1471 /* Test fractional page inputs: page + incomplete capture */
1474 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1475 ogg_sync_reset(&oy);
1477 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1479 ogg_sync_wrote(&oy,og[1].header_len);
1481 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1483 ogg_sync_wrote(&oy,og[1].body_len);
1485 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1487 ogg_sync_wrote(&oy,20);
1488 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1489 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1491 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1492 og[1].header_len-20);
1493 ogg_sync_wrote(&oy,og[1].header_len-20);
1494 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1496 ogg_sync_wrote(&oy,og[1].body_len);
1497 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1499 fprintf(stderr,"ok.\n");
1502 /* Test recapture: garbage + page */
1505 fprintf(stderr,"Testing search for capture... ");
1506 ogg_sync_reset(&oy);
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[1].header_len),og[1].header,
1515 ogg_sync_wrote(&oy,og[1].header_len);
1517 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1519 ogg_sync_wrote(&oy,og[1].body_len);
1521 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1523 ogg_sync_wrote(&oy,20);
1524 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1525 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1526 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1528 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1529 og[2].header_len-20);
1530 ogg_sync_wrote(&oy,og[2].header_len-20);
1531 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1533 ogg_sync_wrote(&oy,og[2].body_len);
1534 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1536 fprintf(stderr,"ok.\n");
1539 /* Test recapture: page + garbage + page */
1542 fprintf(stderr,"Testing recapture... ");
1543 ogg_sync_reset(&oy);
1545 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1547 ogg_sync_wrote(&oy,og[1].header_len);
1549 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1551 ogg_sync_wrote(&oy,og[1].body_len);
1553 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1555 ogg_sync_wrote(&oy,og[2].header_len);
1557 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1559 ogg_sync_wrote(&oy,og[2].header_len);
1561 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1563 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1565 ogg_sync_wrote(&oy,og[2].body_len-5);
1567 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1569 ogg_sync_wrote(&oy,og[3].header_len);
1571 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1573 ogg_sync_wrote(&oy,og[3].body_len);
1575 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1576 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1578 fprintf(stderr,"ok.\n");