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.22 2000/08/04 01:05:45 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 unsigned vorbis_size32_t crc_lookup[256];
77 static int crc_ready=0;
79 static unsigned vorbis_size32_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){
173 unsigned vorbis_size32_t crc_reg=0;
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 will flush remaining packets into a page (returning nonzero),
225 even if there is not enough data to trigger a flush normally
226 (undersized page). If there are no packets or partial packets to
227 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
228 try to flush a normal sized page like ogg_stream_pageout; a call to
229 ogg_stream_flush does not gurantee that all packets have flushed.
230 Only a return value of 0 from ogg_stream_flush indicates all packet
231 data is flushed into pages.
233 ogg_stream_page will flush the last page in a stream even if it's
234 undersized; you almost certainly want to use ogg_stream_pageout
235 (and *not* ogg_stream_flush) unless you need to flush an undersized
236 page in the middle of a stream for some reason. */
238 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
241 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
244 int64_t pcm_pos=os->pcm_vals[0];
246 if(maxvals==0)return(0);
248 /* construct a page */
249 /* decide how many segments to include */
251 /* If this is the initial header case, the first page must only include
252 the initial header packet */
253 if(os->b_o_s==0){ /* 'initial header page' case */
255 for(vals=0;vals<maxvals;vals++){
256 if((os->lacing_vals[vals]&0x0ff)<255){
262 for(vals=0;vals<maxvals;vals++){
264 acc+=os->lacing_vals[vals]&0x0ff;
265 pcm_pos=os->pcm_vals[vals];
269 /* construct the header in temp storage */
270 memcpy(os->header,"OggS",4);
272 /* stream structure version */
275 /* continued packet flag? */
277 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
278 /* first page flag? */
279 if(os->b_o_s==0)os->header[5]|=0x02;
280 /* last page flag? */
281 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
284 /* 64 bits of PCM position */
286 os->header[i]=(pcm_pos&0xff);
290 /* 32 bits of stream serial number */
292 long serialno=os->serialno;
294 os->header[i]=(serialno&0xff);
299 /* 32 bits of page counter (we have both counter and page header
300 because this val can roll over) */
301 if(os->pageno==-1)os->pageno=0; /* because someone called
302 stream_reset; this would be a
303 strange thing to do in an
304 encode stream, but it has
307 long pageno=os->pageno++;
309 os->header[i]=(pageno&0xff);
314 /* zero for computation; filled in later */
321 os->header[26]=vals&0xff;
323 bytes+=os->header[i+27]=(os->lacing_vals[i]&0xff);
325 /* advance the lacing data and set the body_returned pointer */
327 os->lacing_fill-=vals;
328 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(int));
329 memmove(os->pcm_vals,os->pcm_vals+vals,os->lacing_fill*sizeof(int64_t));
330 os->body_returned=bytes;
332 /* set pointers in the ogg_page struct */
333 og->header=os->header;
334 og->header_len=os->header_fill=vals+27;
335 og->body=os->body_data;
338 /* calculate the checksum */
347 /* This constructs pages from buffered packet segments. The pointers
348 returned are to static buffers; do not free. The returned buffers are
349 good only until the next call (using the same ogg_stream_state) */
351 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
353 if(os->body_returned){
354 /* advance packet data according to the body_returned pointer. We
355 had to keep it around to return a pointer into the buffer last
358 os->body_fill-=os->body_returned;
360 memmove(os->body_data,os->body_data+os->body_returned,
361 os->body_fill*sizeof(char));
365 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
366 os->body_fill > 4096 || /* 'page nominal size' case */
367 os->lacing_fill>=255 || /* 'segment table full' case */
368 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
370 return(ogg_stream_flush(os,og));
373 /* not enough data to construct a page and not end of stream */
377 int ogg_stream_eof(ogg_stream_state *os){
381 /* DECODING PRIMITIVES: packet streaming layer **********************/
383 /* This has two layers to place more of the multi-serialno and paging
384 control in the application's hands. First, we expose a data buffer
385 using ogg_sync_buffer(). The app either copies into the
386 buffer, or passes it directly to read(), etc. We then call
387 ogg_sync_wrote() to tell how many bytes we just added.
389 Pages are returned (pointers into the buffer in ogg_sync_state)
390 by ogg_sync_pageout(). The page is then submitted to
391 ogg_stream_pagein() along with the appropriate
392 ogg_stream_state* (ie, matching serialno). We then get raw
393 packets out calling ogg_stream_packetout() with a
394 ogg_stream_state. See the 'frame-prog.txt' docs for details and
397 /* initialize the struct to a known state */
398 int ogg_sync_init(ogg_sync_state *oy){
400 memset(oy,0,sizeof(ogg_sync_state));
406 /* clear non-flat storage within */
407 int ogg_sync_clear(ogg_sync_state *oy){
409 if(oy->data)free(oy->data);
415 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
417 /* first, clear out any space that has been previously returned */
419 oy->fill-=oy->returned;
421 memmove(oy->data,oy->data+oy->returned,
422 (oy->fill)*sizeof(char));
426 if(size>oy->storage-oy->fill){
427 /* We need to extend the internal buffer */
428 long newsize=size+oy->fill+4096; /* an extra page to be nice */
431 oy->data=realloc(oy->data,newsize);
433 oy->data=malloc(newsize);
437 /* expose a segment at least as large as requested at the fill mark */
438 return((char *)oy->data+oy->fill);
441 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
442 if(oy->fill+bytes>oy->storage)return(-1);
447 /* sync the stream. This is meant to be useful for finding page
450 return values for this:
452 0) page not ready; more data (no bytes skipped)
453 n) page synced at current location; page length n bytes
457 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
458 unsigned char *page=oy->data+oy->returned;
460 long bytes=oy->fill-oy->returned;
462 if(oy->headerbytes==0){
464 if(bytes<27)return(0); /* not enough for a header */
466 /* verify capture pattern */
467 if(memcmp(page,"OggS",4))goto sync_fail;
469 headerbytes=page[26]+27;
470 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
472 /* count up body length in the segment table */
474 for(i=0;i<page[26];i++)
475 oy->bodybytes+=page[27+i];
476 oy->headerbytes=headerbytes;
479 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
481 /* The whole test page is buffered. Verify the checksum */
483 /* Grab the checksum bytes, set the header field to zero */
487 memcpy(chksum,page+22,4);
490 /* set up a temp page struct and recompute the checksum */
492 log.header_len=oy->headerbytes;
493 log.body=page+oy->headerbytes;
494 log.body_len=oy->bodybytes;
498 if(memcmp(chksum,page+22,4)){
499 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
501 /* replace the computed checksum with the one actually read in */
502 memcpy(page+22,chksum,4);
504 /* Bad checksum. Lose sync */
509 /* yes, have a whole page all ready to go */
511 unsigned char *page=oy->data+oy->returned;
516 og->header_len=oy->headerbytes;
517 og->body=page+oy->headerbytes;
518 og->body_len=oy->bodybytes;
522 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
533 /* search for possible capture */
534 next=memchr(page+1,'O',bytes-1);
536 next=oy->data+oy->fill;
538 oy->returned=next-oy->data;
539 return(-(next-page));
542 /* sync the stream and get a page. Keep trying until we find a page.
543 Supress 'sync errors' after reporting the first.
546 -1) recapture (hole in data)
550 Returns pointers into buffered data; invalidated by next call to
551 _stream, _clear, _init, or _buffer */
553 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
555 /* all we need to do is verify a page at the head of the stream
556 buffer. If it doesn't verify, we look for the next potential
560 long ret=ogg_sync_pageseek(oy,og);
570 /* head did not start a synced page... skipped some bytes */
576 /* loop. keep looking */
581 /* add the incoming page to the stream state; we decompose the page
582 into packet segments here as well. */
584 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
585 unsigned char *header=og->header;
586 unsigned char *body=og->body;
587 long bodysize=og->body_len;
590 int version=ogg_page_version(og);
591 int continued=ogg_page_continued(og);
592 int bos=ogg_page_bos(og);
593 int eos=ogg_page_eos(og);
594 int64_t pcmpos=ogg_page_frameno(og);
595 int serialno=ogg_page_serialno(og);
596 int pageno=ogg_page_pageno(og);
597 int segments=header[26];
599 /* clean up 'returned data' */
601 long lr=os->lacing_returned;
602 long br=os->body_returned;
608 memmove(os->body_data,os->body_data+br,os->body_fill);
614 if(os->lacing_fill-lr){
615 memmove(os->lacing_vals,os->lacing_vals+lr,
616 (os->lacing_fill-lr)*sizeof(int));
617 memmove(os->pcm_vals,os->pcm_vals+lr,
618 (os->lacing_fill-lr)*sizeof(int64_t));
621 os->lacing_packet-=lr;
622 os->lacing_returned=0;
626 /* check the serial number */
627 if(serialno!=os->serialno)return(-1);
628 if(version>0)return(-1);
630 _os_lacing_expand(os,segments+1);
632 /* are we in sequence? */
633 if(pageno!=os->pageno){
636 /* unroll previous partial packet (if any) */
637 for(i=os->lacing_packet;i<os->lacing_fill;i++)
638 os->body_fill-=os->lacing_vals[i]&0xff;
639 os->lacing_fill=os->lacing_packet;
641 /* make a note of dropped data in segment table */
643 os->lacing_vals[os->lacing_fill++]=0x400;
647 /* are we a 'continued packet' page? If so, we'll need to skip
651 for(;segptr<segments;segptr++){
652 int val=header[27+segptr];
664 _os_body_expand(os,bodysize);
665 memcpy(os->body_data+os->body_fill,body,bodysize);
666 os->body_fill+=bodysize;
671 while(segptr<segments){
672 int val=header[27+segptr];
673 os->lacing_vals[os->lacing_fill]=val;
674 os->pcm_vals[os->lacing_fill]=-1;
677 os->lacing_vals[os->lacing_fill]|=0x100;
681 if(val<255)saved=os->lacing_fill;
686 if(val<255)os->lacing_packet=os->lacing_fill;
689 /* set the pcmpos on the last pcmval of the last full packet */
691 os->pcm_vals[saved]=pcmpos;
698 if(os->lacing_fill>0)
699 os->lacing_vals[os->lacing_fill-1]|=0x200;
707 /* clear things to an initial state. Good to call, eg, before seeking */
708 int ogg_sync_reset(ogg_sync_state *oy){
717 int ogg_stream_reset(ogg_stream_state *os){
723 os->lacing_returned=0;
736 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
738 /* The last part of decode. We have the stream broken into packet
739 segments. Now we need to group them into packets (or return the
740 out of sync markers) */
742 int ptr=os->lacing_returned;
744 if(os->lacing_packet<=ptr)return(0);
746 if(os->lacing_vals[ptr]&0x400){
747 /* We lost sync here; let the app know */
748 os->lacing_returned++;
750 /* we need to tell the codec there's a gap; it might need to
751 handle previous packet dependencies. */
756 /* Gather the whole packet. We'll have no holes or a partial packet */
758 int size=os->lacing_vals[ptr]&0xff;
761 op->packet=os->body_data+os->body_returned;
762 op->e_o_s=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
763 op->b_o_s=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
767 int val=os->lacing_vals[++ptr];
769 if(val&0x200)op->e_o_s=0x200;
773 op->packetno=os->packetno;
774 op->frameno=os->pcm_vals[ptr];
777 os->body_returned+=bytes;
778 os->lacing_returned=ptr+1;
787 ogg_stream_state os_en, os_de;
790 void checkpacket(ogg_packet *op,int len, int no, int pos){
792 static int sequence=0;
796 fprintf(stderr,"incorrect packet length!\n");
799 if(op->frameno!=pos){
800 fprintf(stderr,"incorrect packet position!\n");
804 /* packet number just follows sequence/gap; adjust the input number
814 if(op->packetno!=sequence){
815 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
816 (long)(op->packetno),sequence);
821 for(j=0;j<op->bytes;j++)
822 if(op->packet[j]!=((j+no)&0xff)){
823 fprintf(stderr,"body data mismatch at pos %ld: %x!=%lx!\n\n",
824 j,op->packet[j],(j+no)&0xff);
829 void check_page(unsigned char *data,const int *header,ogg_page *og){
832 for(j=0;j<og->body_len;j++)
833 if(og->body[j]!=data[j]){
834 fprintf(stderr,"body data mismatch at pos %ld: %x!=%x!\n\n",
835 j,data[j],og->body[j]);
840 for(j=0;j<og->header_len;j++){
841 if(og->header[j]!=header[j]){
842 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
843 for(j=0;j<header[26]+27;j++)
844 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
845 fprintf(stderr,"\n");
849 if(og->header_len!=header[26]+27){
850 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
851 og->header_len,header[26]+27);
856 void print_header(ogg_page *og){
858 fprintf(stderr,"\nHEADER:\n");
859 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
860 og->header[0],og->header[1],og->header[2],og->header[3],
861 (int)og->header[4],(int)og->header[5]);
863 fprintf(stderr," pcmpos: %d serialno: %d pageno: %d\n",
864 (og->header[9]<<24)|(og->header[8]<<16)|
865 (og->header[7]<<8)|og->header[6],
866 (og->header[17]<<24)|(og->header[16]<<16)|
867 (og->header[15]<<8)|og->header[14],
868 (og->header[21]<<24)|(og->header[20]<<16)|
869 (og->header[19]<<8)|og->header[18]);
871 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
872 (int)og->header[22],(int)og->header[23],
873 (int)og->header[24],(int)og->header[25],
874 (int)og->header[26]);
876 for(j=27;j<og->header_len;j++)
877 fprintf(stderr,"%d ",(int)og->header[j]);
878 fprintf(stderr,")\n\n");
881 void copy_page(ogg_page *og){
882 unsigned char *temp=malloc(og->header_len);
883 memcpy(temp,og->header,og->header_len);
886 temp=malloc(og->body_len);
887 memcpy(temp,og->body,og->body_len);
892 fprintf(stderr,"error!\n");
897 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
898 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
899 0x01,0x02,0x03,0x04,0,0,0,0,
904 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
905 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
906 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
907 0x01,0x02,0x03,0x04,0,0,0,0,
911 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
912 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
913 0x01,0x02,0x03,0x04,1,0,0,0,
916 254,255,0,255,1,255,245,255,255,0,
919 /* nil packets; beginning,middle,end */
920 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
921 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
922 0x01,0x02,0x03,0x04,0,0,0,0,
926 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
927 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
928 0x01,0x02,0x03,0x04,1,0,0,0,
931 17,254,255,0,0,255,1,0,255,245,255,255,0,
934 /* large initial packet */
935 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
936 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
937 0x01,0x02,0x03,0x04,0,0,0,0,
940 255,255,255,255,255,255,255,255,
941 255,255,255,255,255,255,255,255,255,10};
943 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
944 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
945 0x01,0x02,0x03,0x04,1,0,0,0,
951 /* continuing packet test */
952 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
953 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
954 0x01,0x02,0x03,0x04,0,0,0,0,
959 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
960 0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
961 0x01,0x02,0x03,0x04,1,0,0,0,
964 255,255,255,255,255,255,255,255,
965 255,255,255,255,255,255,255,255,255};
967 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
968 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
969 0x01,0x02,0x03,0x04,2,0,0,0,
975 /* page with the 255 segment limit */
976 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
977 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
978 0x01,0x02,0x03,0x04,0,0,0,0,
983 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
984 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
985 0x01,0x02,0x03,0x04,1,0,0,0,
988 10,10,10,10,10,10,10,10,
989 10,10,10,10,10,10,10,10,
990 10,10,10,10,10,10,10,10,
991 10,10,10,10,10,10,10,10,
992 10,10,10,10,10,10,10,10,
993 10,10,10,10,10,10,10,10,
994 10,10,10,10,10,10,10,10,
995 10,10,10,10,10,10,10,10,
996 10,10,10,10,10,10,10,10,
997 10,10,10,10,10,10,10,10,
998 10,10,10,10,10,10,10,10,
999 10,10,10,10,10,10,10,10,
1000 10,10,10,10,10,10,10,10,
1001 10,10,10,10,10,10,10,10,
1002 10,10,10,10,10,10,10,10,
1003 10,10,10,10,10,10,10,10,
1004 10,10,10,10,10,10,10,10,
1005 10,10,10,10,10,10,10,10,
1006 10,10,10,10,10,10,10,10,
1007 10,10,10,10,10,10,10,10,
1008 10,10,10,10,10,10,10,10,
1009 10,10,10,10,10,10,10,10,
1010 10,10,10,10,10,10,10,10,
1011 10,10,10,10,10,10,10,10,
1012 10,10,10,10,10,10,10,10,
1013 10,10,10,10,10,10,10,10,
1014 10,10,10,10,10,10,10,10,
1015 10,10,10,10,10,10,10,10,
1016 10,10,10,10,10,10,10,10,
1017 10,10,10,10,10,10,10,10,
1018 10,10,10,10,10,10,10,10,
1019 10,10,10,10,10,10,10};
1021 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1022 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1023 0x01,0x02,0x03,0x04,2,0,0,0,
1024 0x6c,0x3b,0x82,0x3d,
1029 /* packet that overspans over an entire page */
1030 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1031 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1032 0x01,0x02,0x03,0x04,0,0,0,0,
1033 0xff,0x7b,0x23,0x17,
1037 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1038 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1039 0x01,0x02,0x03,0x04,1,0,0,0,
1040 0x3c,0xd9,0x4d,0x3f,
1042 100,255,255,255,255,255,255,255,255,
1043 255,255,255,255,255,255,255,255};
1045 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1046 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1047 0x01,0x02,0x03,0x04,2,0,0,0,
1048 0xbd,0xd5,0xb5,0x8b,
1050 255,255,255,255,255,255,255,255,
1051 255,255,255,255,255,255,255,255,255};
1053 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1054 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1055 0x01,0x02,0x03,0x04,3,0,0,0,
1056 0xef,0xdd,0x88,0xde,
1058 255,255,75,255,4,255,0};
1060 /* packet that overspans over an entire page */
1061 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1062 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1063 0x01,0x02,0x03,0x04,0,0,0,0,
1064 0xff,0x7b,0x23,0x17,
1068 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1069 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1070 0x01,0x02,0x03,0x04,1,0,0,0,
1071 0x3c,0xd9,0x4d,0x3f,
1073 100,255,255,255,255,255,255,255,255,
1074 255,255,255,255,255,255,255,255};
1076 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1077 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1078 0x01,0x02,0x03,0x04,2,0,0,0,
1079 0xd4,0xe0,0x60,0xe5,
1082 void test_pack(const int *pl, const int **headers){
1083 unsigned char *data=malloc(1024*1024); /* for scripted test cases only */
1089 int i,j,packets,pageno=0,pageout=0;
1093 ogg_stream_reset(&os_en);
1094 ogg_stream_reset(&os_de);
1095 ogg_sync_reset(&oy);
1097 for(packets=0;;packets++)if(pl[packets]==-1)break;
1099 for(i=0;i<packets;i++){
1100 /* construct a test packet */
1104 op.packet=data+inptr;
1106 op.e_o_s=(pl[i+1]<0?1:0);
1111 for(j=0;j<len;j++)data[inptr++]=i+j;
1113 /* submit the test packet */
1114 ogg_stream_packetin(&os_en,&op);
1116 /* retrieve any finished pages */
1120 while(ogg_stream_pageout(&os_en,&og)){
1121 /* We have a page. Check it carefully */
1123 fprintf(stderr,"%d, ",pageno);
1125 if(headers[pageno]==NULL){
1126 fprintf(stderr,"coded too many pages!\n");
1130 check_page(data+outptr,headers[pageno],&og);
1132 outptr+=og.body_len;
1135 /* have a complete page; submit it to sync/decode */
1140 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1141 memcpy(buf,og.header,og.header_len);
1142 memcpy(buf+og.header_len,og.body,og.body_len);
1143 ogg_sync_wrote(&oy,og.header_len+og.body_len);
1145 while(ogg_sync_pageout(&oy,&og_de)>0){
1146 /* got a page. Happy happy. Verify that it's good. */
1148 check_page(data+deptr,headers[pageout],&og_de);
1149 deptr+=og_de.body_len;
1152 /* submit it to deconstitution */
1153 ogg_stream_pagein(&os_de,&og_de);
1156 while(ogg_stream_packetout(&os_de,&op_de)>0){
1158 /* verify the packet! */
1160 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1161 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1165 /* check bos flag */
1166 if(bosflag==0 && op_de.b_o_s==0){
1167 fprintf(stderr,"b_o_s flag not set on packet!\n");
1170 if(bosflag && op_de.b_o_s){
1171 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1175 depacket+=op_de.bytes;
1177 /* check eos flag */
1179 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1183 if(op_de.e_o_s)eosflag=1;
1185 /* check pcmpos flag */
1186 if(op_de.frameno!=-1){
1187 fprintf(stderr," pcm:%ld ",(long)op_de.frameno);
1196 if(headers[pageno]!=NULL){
1197 fprintf(stderr,"did not write last page!\n");
1200 if(headers[pageout]!=NULL){
1201 fprintf(stderr,"did not decode last page!\n");
1205 fprintf(stderr,"encoded page data incomplete!\n");
1209 fprintf(stderr,"decoded page data incomplete!\n");
1212 if(inptr!=depacket){
1213 fprintf(stderr,"decoded packet data incomplete!\n");
1217 fprintf(stderr,"Never got a packet with EOS set!\n");
1220 fprintf(stderr,"ok.\n");
1225 ogg_stream_init(&os_en,0x04030201);
1226 ogg_stream_init(&os_de,0x04030201);
1229 /* Exercise each code path in the framing code. Also verify that
1230 the checksums are working. */
1234 const int packets[]={17, -1};
1235 const int *headret[]={head1_0,NULL};
1237 fprintf(stderr,"testing single page encoding... ");
1238 test_pack(packets,headret);
1242 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1243 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1244 const int *headret[]={head1_1,head2_1,NULL};
1246 fprintf(stderr,"testing basic page encoding... ");
1247 test_pack(packets,headret);
1251 /* nil packets; beginning,middle,end */
1252 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1253 const int *headret[]={head1_2,head2_2,NULL};
1255 fprintf(stderr,"testing basic nil packets... ");
1256 test_pack(packets,headret);
1260 /* large initial packet */
1261 const int packets[]={4345,259,255,-1};
1262 const int *headret[]={head1_3,head2_3,NULL};
1264 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1265 test_pack(packets,headret);
1269 /* continuing packet test */
1270 const int packets[]={0,4345,259,255,-1};
1271 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1273 fprintf(stderr,"testing single packet page span... ");
1274 test_pack(packets,headret);
1277 /* page with the 255 segment limit */
1280 const int packets[]={0,10,10,10,10,10,10,10,10,
1281 10,10,10,10,10,10,10,10,
1282 10,10,10,10,10,10,10,10,
1283 10,10,10,10,10,10,10,10,
1284 10,10,10,10,10,10,10,10,
1285 10,10,10,10,10,10,10,10,
1286 10,10,10,10,10,10,10,10,
1287 10,10,10,10,10,10,10,10,
1288 10,10,10,10,10,10,10,10,
1289 10,10,10,10,10,10,10,10,
1290 10,10,10,10,10,10,10,10,
1291 10,10,10,10,10,10,10,10,
1292 10,10,10,10,10,10,10,10,
1293 10,10,10,10,10,10,10,10,
1294 10,10,10,10,10,10,10,10,
1295 10,10,10,10,10,10,10,10,
1296 10,10,10,10,10,10,10,10,
1297 10,10,10,10,10,10,10,10,
1298 10,10,10,10,10,10,10,10,
1299 10,10,10,10,10,10,10,10,
1300 10,10,10,10,10,10,10,10,
1301 10,10,10,10,10,10,10,10,
1302 10,10,10,10,10,10,10,10,
1303 10,10,10,10,10,10,10,10,
1304 10,10,10,10,10,10,10,10,
1305 10,10,10,10,10,10,10,10,
1306 10,10,10,10,10,10,10,10,
1307 10,10,10,10,10,10,10,10,
1308 10,10,10,10,10,10,10,10,
1309 10,10,10,10,10,10,10,10,
1310 10,10,10,10,10,10,10,10,
1311 10,10,10,10,10,10,10,50,-1};
1312 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1314 fprintf(stderr,"testing max packet segments... ");
1315 test_pack(packets,headret);
1319 /* packet that overspans over an entire page */
1320 const int packets[]={0,100,9000,259,255,-1};
1321 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1323 fprintf(stderr,"testing very large packets... ");
1324 test_pack(packets,headret);
1328 /* term only page. why not? */
1329 const int packets[]={0,100,4080,-1};
1330 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1332 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1333 test_pack(packets,headret);
1339 /* build a bunch of pages for testing */
1340 unsigned char *data=malloc(1024*1024);
1341 int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
1345 ogg_stream_reset(&os_en);
1347 for(i=0;pl[i]!=-1;i++){
1351 op.packet=data+inptr;
1353 op.e_o_s=(pl[i+1]<0?1:0);
1354 op.frameno=(i+1)*1000;
1356 for(j=0;j<len;j++)data[inptr++]=i+j;
1357 ogg_stream_packetin(&os_en,&op);
1362 /* retrieve finished pages */
1364 if(ogg_stream_pageout(&os_en,&og[i])==0){
1365 fprintf(stderr,"Too few pages output building sync tests!\n");
1371 /* Test lost pages on pagein/packetout: no rollback */
1376 fprintf(stderr,"Testing loss of pages... ");
1378 ogg_sync_reset(&oy);
1379 ogg_stream_reset(&os_de);
1381 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1383 ogg_sync_wrote(&oy,og[i].header_len);
1384 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1385 ogg_sync_wrote(&oy,og[i].body_len);
1388 ogg_sync_pageout(&oy,&temp);
1389 ogg_stream_pagein(&os_de,&temp);
1390 ogg_sync_pageout(&oy,&temp);
1391 ogg_stream_pagein(&os_de,&temp);
1392 ogg_sync_pageout(&oy,&temp);
1394 ogg_sync_pageout(&oy,&temp);
1395 ogg_stream_pagein(&os_de,&temp);
1397 /* do we get the expected results/packets? */
1399 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1400 checkpacket(&test,0,0,0);
1401 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1402 checkpacket(&test,100,1,-1);
1403 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1404 checkpacket(&test,4079,2,3000);
1405 if(ogg_stream_packetout(&os_de,&test)!=-1){
1406 fprintf(stderr,"Error: loss of page did not return error\n");
1409 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1410 checkpacket(&test,76,5,-1);
1411 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1412 checkpacket(&test,34,6,-1);
1413 fprintf(stderr,"ok.\n");
1416 /* Test lost pages on pagein/packetout: rollback with continuation */
1421 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1423 ogg_sync_reset(&oy);
1424 ogg_stream_reset(&os_de);
1426 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1428 ogg_sync_wrote(&oy,og[i].header_len);
1429 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1430 ogg_sync_wrote(&oy,og[i].body_len);
1433 ogg_sync_pageout(&oy,&temp);
1434 ogg_stream_pagein(&os_de,&temp);
1435 ogg_sync_pageout(&oy,&temp);
1436 ogg_stream_pagein(&os_de,&temp);
1437 ogg_sync_pageout(&oy,&temp);
1438 ogg_stream_pagein(&os_de,&temp);
1439 ogg_sync_pageout(&oy,&temp);
1441 ogg_sync_pageout(&oy,&temp);
1442 ogg_stream_pagein(&os_de,&temp);
1444 /* do we get the expected results/packets? */
1446 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1447 checkpacket(&test,0,0,0);
1448 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1449 checkpacket(&test,100,1,-1);
1450 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1451 checkpacket(&test,4079,2,3000);
1452 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1453 checkpacket(&test,2956,3,4000);
1454 if(ogg_stream_packetout(&os_de,&test)!=-1){
1455 fprintf(stderr,"Error: loss of page did not return error\n");
1458 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1459 checkpacket(&test,300,13,14000);
1460 fprintf(stderr,"ok.\n");
1463 /* the rest only test sync */
1466 /* Test fractional page inputs: incomplete capture */
1467 fprintf(stderr,"Testing sync on partial inputs... ");
1468 ogg_sync_reset(&oy);
1469 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1471 ogg_sync_wrote(&oy,3);
1472 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1474 /* Test fractional page inputs: incomplete fixed header */
1475 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1477 ogg_sync_wrote(&oy,20);
1478 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1480 /* Test fractional page inputs: incomplete header */
1481 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1483 ogg_sync_wrote(&oy,5);
1484 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1486 /* Test fractional page inputs: incomplete body */
1488 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1489 og[1].header_len-28);
1490 ogg_sync_wrote(&oy,og[1].header_len-28);
1491 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1493 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1494 ogg_sync_wrote(&oy,1000);
1495 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1497 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1498 og[1].body_len-1000);
1499 ogg_sync_wrote(&oy,og[1].body_len-1000);
1500 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1502 fprintf(stderr,"ok.\n");
1505 /* Test fractional page inputs: page + incomplete capture */
1508 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1509 ogg_sync_reset(&oy);
1511 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1513 ogg_sync_wrote(&oy,og[1].header_len);
1515 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1517 ogg_sync_wrote(&oy,og[1].body_len);
1519 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1521 ogg_sync_wrote(&oy,20);
1522 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1523 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1525 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1526 og[1].header_len-20);
1527 ogg_sync_wrote(&oy,og[1].header_len-20);
1528 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1530 ogg_sync_wrote(&oy,og[1].body_len);
1531 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1533 fprintf(stderr,"ok.\n");
1536 /* Test recapture: garbage + page */
1539 fprintf(stderr,"Testing search for capture... ");
1540 ogg_sync_reset(&oy);
1543 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1545 ogg_sync_wrote(&oy,og[1].body_len);
1547 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1549 ogg_sync_wrote(&oy,og[1].header_len);
1551 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1553 ogg_sync_wrote(&oy,og[1].body_len);
1555 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1557 ogg_sync_wrote(&oy,20);
1558 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1559 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1560 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1562 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
1563 og[2].header_len-20);
1564 ogg_sync_wrote(&oy,og[2].header_len-20);
1565 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1567 ogg_sync_wrote(&oy,og[2].body_len);
1568 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1570 fprintf(stderr,"ok.\n");
1573 /* Test recapture: page + garbage + page */
1576 fprintf(stderr,"Testing recapture... ");
1577 ogg_sync_reset(&oy);
1579 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1581 ogg_sync_wrote(&oy,og[1].header_len);
1583 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1585 ogg_sync_wrote(&oy,og[1].body_len);
1587 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1589 ogg_sync_wrote(&oy,og[2].header_len);
1591 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
1593 ogg_sync_wrote(&oy,og[2].header_len);
1595 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1597 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
1599 ogg_sync_wrote(&oy,og[2].body_len-5);
1601 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
1603 ogg_sync_wrote(&oy,og[3].header_len);
1605 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
1607 ogg_sync_wrote(&oy,og[3].body_len);
1609 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1610 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1612 fprintf(stderr,"ok.\n");