1 /********************************************************************
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. *
8 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * by the Xiph.Org Foundation http://www.xiph.org/ *
11 ********************************************************************
13 function: code raw [Vorbis] packets into framed OggSquish stream and
14 decode Ogg streams back into raw packets
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
21 ********************************************************************/
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);
58 int ogg_page_serialno(ogg_page
*og
){
59 return(og
->header
[14] |
61 (og
->header
[16]<<16) |
62 (og
->header
[17]<<24));
65 long ogg_page_pageno(ogg_page
*og
){
66 return(og
->header
[18] |
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
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;
94 if(og
->header
[27+i
]<255)count
++;
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
){
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 */
116 return (r
& 0xffffffffUL
);
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
){
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
;
205 /* _clear does not free os, only the non-flat storage within */
206 int ogg_stream_clear(ogg_stream_state
*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
));
217 int ogg_stream_destroy(ogg_stream_state
*os
){
219 ogg_stream_clear(os
);
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
){
249 ogg_uint32_t crc_reg
=0;
252 /* safety; needed for API behavior, but not framing code */
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
279 os
->body_fill
-=os
->body_returned
;
281 memmove(os
->body_data
,os
->body_data
+os
->body_returned
,
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
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 */
314 if(op
->e_o_s
)os
->e_o_s
=1;
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
){
336 int maxvals
=(os
->lacing_fill
>255?255:os
->lacing_fill
);
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 */
350 for(vals
=0;vals
<maxvals
;vals
++){
351 if((os
->lacing_vals
[vals
]&0x0ff)<255){
357 for(vals
=0;vals
<maxvals
;vals
++){
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 */
370 /* continued packet flag? */
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;
379 /* 64 bits of PCM position */
381 os
->header
[i
]=(unsigned char)(granule_pos
&0xff);
385 /* 32 bits of stream serial number */
387 long serialno
=os
->serialno
;
389 os
->header
[i
]=(unsigned char)(serialno
&0xff);
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
402 long pageno
=os
->pageno
++;
404 os
->header
[i
]=(unsigned char)(pageno
&0xff);
409 /* zero for computation; filled in later */
416 os
->header
[26]=(unsigned char)(vals
&0xff);
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
;
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
);
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 */
460 int ogg_stream_eos(ogg_stream_state
*os
){
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
480 /* initialize the struct to a known state */
481 int ogg_sync_init(ogg_sync_state
*oy
){
483 memset(oy
,0,sizeof(*oy
));
488 /* clear non-flat storage within */
489 int ogg_sync_clear(ogg_sync_state
*oy
){
491 if(oy
->data
)_ogg_free(oy
->data
);
497 int ogg_sync_destroy(ogg_sync_state
*oy
){
505 char *ogg_sync_buffer(ogg_sync_state
*oy
, long size
){
507 /* first, clear out any space that has been previously returned */
509 oy
->fill
-=oy
->returned
;
511 memmove(oy
->data
,oy
->data
+oy
->returned
,oy
->fill
);
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 */
520 oy
->data
=_ogg_realloc(oy
->data
,newsize
);
522 oy
->data
=_ogg_malloc(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);
536 /* sync the stream. This is meant to be useful for finding page
539 return values for this:
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
;
549 long bytes
=oy
->fill
-oy
->returned
;
551 if(oy
->headerbytes
==0){
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 */
576 memcpy(chksum
,page
+22,4);
579 /* set up a temp page struct and recompute the checksum */
581 log
.header_len
=oy
->headerbytes
;
582 log
.body
=page
+oy
->headerbytes
;
583 log
.body_len
=oy
->bodybytes
;
584 ogg_page_checksum_set(&log
);
587 if(memcmp(chksum
,page
+22,4)){
588 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
590 /* replace the computed checksum with the one actually read in */
591 memcpy(page
+22,chksum
,4);
593 /* Bad checksum. Lose sync */
598 /* yes, have a whole page all ready to go */
600 unsigned char *page
=oy
->data
+oy
->returned
;
605 og
->header_len
=oy
->headerbytes
;
606 og
->body
=page
+oy
->headerbytes
;
607 og
->body_len
=oy
->bodybytes
;
611 oy
->returned
+=(bytes
=oy
->headerbytes
+oy
->bodybytes
);
622 /* search for possible capture */
623 next
=memchr(page
+1,'O',bytes
-1);
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.
635 -1) recapture (hole in data)
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
649 long ret
=ogg_sync_pageseek(oy
,og
);
659 /* head did not start a synced page... skipped some bytes */
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
;
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
;
697 memmove(os
->body_data
,os
->body_data
+br
,os
->body_fill
);
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
));
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
){
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 */
732 os
->lacing_vals
[os
->lacing_fill
++]=0x400;
737 /* are we a 'continued packet' page? If so, we may need to skip
740 if(os
->lacing_fill
<1 ||
741 os
->lacing_vals
[os
->lacing_fill
-1]==0x400){
743 for(;segptr
<segments
;segptr
++){
744 int val
=header
[27+segptr
];
756 _os_body_expand(os
,bodysize
);
757 memcpy(os
->body_data
+os
->body_fill
,body
,bodysize
);
758 os
->body_fill
+=bodysize
;
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;
769 os
->lacing_vals
[os
->lacing_fill
]|=0x100;
773 if(val
<255)saved
=os
->lacing_fill
;
778 if(val
<255)os
->lacing_packet
=os
->lacing_fill
;
781 /* set the granulepos on the last granuleval of the last full packet */
783 os
->granule_vals
[saved
]=granulepos
;
790 if(os
->lacing_fill
>0)
791 os
->lacing_vals
[os
->lacing_fill
-1]|=0x200;
799 /* clear things to an initial state. Good to call, eg, before seeking */
800 int ogg_sync_reset(ogg_sync_state
*oy
){
809 int ogg_stream_reset(ogg_stream_state
*os
){
815 os
->lacing_returned
=0;
828 int ogg_stream_reset_serialno(ogg_stream_state
*os
,int serialno
){
829 ogg_stream_reset(os
);
830 os
->serialno
=serialno
;
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
++;
852 if(!op
&& !adv
)return(1); /* just using peek as an inexpensive way
853 to ask if there's a whole packet
856 /* Gather the whole packet. We'll have no holes or a partial packet */
858 int size
=os
->lacing_vals
[ptr
]&0xff;
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? */
864 int val
=os
->lacing_vals
[++ptr
];
866 if(val
&0x200)eos
=0x200;
873 op
->packet
=os
->body_data
+os
->body_returned
;
874 op
->packetno
=os
->packetno
;
875 op
->granulepos
=os
->granule_vals
[ptr
];
880 os
->body_returned
+=bytes
;
881 os
->lacing_returned
=ptr
+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
));