examples/sfexamples/oggvorbiscodec/src/tremor/framing.c

00001 /********************************************************************
00002  *                                                                  *
00003  * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE.   *
00004  *                                                                  *
00005  * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
00006  * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
00007  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
00008  *                                                                  *
00009  * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003    *
00010  * BY THE Xiph.Org FOUNDATION http://www.xiph.org/                  *
00011  *                                                                  *
00012  ********************************************************************
00013 
00014  function: decode Ogg streams back into raw packets
00015 
00016  note: The CRC code is directly derived from public domain code by
00017  Ross Williams (ross@guest.adelaide.edu.au).  See docs/framing.html
00018  for details.
00019 
00020  ********************************************************************/
00021 
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include "ogg.h"
00025 #include "misc.h"
00026 
00027 
00028 /* A complete description of Ogg framing exists in docs/framing.html */
00029 
00030 /* basic, centralized Ogg memory management based on linked lists of
00031    references to refcounted memory buffers.  References and buffers
00032    are both recycled.  Buffers are passed around and consumed in
00033    reference form. */
00034 
00035 static ogg_buffer_state *ogg_buffer_create(void){
00036   ogg_buffer_state *bs=(ogg_buffer_state *)_ogg_calloc(1,sizeof(*bs));
00037   return bs;
00038 }
00039 
00040 /* destruction is 'lazy'; there may be memory references outstanding,
00041    and yanking the buffer state out from underneath would be
00042    antisocial.  Dealloc what is currently unused and have
00043    _release_one watch for the stragglers to come in.  When they do,
00044    finish destruction. */
00045 
00046 /* call the helper while holding lock */
00047 static void _ogg_buffer_destroy(ogg_buffer_state *bs){
00048   ogg_buffer *bt;
00049   ogg_reference *rt;
00050 
00051   if(bs->shutdown){
00052 
00053     bt=bs->unused_buffers;
00054     rt=bs->unused_references;
00055 
00056     while(bt){
00057       ogg_buffer *b=bt;
00058       bt=b->ptr.next;
00059       if(b->data)_ogg_free(b->data);
00060       _ogg_free(b);
00061     }
00062     bs->unused_buffers=0;
00063     while(rt){
00064       ogg_reference *r=rt;
00065       rt=r->next;
00066       _ogg_free(r);
00067     }
00068     bs->unused_references=0;
00069     
00070     if(!bs->outstanding){
00071       _ogg_free(bs);
00072       return;
00073     }
00074 
00075   }
00076 }
00077 
00078 static void ogg_buffer_destroy(ogg_buffer_state *bs){
00079   bs->shutdown=1;
00080   _ogg_buffer_destroy(bs);
00081 }
00082 
00083 static ogg_buffer *_fetch_buffer(ogg_buffer_state *bs,long bytes){
00084   ogg_buffer    *ob;
00085   bs->outstanding++;
00086 
00087   /* do we have an unused buffer sitting in the pool? */
00088   if(bs->unused_buffers){
00089     ob=bs->unused_buffers;
00090     bs->unused_buffers=ob->ptr.next;
00091 
00092     /* if the unused buffer is too small, grow it */
00093     if(ob->size<bytes){
00094       ob->data=(unsigned char* )_ogg_realloc(ob->data,bytes);
00095       ob->size=bytes;
00096     }
00097   }else{
00098     /* allocate a new buffer */
00099     ob=(ogg_buffer* )_ogg_malloc(sizeof(*ob));
00100     ob->data=(unsigned char* )_ogg_malloc(bytes<16?16:bytes);
00101     ob->size=bytes;
00102   }
00103 
00104   ob->refcount=1;
00105   ob->ptr.owner=bs;
00106   return ob;
00107 }
00108 
00109 static ogg_reference *_fetch_ref(ogg_buffer_state *bs){
00110   ogg_reference *oggref;
00111   bs->outstanding++;
00112 
00113   /* do we have an unused reference sitting in the pool? */
00114   if(bs->unused_references){
00115     oggref=bs->unused_references;
00116     bs->unused_references=oggref->next;
00117   }else{
00118     /* allocate a new reference */
00119     oggref=(ogg_reference *)_ogg_malloc(sizeof(*oggref));
00120   }
00121 
00122   oggref->begin=0;
00123   oggref->length=0;
00124   oggref->next=0;
00125   return oggref;
00126 }
00127 
00128 /* fetch a reference pointing to a fresh, initially continguous buffer
00129    of at least [bytes] length */
00130 static ogg_reference *ogg_buffer_alloc(ogg_buffer_state *bs,long bytes){
00131   ogg_buffer    *ob=_fetch_buffer(bs,bytes);
00132   ogg_reference *oggref=_fetch_ref(bs);
00133   oggref->buffer=ob;
00134   return oggref;
00135 }
00136 
00137 /* enlarge the data buffer in the current link */
00138 static void ogg_buffer_realloc(ogg_reference *oggref,long bytes){
00139   ogg_buffer    *ob=oggref->buffer;
00140   
00141   /* if the unused buffer is too small, grow it */
00142   if(ob->size<bytes){
00143     ob->data=(unsigned char* )_ogg_realloc(ob->data,bytes);
00144     ob->size=bytes;
00145   }
00146 }
00147 
00148 static void _ogg_buffer_mark_one(ogg_reference *oggref){
00149   oggref->buffer->refcount++;
00150 }
00151 
00152 /* increase the refcount of the buffers to which the reference points */
00153 static void ogg_buffer_mark(ogg_reference *oggref){
00154   while(oggref){
00155     _ogg_buffer_mark_one(oggref);
00156     oggref=oggref->next;
00157   }
00158 }
00159 
00160 /* duplicate a reference (pointing to the same actual buffer memory)
00161    and increment buffer refcount.  If the desired segment begins out
00162    of range, NULL is returned; if the desired segment is simply zero
00163    length, a zero length ref is returned.  Partial range overlap
00164    returns the overlap of the ranges */
00165 static ogg_reference *ogg_buffer_sub(ogg_reference *oggref,long begin,long length){
00166   ogg_reference *ret=0,*head=0;
00167 
00168   /* walk past any preceeding fragments we don't want */
00169   while(oggref && begin>=oggref->length){
00170     begin-=oggref->length;
00171     oggref=oggref->next;
00172   }
00173 
00174   /* duplicate the reference chain; increment refcounts */
00175   while(oggref && length){
00176     ogg_reference *temp=_fetch_ref(oggref->buffer->ptr.owner);
00177     if(head)
00178       head->next=temp;
00179     else
00180       ret=temp;
00181     head=temp;
00182     head->buffer=oggref->buffer;    
00183     head->begin=oggref->begin+begin;
00184     head->length=length;
00185     if(head->length>oggref->length-begin)
00186       head->length=oggref->length-begin;
00187     
00188     begin=0;
00189     length-=head->length;
00190     oggref=oggref->next;
00191   }
00192 
00193   ogg_buffer_mark(ret);
00194   return ret;
00195 }
00196 
00197 ogg_reference *ogg_buffer_dup(ogg_reference *oggref){
00198   ogg_reference *ret=0,*head=0;
00199   /* duplicate the reference chain; increment refcounts */
00200   while(oggref){
00201     ogg_reference *temp=_fetch_ref(oggref->buffer->ptr.owner);
00202     if(head)
00203       head->next=temp;
00204     else
00205       ret=temp;
00206     head=temp;
00207     head->buffer=oggref->buffer;    
00208     head->begin=oggref->begin;
00209     head->length=oggref->length;
00210     oggref=oggref->next;
00211   }
00212 
00213   ogg_buffer_mark(ret);
00214   return ret;
00215 }
00216 
00217 /* split a reference into two references; 'return' is a reference to
00218    the buffer preceeding pos and 'head'/'tail' are the buffer past the
00219    split.  If pos is at or past the end of the passed in segment,
00220    'head/tail' are NULL */
00221 static ogg_reference *ogg_buffer_split(ogg_reference **tail,
00222                                 ogg_reference **head,long pos){
00223 
00224   /* walk past any preceeding fragments to one of:
00225      a) the exact boundary that seps two fragments
00226      b) the fragment that needs split somewhere in the middle */
00227   ogg_reference *ret=*tail;
00228   ogg_reference *oggref=*tail;
00229 
00230   while(oggref && pos>oggref->length){
00231     pos-=oggref->length;
00232     oggref=oggref->next;
00233   }
00234 
00235   if(!oggref || pos==0){
00236 
00237     return 0;
00238     
00239   }else{
00240     
00241     if(pos>=oggref->length){
00242       /* exact split, oggref off the end? */
00243       if(oggref->next){
00244         
00245         /* a split */
00246         *tail=oggref->next;
00247         oggref->next=0;
00248         
00249       }else{
00250         
00251         /* off oggref at the end */
00252         *tail=*head=0;
00253         
00254       }
00255     }else{
00256       
00257       /* split within a fragment */
00258       long lengthA=pos;
00259       long beginB=oggref->begin+pos;
00260       long lengthB=oggref->length-pos;
00261       
00262       /* make a new reference to tail the second piece */
00263       *tail=_fetch_ref(oggref->buffer->ptr.owner);
00264       
00265       (*tail)->buffer=oggref->buffer;
00266       (*tail)->begin=beginB;
00267       (*tail)->length=lengthB;
00268       (*tail)->next=oggref->next;
00269       _ogg_buffer_mark_one(*tail);
00270       if(head && oggref==*head)*head=*tail;    
00271       
00272       /* update the first piece */
00273       oggref->next=0;
00274       oggref->length=lengthA;
00275       
00276     }
00277   }
00278   return ret;
00279 }
00280 
00281 static void ogg_buffer_release_one(ogg_reference *oggref){
00282   ogg_buffer *ob=oggref->buffer;
00283   ogg_buffer_state *bs=ob->ptr.owner;
00284 
00285   ob->refcount--;
00286   if(ob->refcount==0){
00287     bs->outstanding--; /* for the returned buffer */
00288     ob->ptr.next=bs->unused_buffers;
00289     bs->unused_buffers=ob;
00290   }
00291   
00292   bs->outstanding--; /* for the returned reference */
00293   oggref->next=bs->unused_references;
00294   bs->unused_references=oggref;
00295 
00296   _ogg_buffer_destroy(bs); /* lazy cleanup (if needed) */
00297 
00298 }
00299 
00300 /* release the references, decrease the refcounts of buffers to which
00301    they point, release any buffers with a refcount that drops to zero */
00302 static void ogg_buffer_release(ogg_reference *oggref){
00303   while(oggref){
00304     ogg_reference *next=oggref->next;
00305     ogg_buffer_release_one(oggref);
00306     oggref=next;
00307   }
00308 }
00309 
00310 static ogg_reference *ogg_buffer_pretruncate(ogg_reference *oggref,long pos){
00311   /* release preceeding fragments we don't want */
00312   while(oggref && pos>=oggref->length){
00313     ogg_reference *next=oggref->next;
00314     pos-=oggref->length;
00315     ogg_buffer_release_one(oggref);
00316     oggref=next;
00317   }
00318   if (oggref) {
00319     oggref->begin+=pos;
00320     oggref->length-=pos;
00321   }
00322   return oggref;
00323 }
00324 
00325 static ogg_reference *ogg_buffer_walk(ogg_reference *oggref){
00326   if(!oggref)return NULL;
00327   while(oggref->next){
00328     oggref=oggref->next;
00329   }
00330   return(oggref);
00331 }
00332 
00333 /* *head is appended to the front end (head) of *tail; both continue to
00334    be valid pointers, with *tail at the tail and *head at the head */
00335 static ogg_reference *ogg_buffer_cat(ogg_reference *tail, ogg_reference *head){
00336   if(!tail)return head;
00337 
00338   while(tail->next){
00339     tail=tail->next;
00340   }
00341   tail->next=head;
00342   return ogg_buffer_walk(head);
00343 }
00344 
00345 static void _positionB(oggbyte_buffer *b,int pos){
00346   if(pos<b->pos){
00347     /* start at beginning, scan forward */
00348     b->ref=b->baseref;
00349     b->pos=0;
00350     b->end=b->pos+b->ref->length;
00351     b->ptr=b->ref->buffer->data+b->ref->begin;
00352   }
00353 }
00354 
00355 static void _positionF(oggbyte_buffer *b,int pos){
00356   /* scan forward for position */
00357   while(pos>=b->end){
00358     /* just seek forward */
00359     b->pos+=b->ref->length;
00360     b->ref=b->ref->next;
00361     b->end=b->ref->length+b->pos;
00362     b->ptr=b->ref->buffer->data+b->ref->begin;
00363   }
00364 }
00365 
00366 static int oggbyte_init(oggbyte_buffer *b,ogg_reference *oggref){
00367   memset(b,0,sizeof(*b));
00368   if(oggref){
00369     b->ref=b->baseref=oggref;
00370     b->pos=0;
00371     b->end=b->ref->length;
00372     b->ptr=b->ref->buffer->data+b->ref->begin;  
00373     return 0;
00374   }else
00375     return -1;
00376 }
00377 
00378 static void oggbyte_set4(oggbyte_buffer *b,ogg_uint32_t val,int pos){
00379   int i;
00380   _positionB(b,pos);
00381   for(i=0;i<4;i++){
00382     _positionF(b,pos);
00383     b->ptr[pos-b->pos]=val;
00384     val>>=8;
00385     ++pos;
00386   }
00387 }
00388  
00389 static unsigned char oggbyte_read1(oggbyte_buffer *b,int pos){
00390   _positionB(b,pos);
00391   _positionF(b,pos);
00392   return b->ptr[pos-b->pos];
00393 }
00394 
00395 static ogg_uint32_t oggbyte_read4(oggbyte_buffer *b,int pos){
00396   ogg_uint32_t ret;
00397   _positionB(b,pos);
00398   _positionF(b,pos);
00399   ret=b->ptr[pos-b->pos];
00400   _positionF(b,++pos);
00401   ret|=b->ptr[pos-b->pos]<<8;
00402   _positionF(b,++pos);
00403   ret|=b->ptr[pos-b->pos]<<16;
00404   _positionF(b,++pos);
00405   ret|=b->ptr[pos-b->pos]<<24;
00406   return ret;
00407 }
00408 
00409 static ogg_int64_t oggbyte_read8(oggbyte_buffer *b,int pos){
00410   ogg_int64_t ret;
00411   unsigned char t[7];
00412   int i;
00413   _positionB(b,pos);
00414   for(i=0;i<7;i++){
00415     _positionF(b,pos);
00416     t[i]=b->ptr[pos++ -b->pos];
00417   }
00418 
00419   _positionF(b,pos);
00420   ret=b->ptr[pos-b->pos];
00421 
00422   for(i=6;i>=0;--i)
00423     ret= ret<<8 | t[i];
00424 
00425   return ret;
00426 }
00427 
00428 /* Now we get to the actual framing code */
00429 
00430 int ogg_page_version(ogg_page *og){
00431   oggbyte_buffer ob;
00432   oggbyte_init(&ob,og->header);
00433   return oggbyte_read1(&ob,4);
00434 }
00435 
00436 int ogg_page_continued(ogg_page *og){
00437   oggbyte_buffer ob;
00438   oggbyte_init(&ob,og->header);
00439   return oggbyte_read1(&ob,5)&0x01;
00440 }
00441 
00442 int ogg_page_bos(ogg_page *og){
00443   oggbyte_buffer ob;
00444   oggbyte_init(&ob,og->header);
00445   return oggbyte_read1(&ob,5)&0x02;
00446 }
00447 
00448 int ogg_page_eos(ogg_page *og){
00449   oggbyte_buffer ob;
00450   oggbyte_init(&ob,og->header);
00451   return oggbyte_read1(&ob,5)&0x04;
00452 }
00453 
00454 ogg_int64_t ogg_page_granulepos(ogg_page *og){
00455   oggbyte_buffer ob;
00456   oggbyte_init(&ob,og->header);
00457   return oggbyte_read8(&ob,6);
00458 }
00459 
00460 ogg_uint32_t ogg_page_serialno(ogg_page *og){
00461   oggbyte_buffer ob;
00462   oggbyte_init(&ob,og->header);
00463   return oggbyte_read4(&ob,14);
00464 }
00465  
00466 ogg_uint32_t ogg_page_pageno(ogg_page *og){
00467   oggbyte_buffer ob;
00468   oggbyte_init(&ob,og->header);
00469   return oggbyte_read4(&ob,18);
00470 }
00471 
00472 /* returns the number of packets that are completed on this page (if
00473    the leading packet is begun on a previous page, but ends on this
00474    page, it's counted */
00475 
00476 /* NOTE:
00477 If a page consists of a packet begun on a previous page, and a new
00478 packet begun (but not completed) on this page, the return will be:
00479   ogg_page_packets(page)   ==1, 
00480   ogg_page_continued(page) !=0
00481 
00482 If a page happens to be a single packet that was begun on a
00483 previous page, and spans to the next page (in the case of a three or
00484 more page packet), the return will be: 
00485   ogg_page_packets(page)   ==0, 
00486   ogg_page_continued(page) !=0
00487 */
00488 
00489 int ogg_page_packets(ogg_page *og){
00490   int i;
00491   int n;
00492   int count=0;
00493   oggbyte_buffer ob;
00494   oggbyte_init(&ob,og->header);
00495 
00496   n=oggbyte_read1(&ob,26);
00497   for(i=0;i<n;i++)
00498     if(oggbyte_read1(&ob,27+i)<255)count++;
00499   return(count);
00500 }
00501 
00502 /* Static CRC calculation table.  See older code in CVS for dead
00503    run-time initialization code. */
00504 
00505 static ogg_uint32_t const crc_lookup[256]={
00506   0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
00507   0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
00508   0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
00509   0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
00510   0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
00511   0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
00512   0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
00513   0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
00514   0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
00515   0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
00516   0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
00517   0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
00518   0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
00519   0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
00520   0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
00521   0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
00522   0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
00523   0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
00524   0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
00525   0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
00526   0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
00527   0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
00528   0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
00529   0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
00530   0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
00531   0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
00532   0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
00533   0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
00534   0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
00535   0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
00536   0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
00537   0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
00538   0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
00539   0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
00540   0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
00541   0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
00542   0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
00543   0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
00544   0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
00545   0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
00546   0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
00547   0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
00548   0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
00549   0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
00550   0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
00551   0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
00552   0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
00553   0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
00554   0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
00555   0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
00556   0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
00557   0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
00558   0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
00559   0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
00560   0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
00561   0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
00562   0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
00563   0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
00564   0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
00565   0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
00566   0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
00567   0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
00568   0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
00569   0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
00570 
00571 ogg_sync_state *ogg_sync_create(void){
00572   ogg_sync_state *oy=(ogg_sync_state *)_ogg_calloc(1,sizeof(*oy));
00573   memset(oy,0,sizeof(*oy));
00574   oy->bufferpool=ogg_buffer_create();
00575   return oy;
00576 }
00577 
00578 int ogg_sync_destroy(ogg_sync_state *oy){
00579   if(oy){
00580     ogg_sync_reset(oy);
00581     ogg_buffer_destroy(oy->bufferpool);
00582     memset(oy,0,sizeof(*oy));
00583     _ogg_free(oy);
00584   }
00585   return OGG_SUCCESS;
00586 }
00587 
00588 unsigned char *ogg_sync_bufferin(ogg_sync_state *oy, long bytes){
00589   
00590   /* [allocate and] expose a buffer for data submission.
00591 
00592      If there is no head fragment
00593        allocate one and expose it
00594      else
00595        if the current head fragment has sufficient unused space
00596          expose it
00597        else
00598          if the current head fragment is unused
00599            resize and expose it
00600          else
00601            allocate new fragment and expose it
00602   */
00603 
00604   /* base case; fifo uninitialized */
00605   if(!oy->fifo_head){
00606     oy->fifo_head=oy->fifo_tail=ogg_buffer_alloc(oy->bufferpool,bytes);
00607     return oy->fifo_head->buffer->data;
00608   }
00609   
00610   /* space left in current fragment case */
00611   if(oy->fifo_head->buffer->size-
00612      oy->fifo_head->length-
00613      oy->fifo_head->begin >= bytes)
00614     return oy->fifo_head->buffer->data+
00615       oy->fifo_head->length+oy->fifo_head->begin;
00616 
00617   /* current fragment is unused, but too small */
00618   if(!oy->fifo_head->length){
00619     ogg_buffer_realloc(oy->fifo_head,bytes);
00620     return oy->fifo_head->buffer->data+oy->fifo_head->begin;
00621   }
00622   
00623   /* current fragment used/full; get new fragment */
00624   {
00625     ogg_reference *newref=ogg_buffer_alloc(oy->bufferpool,bytes);
00626     oy->fifo_head->next=newref;
00627     oy->fifo_head=newref;
00628   }
00629   return oy->fifo_head->buffer->data;
00630 }
00631 
00632 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ 
00633   if(!oy->fifo_head)return OGG_EINVAL;
00634   if(oy->fifo_head->buffer->size-oy->fifo_head->length-oy->fifo_head->begin < 
00635      bytes)return OGG_EINVAL;
00636   oy->fifo_head->length+=bytes;
00637   oy->fifo_fill+=bytes;
00638   return OGG_SUCCESS;
00639 }
00640 
00641 static ogg_uint32_t _checksum(ogg_reference *oggref, int bytes){
00642   ogg_uint32_t crc_reg=0;
00643   int j,post;
00644 
00645   while(oggref){
00646     unsigned char *data=oggref->buffer->data+oggref->begin;
00647     post=(bytes<oggref->length?bytes:oggref->length);
00648     for(j=0;j<post;++j)
00649       crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^data[j]];
00650     bytes-=j;
00651     oggref=oggref->next;
00652   }
00653 
00654   return crc_reg;
00655 }
00656 
00657 
00658 /* sync the stream.  This is meant to be useful for finding page
00659    boundaries.
00660 
00661    return values for this:
00662   -n) skipped n bytes
00663    0) page not ready; more data (no bytes skipped)
00664    n) page synced at current location; page length n bytes
00665    
00666 */
00667 
00668 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
00669   oggbyte_buffer page;
00670   long           bytes,ret=0;
00671 
00672   ogg_page_release(og);
00673 
00674   bytes=oy->fifo_fill;
00675   oggbyte_init(&page,oy->fifo_tail);
00676 
00677   if(oy->headerbytes==0){
00678     if(bytes<27)goto sync_out; /* not enough for even a minimal header */
00679     
00680     /* verify capture pattern */
00681     if(oggbyte_read1(&page,0)!=(int)'O' ||
00682        oggbyte_read1(&page,1)!=(int)'g' ||
00683        oggbyte_read1(&page,2)!=(int)'g' ||
00684        oggbyte_read1(&page,3)!=(int)'S'    ) goto sync_fail;
00685 
00686     oy->headerbytes=oggbyte_read1(&page,26)+27;
00687   }
00688   if(bytes<oy->headerbytes)goto sync_out; /* not enough for header +
00689                                              seg table */
00690   if(oy->bodybytes==0){
00691     int i;
00692     /* count up body length in the segment table */
00693     for(i=0;i<oy->headerbytes-27;i++)
00694       oy->bodybytes+=oggbyte_read1(&page,27+i);
00695   }
00696   
00697   if(oy->bodybytes+oy->headerbytes>bytes)goto sync_out;
00698 
00699   /* we have what appears to be a complete page; last test: verify
00700      checksum */
00701   {
00702     ogg_uint32_t chksum=oggbyte_read4(&page,22);
00703     oggbyte_set4(&page,0,22);
00704 
00705     /* Compare checksums; memory continues to be common access */
00706     if(chksum!=_checksum(oy->fifo_tail,oy->bodybytes+oy->headerbytes)){
00707       
00708       /* D'oh.  Mismatch! Corrupt page (or miscapture and not a page
00709          at all). replace the computed checksum with the one actually
00710          read in; remember all the memory is common access */
00711       
00712       oggbyte_set4(&page,chksum,22);
00713       goto sync_fail;
00714     }
00715     oggbyte_set4(&page,chksum,22);
00716   }
00717 
00718   /* We have a page.  Set up page return. */
00719   if(og){
00720     /* set up page output */
00721     og->header=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->headerbytes);
00722     og->header_len=oy->headerbytes;
00723     og->body=ogg_buffer_split(&oy->fifo_tail,&oy->fifo_head,oy->bodybytes);
00724     og->body_len=oy->bodybytes;
00725   }else{
00726     /* simply advance */
00727     oy->fifo_tail=
00728       ogg_buffer_pretruncate(oy->fifo_tail,oy->headerbytes+oy->bodybytes);
00729     if(!oy->fifo_tail)oy->fifo_head=0;
00730   }
00731   
00732   ret=oy->headerbytes+oy->bodybytes;
00733   oy->unsynced=0;
00734   oy->headerbytes=0;
00735   oy->bodybytes=0;
00736   oy->fifo_fill-=ret;
00737 
00738   return ret;
00739   
00740  sync_fail:
00741 
00742   oy->headerbytes=0;
00743   oy->bodybytes=0;
00744   oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,1);
00745   ret--;
00746   
00747   /* search forward through fragments for possible capture */
00748   while(oy->fifo_tail){
00749     /* invariant: fifo_cursor points to a position in fifo_tail */
00750     unsigned char *now=oy->fifo_tail->buffer->data+oy->fifo_tail->begin;
00751     unsigned char *next=(unsigned char *)memchr(now, 'O', oy->fifo_tail->length);
00752       
00753     if(next){
00754       /* possible capture in this segment */
00755       long bytes=next-now;
00756       oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
00757       ret-=bytes;
00758       break;
00759     }else{
00760       /* no capture.  advance to next segment */
00761       long bytes=oy->fifo_tail->length;
00762       ret-=bytes;
00763       oy->fifo_tail=ogg_buffer_pretruncate(oy->fifo_tail,bytes);
00764     }
00765   }
00766   if(!oy->fifo_tail)oy->fifo_head=0;
00767   oy->fifo_fill+=ret;
00768 
00769  sync_out:
00770   return ret;
00771 }
00772 
00773 /* sync the stream and get a page.  Keep trying until we find a page.
00774    Supress 'sync errors' after reporting the first.
00775 
00776    return values:
00777    OGG_HOLE) recapture (hole in data)
00778           0) need more data
00779           1) page returned
00780 
00781    Returns pointers into buffered data; invalidated by next call to
00782    _stream, _clear, _init, or _buffer */
00783 
00784 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
00785 
00786   /* all we need to do is verify a page at the head of the stream
00787      buffer.  If it doesn't verify, we look for the next potential
00788      frame */
00789 
00790   while(1){
00791     long ret=ogg_sync_pageseek(oy,og);
00792     if(ret>0){
00793       /* have a page */
00794       return 1;
00795     }
00796     if(ret==0){
00797       /* need more data */
00798       return 0;
00799     }
00800     
00801     /* head did not start a synced page... skipped some bytes */
00802     if(!oy->unsynced){
00803       oy->unsynced=1;
00804       return OGG_HOLE;
00805     }
00806 
00807     /* loop. keep looking */
00808 
00809   }
00810 }
00811 
00812 /* clear things to an initial state.  Good to call, eg, before seeking */
00813 int ogg_sync_reset(ogg_sync_state *oy){
00814   ogg_buffer_release(oy->fifo_tail);
00815   oy->fifo_tail=0;
00816   oy->fifo_head=0;
00817   oy->fifo_fill=0;
00818 
00819   oy->unsynced=0;
00820   oy->headerbytes=0;
00821   oy->bodybytes=0;
00822   return OGG_SUCCESS;
00823 }
00824 
00825 ogg_stream_state *ogg_stream_create(int serialno){
00826   ogg_stream_state *os=(ogg_stream_state *)_ogg_calloc(1,sizeof(*os));
00827   os->serialno=serialno;
00828   os->pageno=-1;
00829   return os;
00830 } 
00831 
00832 int ogg_stream_destroy(ogg_stream_state *os){
00833   if(os){
00834     ogg_buffer_release(os->header_tail);
00835     ogg_buffer_release(os->body_tail);
00836     memset(os,0,sizeof(*os));    
00837     _ogg_free(os);
00838   }
00839   return OGG_SUCCESS;
00840 } 
00841 
00842 
00843 #define FINFLAG 0x80000000UL
00844 #define FINMASK 0x7fffffffUL
00845 
00846 static void _next_lace(oggbyte_buffer *ob,ogg_stream_state *os){
00847   /* search ahead one lace */
00848   os->body_fill_next=0;
00849   while(os->laceptr<os->lacing_fill){
00850     int val=oggbyte_read1(ob,27+os->laceptr++);
00851     os->body_fill_next+=val;
00852     if(val<255){
00853       os->body_fill_next|=FINFLAG;
00854       os->clearflag=1;
00855       break;
00856     }
00857   }
00858 }
00859 
00860 static void _span_queued_page(ogg_stream_state *os){ 
00861   while( !(os->body_fill&FINFLAG) ){
00862     
00863     if(!os->header_tail)break;
00864 
00865     /* first flush out preceeding page header (if any).  Body is
00866        flushed as it's consumed, so that's not done here. */
00867 
00868     if(os->lacing_fill>=0)
00869       os->header_tail=ogg_buffer_pretruncate(os->header_tail,
00870                                              os->lacing_fill+27);
00871     os->lacing_fill=0;
00872     os->laceptr=0;
00873     os->clearflag=0;
00874 
00875     if(!os->header_tail){
00876       os->header_head=0;
00877       break;
00878     }else{
00879       
00880       /* process/prepare next page, if any */
00881 
00882       long pageno;
00883       oggbyte_buffer ob;
00884       ogg_page og;               /* only for parsing header values */
00885       og.header=os->header_tail; /* only for parsing header values */
00886       pageno=ogg_page_pageno(&og);
00887 
00888       oggbyte_init(&ob,os->header_tail);
00889       os->lacing_fill=oggbyte_read1(&ob,26);
00890       
00891       /* are we in sequence? */
00892       if(pageno!=os->pageno){
00893         if(os->pageno==-1) /* indicates seek or reset */
00894           os->holeflag=1;  /* set for internal use */
00895         else
00896           os->holeflag=2;  /* set for external reporting */
00897 
00898         os->body_tail=ogg_buffer_pretruncate(os->body_tail,
00899                                              os->body_fill);
00900         if(os->body_tail==0)os->body_head=0;
00901         os->body_fill=0;
00902 
00903       }
00904     
00905       if(ogg_page_continued(&og)){
00906         if(os->body_fill==0){
00907           /* continued packet, but no preceeding data to continue */
00908           /* dump the first partial packet on the page */
00909           _next_lace(&ob,os);   
00910           os->body_tail=
00911             ogg_buffer_pretruncate(os->body_tail,os->body_fill_next&FINMASK);
00912           if(os->body_tail==0)os->body_head=0;
00913           /* set span flag */
00914           if(!os->spanflag && !os->holeflag)os->spanflag=2;
00915         }
00916       }else{
00917         if(os->body_fill>0){
00918           /* preceeding data to continue, but not a continued page */
00919           /* dump body_fill */
00920           os->body_tail=ogg_buffer_pretruncate(os->body_tail,
00921                                                os->body_fill);
00922           if(os->body_tail==0)os->body_head=0;
00923           os->body_fill=0;
00924 
00925           /* set espan flag */
00926           if(!os->spanflag && !os->holeflag)os->spanflag=2;
00927         }
00928       }
00929 
00930       if(os->laceptr<os->lacing_fill){
00931         os->granulepos=ogg_page_granulepos(&og);
00932 
00933         /* get current packet size & flag */
00934         _next_lace(&ob,os);
00935         os->body_fill+=os->body_fill_next; /* addition handles the flag fine;
00936                                              unsigned on purpose */
00937         /* ...and next packet size & flag */
00938         _next_lace(&ob,os);
00939 
00940       }
00941       
00942       os->pageno=pageno+1;
00943       os->e_o_s=ogg_page_eos(&og);
00944       os->b_o_s=ogg_page_bos(&og);
00945     
00946     }
00947   }
00948 }
00949 
00950 /* add the incoming page to the stream state; we decompose the page
00951    into packet segments here as well. */
00952 
00953 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
00954 
00955   int serialno=ogg_page_serialno(og);
00956   int version=ogg_page_version(og);
00957 
00958   /* check the serial number */
00959   if(serialno!=os->serialno){
00960     ogg_page_release(og);
00961     return OGG_ESERIAL;
00962   }
00963   if(version>0){
00964     ogg_page_release(og);
00965     return OGG_EVERSION;
00966   }
00967 
00968   /* add to fifos */
00969   if(!os->body_tail){
00970     os->body_tail=og->body;
00971     os->body_head=ogg_buffer_walk(og->body);
00972   }else{
00973     os->body_head=ogg_buffer_cat(os->body_head,og->body);
00974   }
00975   if(!os->header_tail){
00976     os->header_tail=og->header;
00977     os->header_head=ogg_buffer_walk(og->header);
00978     os->lacing_fill=-27;
00979   }else{
00980     os->header_head=ogg_buffer_cat(os->header_head,og->header);
00981   }
00982 
00983   memset(og,0,sizeof(*og));
00984   return OGG_SUCCESS;
00985 }
00986 
00987 int ogg_stream_reset(ogg_stream_state *os){
00988 
00989   ogg_buffer_release(os->header_tail);
00990   ogg_buffer_release(os->body_tail);
00991   os->header_tail=os->header_head=0;
00992   os->body_tail=os->body_head=0;
00993 
00994   os->e_o_s=0;
00995   os->b_o_s=0;
00996   os->pageno=-1;
00997   os->packetno=0;
00998   os->granulepos=0;
00999 
01000   os->body_fill=0;
01001   os->lacing_fill=0;
01002 
01003   os->holeflag=0;
01004   os->spanflag=0;
01005   os->clearflag=0;
01006   os->laceptr=0;
01007   os->body_fill_next=0;
01008 
01009   return OGG_SUCCESS;
01010 }
01011 
01012 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
01013   ogg_stream_reset(os);
01014   os->serialno=serialno;
01015   return OGG_SUCCESS;
01016 }
01017 
01018 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
01019 
01020   ogg_packet_release(op);
01021   _span_queued_page(os);
01022 
01023   if(os->holeflag){
01024     int temp=os->holeflag;
01025     if(os->clearflag)
01026       os->holeflag=0;
01027     else
01028       os->holeflag=1;
01029     if(temp==2){
01030       os->packetno++;
01031       return OGG_HOLE;
01032     }
01033   }
01034   if(os->spanflag){
01035     int temp=os->spanflag;
01036     if(os->clearflag)
01037       os->spanflag=0;
01038     else
01039       os->spanflag=1;
01040     if(temp==2){
01041       os->packetno++;
01042       return OGG_SPAN;
01043     }
01044   }
01045 
01046   if(!(os->body_fill&FINFLAG)) return 0;
01047   if(!op && !adv)return 1; /* just using peek as an inexpensive way
01048                                to ask if there's a whole packet
01049                                waiting */
01050   if(op){
01051     op->b_o_s=os->b_o_s;
01052     if(os->e_o_s && os->body_fill_next==0)
01053       op->e_o_s=os->e_o_s;
01054     else
01055       op->e_o_s=0;
01056     if( (os->body_fill&FINFLAG) && !(os->body_fill_next&FINFLAG) )
01057       op->granulepos=os->granulepos;
01058     else
01059       op->granulepos=-1;
01060     op->packetno=os->packetno;
01061   }
01062 
01063   if(adv){
01064     oggbyte_buffer ob;
01065     oggbyte_init(&ob,os->header_tail);
01066 
01067     /* split the body contents off */
01068     if(op){
01069       op->packet=ogg_buffer_split(&os->body_tail,&os->body_head,
01070                                   os->body_fill&FINMASK);
01071       op->bytes=os->body_fill&FINMASK;
01072     }else{
01073       os->body_tail=ogg_buffer_pretruncate(os->body_tail,
01074                                            os->body_fill&FINMASK);
01075       if(os->body_tail==0)os->body_head=0;
01076     }
01077 
01078     /* update lacing pointers */
01079     os->body_fill=os->body_fill_next;
01080     _next_lace(&ob,os);
01081   }else{
01082     if(op){
01083       op->packet=ogg_buffer_sub(os->body_tail,0,os->body_fill&FINMASK);
01084       op->bytes=os->body_fill&FINMASK;
01085     }
01086   }
01087   
01088   if(adv){
01089     os->packetno++;
01090     os->b_o_s=0;
01091   }
01092 
01093   return 1;
01094 }
01095 
01096 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
01097   return _packetout(os,op,1);
01098 }
01099 
01100 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
01101   return _packetout(os,op,0);
01102 }
01103 
01104 int ogg_packet_release(ogg_packet *op) {
01105   if(op){
01106     ogg_buffer_release(op->packet);
01107     memset(op, 0, sizeof(*op));
01108   }
01109   return OGG_SUCCESS;
01110 }
01111 
01112 int ogg_page_release(ogg_page *og) {
01113   if(og){
01114     ogg_buffer_release(og->header);
01115     ogg_buffer_release(og->body);
01116     memset(og, 0, sizeof(*og));
01117   }
01118   return OGG_SUCCESS;
01119 }
01120 
01121 void ogg_page_dup(ogg_page *dup,ogg_page *orig){
01122   dup->header_len=orig->header_len;
01123   dup->body_len=orig->body_len;
01124   dup->header=ogg_buffer_dup(orig->header);
01125   dup->body=ogg_buffer_dup(orig->body);
01126 }
01127 

Generated by  doxygen 1.6.2