stream/http: Add support for login/password in http_proxy env variable
[mplayer/glamo.git] / tremor / framing.c
blob17c28b11116ae4ffbdeeb4e17d394d0ef5a1db99
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
10 * *
11 ********************************************************************
13 function: code raw [Vorbis] packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
15 last mod: $Id$
17 note: The CRC code is directly derived from public domain code by
18 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
19 for details.
21 ********************************************************************/
23 #include <stdlib.h>
24 #include <string.h>
25 #include "ogg.h"
27 /* A complete description of Ogg framing exists in docs/framing.html */
29 int ogg_page_version(ogg_page *og){
30 return((int)(og->header[4]));
33 int ogg_page_continued(ogg_page *og){
34 return((int)(og->header[5]&0x01));
37 int ogg_page_bos(ogg_page *og){
38 return((int)(og->header[5]&0x02));
41 int ogg_page_eos(ogg_page *og){
42 return((int)(og->header[5]&0x04));
45 ogg_int64_t ogg_page_granulepos(ogg_page *og){
46 unsigned char *page=og->header;
47 ogg_int64_t granulepos=page[13]&(0xff);
48 granulepos= (granulepos<<8)|(page[12]&0xff);
49 granulepos= (granulepos<<8)|(page[11]&0xff);
50 granulepos= (granulepos<<8)|(page[10]&0xff);
51 granulepos= (granulepos<<8)|(page[9]&0xff);
52 granulepos= (granulepos<<8)|(page[8]&0xff);
53 granulepos= (granulepos<<8)|(page[7]&0xff);
54 granulepos= (granulepos<<8)|(page[6]&0xff);
55 return(granulepos);
58 int ogg_page_serialno(ogg_page *og){
59 return(og->header[14] |
60 (og->header[15]<<8) |
61 (og->header[16]<<16) |
62 (og->header[17]<<24));
65 long ogg_page_pageno(ogg_page *og){
66 return(og->header[18] |
67 (og->header[19]<<8) |
68 (og->header[20]<<16) |
69 (og->header[21]<<24));
74 /* returns the number of packets that are completed on this page (if
75 the leading packet is begun on a previous page, but ends on this
76 page, it's counted */
78 /* NOTE:
79 If a page consists of a packet begun on a previous page, and a new
80 packet begun (but not completed) on this page, the return will be:
81 ogg_page_packets(page) ==1,
82 ogg_page_continued(page) !=0
84 If a page happens to be a single packet that was begun on a
85 previous page, and spans to the next page (in the case of a three or
86 more page packet), the return will be:
87 ogg_page_packets(page) ==0,
88 ogg_page_continued(page) !=0
91 int ogg_page_packets(ogg_page *og){
92 int i,n=og->header[26],count=0;
93 for(i=0;i<n;i++)
94 if(og->header[27+i]<255)count++;
95 return(count);
99 #if 0
100 /* helper to initialize lookup for direct-table CRC (illustrative; we
101 use the static init below) */
103 static ogg_uint32_t _ogg_crc_entry(unsigned long index){
104 int i;
105 unsigned long r;
107 r = index << 24;
108 for (i=0; i<8; i++)
109 if (r & 0x80000000UL)
110 r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
111 polynomial, although we use an
112 unreflected alg and an init/final
113 of 0, not 0xffffffff */
114 else
115 r<<=1;
116 return (r & 0xffffffffUL);
118 #endif
120 static const ogg_uint32_t crc_lookup[256]={
121 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
122 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
123 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
124 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
125 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
126 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
127 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
128 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
129 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
130 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
131 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
132 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
133 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
134 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
135 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
136 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
137 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
138 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
139 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
140 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
141 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
142 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
143 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
144 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
145 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
146 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
147 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
148 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
149 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
150 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
151 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
152 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
153 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
154 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
155 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
156 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
157 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
158 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
159 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
160 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
161 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
162 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
163 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
164 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
165 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
166 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
167 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
168 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
169 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
170 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
171 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
172 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
173 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
174 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
175 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
176 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
177 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
178 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
179 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
180 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
181 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
182 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
183 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
184 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
186 /* init the encode/decode logical stream state */
188 int ogg_stream_init(ogg_stream_state *os,int serialno){
189 if(os){
190 memset(os,0,sizeof(*os));
191 os->body_storage=16*1024;
192 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
194 os->lacing_storage=1024;
195 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
196 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
198 os->serialno=serialno;
200 return(0);
202 return(-1);
205 /* _clear does not free os, only the non-flat storage within */
206 int ogg_stream_clear(ogg_stream_state *os){
207 if(os){
208 if(os->body_data)_ogg_free(os->body_data);
209 if(os->lacing_vals)_ogg_free(os->lacing_vals);
210 if(os->granule_vals)_ogg_free(os->granule_vals);
212 memset(os,0,sizeof(*os));
214 return(0);
217 int ogg_stream_destroy(ogg_stream_state *os){
218 if(os){
219 ogg_stream_clear(os);
220 _ogg_free(os);
222 return(0);
225 /* Helpers for ogg_stream_encode; this keeps the structure and
226 what's happening fairly clear */
228 static void _os_body_expand(ogg_stream_state *os,int needed){
229 if(os->body_storage<=os->body_fill+needed){
230 os->body_storage+=(needed+1024);
231 os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
235 static void _os_lacing_expand(ogg_stream_state *os,int needed){
236 if(os->lacing_storage<=os->lacing_fill+needed){
237 os->lacing_storage+=(needed+32);
238 os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
239 os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
243 /* checksum the page */
244 /* Direct table CRC; note that this will be faster in the future if we
245 perform the checksum silmultaneously with other copies */
247 void ogg_page_checksum_set(ogg_page *og){
248 if(og){
249 ogg_uint32_t crc_reg=0;
250 int i;
252 /* safety; needed for API behavior, but not framing code */
253 og->header[22]=0;
254 og->header[23]=0;
255 og->header[24]=0;
256 og->header[25]=0;
258 for(i=0;i<og->header_len;i++)
259 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
260 for(i=0;i<og->body_len;i++)
261 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
263 og->header[22]=(unsigned char)(crc_reg&0xff);
264 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
265 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
266 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
270 /* submit data to the internal buffer of the framing engine */
271 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
272 int lacing_vals=op->bytes/255+1,i;
274 if(os->body_returned){
275 /* advance packet data according to the body_returned pointer. We
276 had to keep it around to return a pointer into the buffer last
277 call */
279 os->body_fill-=os->body_returned;
280 if(os->body_fill)
281 memmove(os->body_data,os->body_data+os->body_returned,
282 os->body_fill);
283 os->body_returned=0;
286 /* make sure we have the buffer storage */
287 _os_body_expand(os,op->bytes);
288 _os_lacing_expand(os,lacing_vals);
290 /* Copy in the submitted packet. Yes, the copy is a waste; this is
291 the liability of overly clean abstraction for the time being. It
292 will actually be fairly easy to eliminate the extra copy in the
293 future */
295 memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
296 os->body_fill+=op->bytes;
298 /* Store lacing vals for this packet */
299 for(i=0;i<lacing_vals-1;i++){
300 os->lacing_vals[os->lacing_fill+i]=255;
301 os->granule_vals[os->lacing_fill+i]=os->granulepos;
303 os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
304 os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
306 /* flag the first segment as the beginning of the packet */
307 os->lacing_vals[os->lacing_fill]|= 0x100;
309 os->lacing_fill+=lacing_vals;
311 /* for the sake of completeness */
312 os->packetno++;
314 if(op->e_o_s)os->e_o_s=1;
316 return(0);
319 /* This will flush remaining packets into a page (returning nonzero),
320 even if there is not enough data to trigger a flush normally
321 (undersized page). If there are no packets or partial packets to
322 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
323 try to flush a normal sized page like ogg_stream_pageout; a call to
324 ogg_stream_flush does not guarantee that all packets have flushed.
325 Only a return value of 0 from ogg_stream_flush indicates all packet
326 data is flushed into pages.
328 since ogg_stream_flush will flush the last page in a stream even if
329 it's undersized, you almost certainly want to use ogg_stream_pageout
330 (and *not* ogg_stream_flush) unless you specifically need to flush
331 an page regardless of size in the middle of a stream. */
333 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
334 int i;
335 int vals=0;
336 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
337 int bytes=0;
338 long acc=0;
339 ogg_int64_t granule_pos=os->granule_vals[0];
341 if(maxvals==0)return(0);
343 /* construct a page */
344 /* decide how many segments to include */
346 /* If this is the initial header case, the first page must only include
347 the initial header packet */
348 if(os->b_o_s==0){ /* 'initial header page' case */
349 granule_pos=0;
350 for(vals=0;vals<maxvals;vals++){
351 if((os->lacing_vals[vals]&0x0ff)<255){
352 vals++;
353 break;
356 }else{
357 for(vals=0;vals<maxvals;vals++){
358 if(acc>4096)break;
359 acc+=os->lacing_vals[vals]&0x0ff;
360 granule_pos=os->granule_vals[vals];
364 /* construct the header in temp storage */
365 memcpy(os->header,"OggS",4);
367 /* stream structure version */
368 os->header[4]=0x00;
370 /* continued packet flag? */
371 os->header[5]=0x00;
372 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
373 /* first page flag? */
374 if(os->b_o_s==0)os->header[5]|=0x02;
375 /* last page flag? */
376 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
377 os->b_o_s=1;
379 /* 64 bits of PCM position */
380 for(i=6;i<14;i++){
381 os->header[i]=(unsigned char)(granule_pos&0xff);
382 granule_pos>>=8;
385 /* 32 bits of stream serial number */
387 long serialno=os->serialno;
388 for(i=14;i<18;i++){
389 os->header[i]=(unsigned char)(serialno&0xff);
390 serialno>>=8;
394 /* 32 bits of page counter (we have both counter and page header
395 because this val can roll over) */
396 if(os->pageno==-1)os->pageno=0; /* because someone called
397 stream_reset; this would be a
398 strange thing to do in an
399 encode stream, but it has
400 plausible uses */
402 long pageno=os->pageno++;
403 for(i=18;i<22;i++){
404 os->header[i]=(unsigned char)(pageno&0xff);
405 pageno>>=8;
409 /* zero for computation; filled in later */
410 os->header[22]=0;
411 os->header[23]=0;
412 os->header[24]=0;
413 os->header[25]=0;
415 /* segment table */
416 os->header[26]=(unsigned char)(vals&0xff);
417 for(i=0;i<vals;i++)
418 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
420 /* set pointers in the ogg_page struct */
421 og->header=os->header;
422 og->header_len=os->header_fill=vals+27;
423 og->body=os->body_data+os->body_returned;
424 og->body_len=bytes;
426 /* advance the lacing data and set the body_returned pointer */
428 os->lacing_fill-=vals;
429 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
430 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
431 os->body_returned+=bytes;
433 /* calculate the checksum */
435 ogg_page_checksum_set(og);
437 /* done */
438 return(1);
442 /* This constructs pages from buffered packet segments. The pointers
443 returned are to static buffers; do not free. The returned buffers are
444 good only until the next call (using the same ogg_stream_state) */
446 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
448 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
449 os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
450 os->lacing_fill>=255 || /* 'segment table full' case */
451 (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
453 return(ogg_stream_flush(os,og));
456 /* not enough data to construct a page and not end of stream */
457 return(0);
460 int ogg_stream_eos(ogg_stream_state *os){
461 return os->e_o_s;
464 /* DECODING PRIMITIVES: packet streaming layer **********************/
466 /* This has two layers to place more of the multi-serialno and paging
467 control in the application's hands. First, we expose a data buffer
468 using ogg_sync_buffer(). The app either copies into the
469 buffer, or passes it directly to read(), etc. We then call
470 ogg_sync_wrote() to tell how many bytes we just added.
472 Pages are returned (pointers into the buffer in ogg_sync_state)
473 by ogg_sync_pageout(). The page is then submitted to
474 ogg_stream_pagein() along with the appropriate
475 ogg_stream_state* (ie, matching serialno). We then get raw
476 packets out calling ogg_stream_packetout() with a
477 ogg_stream_state. See the 'frame-prog.txt' docs for details and
478 example code. */
480 /* initialize the struct to a known state */
481 int ogg_sync_init(ogg_sync_state *oy){
482 if(oy){
483 memset(oy,0,sizeof(*oy));
485 return(0);
488 /* clear non-flat storage within */
489 int ogg_sync_clear(ogg_sync_state *oy){
490 if(oy){
491 if(oy->data)_ogg_free(oy->data);
492 ogg_sync_init(oy);
494 return(0);
497 int ogg_sync_destroy(ogg_sync_state *oy){
498 if(oy){
499 ogg_sync_clear(oy);
500 _ogg_free(oy);
502 return(0);
505 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
507 /* first, clear out any space that has been previously returned */
508 if(oy->returned){
509 oy->fill-=oy->returned;
510 if(oy->fill>0)
511 memmove(oy->data,oy->data+oy->returned,oy->fill);
512 oy->returned=0;
515 if(size>oy->storage-oy->fill){
516 /* We need to extend the internal buffer */
517 long newsize=size+oy->fill+4096; /* an extra page to be nice */
519 if(oy->data)
520 oy->data=_ogg_realloc(oy->data,newsize);
521 else
522 oy->data=_ogg_malloc(newsize);
523 oy->storage=newsize;
526 /* expose a segment at least as large as requested at the fill mark */
527 return((char *)oy->data+oy->fill);
530 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
531 if(oy->fill+bytes>oy->storage)return(-1);
532 oy->fill+=bytes;
533 return(0);
536 /* sync the stream. This is meant to be useful for finding page
537 boundaries.
539 return values for this:
540 -n) skipped n bytes
541 0) page not ready; more data (no bytes skipped)
542 n) page synced at current location; page length n bytes
546 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
547 unsigned char *page=oy->data+oy->returned;
548 unsigned char *next;
549 long bytes=oy->fill-oy->returned;
551 if(oy->headerbytes==0){
552 int headerbytes,i;
553 if(bytes<27)return(0); /* not enough for a header */
555 /* verify capture pattern */
556 if(memcmp(page,"OggS",4))goto sync_fail;
558 headerbytes=page[26]+27;
559 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
561 /* count up body length in the segment table */
563 for(i=0;i<page[26];i++)
564 oy->bodybytes+=page[27+i];
565 oy->headerbytes=headerbytes;
568 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
570 /* The whole test page is buffered. Verify the checksum */
572 /* Grab the checksum bytes, set the header field to zero */
573 char chksum[4];
574 ogg_page log;
576 memcpy(chksum,page+22,4);
577 memset(page+22,0,4);
579 /* set up a temp page struct and recompute the checksum */
580 log.header=page;
581 log.header_len=oy->headerbytes;
582 log.body=page+oy->headerbytes;
583 log.body_len=oy->bodybytes;
584 ogg_page_checksum_set(&log);
586 /* Compare */
587 if(memcmp(chksum,page+22,4)){
588 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
589 at all) */
590 /* replace the computed checksum with the one actually read in */
591 memcpy(page+22,chksum,4);
593 /* Bad checksum. Lose sync */
594 goto sync_fail;
598 /* yes, have a whole page all ready to go */
600 unsigned char *page=oy->data+oy->returned;
601 long bytes;
603 if(og){
604 og->header=page;
605 og->header_len=oy->headerbytes;
606 og->body=page+oy->headerbytes;
607 og->body_len=oy->bodybytes;
610 oy->unsynced=0;
611 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
612 oy->headerbytes=0;
613 oy->bodybytes=0;
614 return(bytes);
617 sync_fail:
619 oy->headerbytes=0;
620 oy->bodybytes=0;
622 /* search for possible capture */
623 next=memchr(page+1,'O',bytes-1);
624 if(!next)
625 next=oy->data+oy->fill;
627 oy->returned=next-oy->data;
628 return(-(next-page));
631 /* sync the stream and get a page. Keep trying until we find a page.
632 Suppress 'sync errors' after reporting the first.
634 return values:
635 -1) recapture (hole in data)
636 0) need more data
637 1) page returned
639 Returns pointers into buffered data; invalidated by next call to
640 _stream, _clear, _init, or _buffer */
642 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
644 /* all we need to do is verify a page at the head of the stream
645 buffer. If it doesn't verify, we look for the next potential
646 frame */
648 for(;;){
649 long ret=ogg_sync_pageseek(oy,og);
650 if(ret>0){
651 /* have a page */
652 return(1);
654 if(ret==0){
655 /* need more data */
656 return(0);
659 /* head did not start a synced page... skipped some bytes */
660 if(!oy->unsynced){
661 oy->unsynced=1;
662 return(-1);
665 /* loop. keep looking */
670 /* add the incoming page to the stream state; we decompose the page
671 into packet segments here as well. */
673 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
674 unsigned char *header=og->header;
675 unsigned char *body=og->body;
676 long bodysize=og->body_len;
677 int segptr=0;
679 int version=ogg_page_version(og);
680 int continued=ogg_page_continued(og);
681 int bos=ogg_page_bos(og);
682 int eos=ogg_page_eos(og);
683 ogg_int64_t granulepos=ogg_page_granulepos(og);
684 int serialno=ogg_page_serialno(og);
685 long pageno=ogg_page_pageno(og);
686 int segments=header[26];
688 /* clean up 'returned data' */
690 long lr=os->lacing_returned;
691 long br=os->body_returned;
693 /* body data */
694 if(br){
695 os->body_fill-=br;
696 if(os->body_fill)
697 memmove(os->body_data,os->body_data+br,os->body_fill);
698 os->body_returned=0;
701 if(lr){
702 /* segment table */
703 if(os->lacing_fill-lr){
704 memmove(os->lacing_vals,os->lacing_vals+lr,
705 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
706 memmove(os->granule_vals,os->granule_vals+lr,
707 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
709 os->lacing_fill-=lr;
710 os->lacing_packet-=lr;
711 os->lacing_returned=0;
715 /* check the serial number */
716 if(serialno!=os->serialno)return(-1);
717 if(version>0)return(-1);
719 _os_lacing_expand(os,segments+1);
721 /* are we in sequence? */
722 if(pageno!=os->pageno){
723 int i;
725 /* unroll previous partial packet (if any) */
726 for(i=os->lacing_packet;i<os->lacing_fill;i++)
727 os->body_fill-=os->lacing_vals[i]&0xff;
728 os->lacing_fill=os->lacing_packet;
730 /* make a note of dropped data in segment table */
731 if(os->pageno!=-1){
732 os->lacing_vals[os->lacing_fill++]=0x400;
733 os->lacing_packet++;
737 /* are we a 'continued packet' page? If so, we may need to skip
738 some segments */
739 if(continued){
740 if(os->lacing_fill<1 ||
741 os->lacing_vals[os->lacing_fill-1]==0x400){
742 bos=0;
743 for(;segptr<segments;segptr++){
744 int val=header[27+segptr];
745 body+=val;
746 bodysize-=val;
747 if(val<255){
748 segptr++;
749 break;
755 if(bodysize){
756 _os_body_expand(os,bodysize);
757 memcpy(os->body_data+os->body_fill,body,bodysize);
758 os->body_fill+=bodysize;
762 int saved=-1;
763 while(segptr<segments){
764 int val=header[27+segptr];
765 os->lacing_vals[os->lacing_fill]=val;
766 os->granule_vals[os->lacing_fill]=-1;
768 if(bos){
769 os->lacing_vals[os->lacing_fill]|=0x100;
770 bos=0;
773 if(val<255)saved=os->lacing_fill;
775 os->lacing_fill++;
776 segptr++;
778 if(val<255)os->lacing_packet=os->lacing_fill;
781 /* set the granulepos on the last granuleval of the last full packet */
782 if(saved!=-1){
783 os->granule_vals[saved]=granulepos;
788 if(eos){
789 os->e_o_s=1;
790 if(os->lacing_fill>0)
791 os->lacing_vals[os->lacing_fill-1]|=0x200;
794 os->pageno=pageno+1;
796 return(0);
799 /* clear things to an initial state. Good to call, eg, before seeking */
800 int ogg_sync_reset(ogg_sync_state *oy){
801 oy->fill=0;
802 oy->returned=0;
803 oy->unsynced=0;
804 oy->headerbytes=0;
805 oy->bodybytes=0;
806 return(0);
809 int ogg_stream_reset(ogg_stream_state *os){
810 os->body_fill=0;
811 os->body_returned=0;
813 os->lacing_fill=0;
814 os->lacing_packet=0;
815 os->lacing_returned=0;
817 os->header_fill=0;
819 os->e_o_s=0;
820 os->b_o_s=0;
821 os->pageno=-1;
822 os->packetno=0;
823 os->granulepos=0;
825 return(0);
828 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
829 ogg_stream_reset(os);
830 os->serialno=serialno;
831 return(0);
834 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
836 /* The last part of decode. We have the stream broken into packet
837 segments. Now we need to group them into packets (or return the
838 out of sync markers) */
840 int ptr=os->lacing_returned;
842 if(os->lacing_packet<=ptr)return(0);
844 if(os->lacing_vals[ptr]&0x400){
845 /* we need to tell the codec there's a gap; it might need to
846 handle previous packet dependencies. */
847 os->lacing_returned++;
848 os->packetno++;
849 return(-1);
852 if(!op && !adv)return(1); /* just using peek as an inexpensive way
853 to ask if there's a whole packet
854 waiting */
856 /* Gather the whole packet. We'll have no holes or a partial packet */
858 int size=os->lacing_vals[ptr]&0xff;
859 int bytes=size;
860 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
861 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
863 while(size==255){
864 int val=os->lacing_vals[++ptr];
865 size=val&0xff;
866 if(val&0x200)eos=0x200;
867 bytes+=size;
870 if(op){
871 op->e_o_s=eos;
872 op->b_o_s=bos;
873 op->packet=os->body_data+os->body_returned;
874 op->packetno=os->packetno;
875 op->granulepos=os->granule_vals[ptr];
876 op->bytes=bytes;
879 if(adv){
880 os->body_returned+=bytes;
881 os->lacing_returned=ptr+1;
882 os->packetno++;
885 return(1);
888 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
889 return _packetout(os,op,1);
892 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
893 return _packetout(os,op,0);
896 void ogg_packet_clear(ogg_packet *op) {
897 _ogg_free(op->packet);
898 memset(op, 0, sizeof(*op));