comparison tremor/framing.c @ 14280:8631a3803289

internal Tremor decoder for Ogg/Vorbis
author henry
date Thu, 30 Dec 2004 12:11:32 +0000
parents
children e891ff7a7b6c
comparison
equal deleted inserted replaced
14279:b4b202086260 14280:8631a3803289
1 /********************************************************************
2 * *
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
4 * *
5 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
6 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
7 * ALL REDISTRIBUTION RIGHTS RESERVED. *
8 * *
9 ********************************************************************
10
11 function: code raw [Vorbis] packets into framed OggSquish stream and
12 decode Ogg streams back into raw packets
13
14 note: The CRC code is directly derived from public domain code by
15 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
16 for details.
17
18 ********************************************************************/
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include "ogg.h"
23
24 /* A complete description of Ogg framing exists in docs/framing.html */
25
26 int ogg_page_version(ogg_page *og){
27 return((int)(og->header[4]));
28 }
29
30 int ogg_page_continued(ogg_page *og){
31 return((int)(og->header[5]&0x01));
32 }
33
34 int ogg_page_bos(ogg_page *og){
35 return((int)(og->header[5]&0x02));
36 }
37
38 int ogg_page_eos(ogg_page *og){
39 return((int)(og->header[5]&0x04));
40 }
41
42 ogg_int64_t ogg_page_granulepos(ogg_page *og){
43 unsigned char *page=og->header;
44 ogg_int64_t granulepos=page[13]&(0xff);
45 granulepos= (granulepos<<8)|(page[12]&0xff);
46 granulepos= (granulepos<<8)|(page[11]&0xff);
47 granulepos= (granulepos<<8)|(page[10]&0xff);
48 granulepos= (granulepos<<8)|(page[9]&0xff);
49 granulepos= (granulepos<<8)|(page[8]&0xff);
50 granulepos= (granulepos<<8)|(page[7]&0xff);
51 granulepos= (granulepos<<8)|(page[6]&0xff);
52 return(granulepos);
53 }
54
55 int ogg_page_serialno(ogg_page *og){
56 return(og->header[14] |
57 (og->header[15]<<8) |
58 (og->header[16]<<16) |
59 (og->header[17]<<24));
60 }
61
62 long ogg_page_pageno(ogg_page *og){
63 return(og->header[18] |
64 (og->header[19]<<8) |
65 (og->header[20]<<16) |
66 (og->header[21]<<24));
67 }
68
69
70
71 /* returns the number of packets that are completed on this page (if
72 the leading packet is begun on a previous page, but ends on this
73 page, it's counted */
74
75 /* NOTE:
76 If a page consists of a packet begun on a previous page, and a new
77 packet begun (but not completed) on this page, the return will be:
78 ogg_page_packets(page) ==1,
79 ogg_page_continued(page) !=0
80
81 If a page happens to be a single packet that was begun on a
82 previous page, and spans to the next page (in the case of a three or
83 more page packet), the return will be:
84 ogg_page_packets(page) ==0,
85 ogg_page_continued(page) !=0
86 */
87
88 int ogg_page_packets(ogg_page *og){
89 int i,n=og->header[26],count=0;
90 for(i=0;i<n;i++)
91 if(og->header[27+i]<255)count++;
92 return(count);
93 }
94
95 static ogg_uint32_t crc_lookup[256]={
96 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
97 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
98 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
99 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
100 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
101 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
102 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
103 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
104 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
105 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
106 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
107 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
108 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
109 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
110 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
111 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
112 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
113 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
114 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
115 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
116 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
117 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
118 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
119 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
120 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
121 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
122 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
123 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
124 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
125 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
126 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
127 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
128 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
129 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
130 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
131 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
132 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
133 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
134 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
135 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
136 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
137 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
138 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
139 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
140 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
141 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
142 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
143 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
144 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
145 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
146 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
147 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
148 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
149 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
150 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
151 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
152 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
153 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
154 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
155 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
156 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
157 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
158 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
159 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
160
161 /* init the encode/decode logical stream state */
162
163 int ogg_stream_init(ogg_stream_state *os,int serialno){
164 if(os){
165 memset(os,0,sizeof(*os));
166 os->body_storage=16*1024;
167 os->body_data=(unsigned char *)_ogg_malloc(os->body_storage*sizeof(*os->body_data));
168
169 os->lacing_storage=1024;
170 os->lacing_vals=(int *)_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
171 os->granule_vals=(ogg_int64_t *)_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
172
173 os->serialno=serialno;
174
175 return(0);
176 }
177 return(-1);
178 }
179
180 /* _clear does not free os, only the non-flat storage within */
181 int ogg_stream_clear(ogg_stream_state *os){
182 if(os){
183 if(os->body_data)_ogg_free(os->body_data);
184 if(os->lacing_vals)_ogg_free(os->lacing_vals);
185 if(os->granule_vals)_ogg_free(os->granule_vals);
186
187 memset(os,0,sizeof(*os));
188 }
189 return(0);
190 }
191
192 int ogg_stream_destroy(ogg_stream_state *os){
193 if(os){
194 ogg_stream_clear(os);
195 _ogg_free(os);
196 }
197 return(0);
198 }
199
200 /* Helpers for ogg_stream_encode; this keeps the structure and
201 what's happening fairly clear */
202
203 static void _os_body_expand(ogg_stream_state *os,int needed){
204 if(os->body_storage<=os->body_fill+needed){
205 os->body_storage+=(needed+1024);
206 os->body_data=(unsigned char *)_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
207 }
208 }
209
210 static void _os_lacing_expand(ogg_stream_state *os,int needed){
211 if(os->lacing_storage<=os->lacing_fill+needed){
212 os->lacing_storage+=(needed+32);
213 os->lacing_vals=(int *)_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
214 os->granule_vals=(ogg_int64_t *)_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
215 }
216 }
217
218 /* checksum the page */
219 /* Direct table CRC; note that this will be faster in the future if we
220 perform the checksum silmultaneously with other copies */
221
222 void ogg_page_checksum_set(ogg_page *og){
223 if(og){
224 ogg_uint32_t crc_reg=0;
225 int i;
226
227 /* safety; needed for API behavior, but not framing code */
228 og->header[22]=0;
229 og->header[23]=0;
230 og->header[24]=0;
231 og->header[25]=0;
232
233 for(i=0;i<og->header_len;i++)
234 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
235 for(i=0;i<og->body_len;i++)
236 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
237
238 og->header[22]=crc_reg&0xff;
239 og->header[23]=(crc_reg>>8)&0xff;
240 og->header[24]=(crc_reg>>16)&0xff;
241 og->header[25]=(crc_reg>>24)&0xff;
242 }
243 }
244
245 /* DECODING PRIMITIVES: packet streaming layer **********************/
246
247 /* This has two layers to place more of the multi-serialno and paging
248 control in the application's hands. First, we expose a data buffer
249 using ogg_sync_buffer(). The app either copies into the
250 buffer, or passes it directly to read(), etc. We then call
251 ogg_sync_wrote() to tell how many bytes we just added.
252
253 Pages are returned (pointers into the buffer in ogg_sync_state)
254 by ogg_sync_pageout(). The page is then submitted to
255 ogg_stream_pagein() along with the appropriate
256 ogg_stream_state* (ie, matching serialno). We then get raw
257 packets out calling ogg_stream_packetout() with a
258 ogg_stream_state. See the 'frame-prog.txt' docs for details and
259 example code. */
260
261 /* initialize the struct to a known state */
262 int ogg_sync_init(ogg_sync_state *oy){
263 if(oy){
264 memset(oy,0,sizeof(*oy));
265 }
266 return(0);
267 }
268
269 /* clear non-flat storage within */
270 int ogg_sync_clear(ogg_sync_state *oy){
271 if(oy){
272 if(oy->data)_ogg_free(oy->data);
273 ogg_sync_init(oy);
274 }
275 return(0);
276 }
277
278 int ogg_sync_destroy(ogg_sync_state *oy){
279 if(oy){
280 ogg_sync_clear(oy);
281 _ogg_free(oy);
282 }
283 return(0);
284 }
285
286 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
287
288 /* first, clear out any space that has been previously returned */
289 if(oy->returned>8192){
290 oy->fill-=oy->returned;
291 if(oy->fill>0)
292 memmove(oy->data,oy->data+oy->returned,oy->fill);
293 oy->returned=0;
294 }
295
296 if(size>oy->storage-oy->fill){
297 /* We need to extend the internal buffer */
298 long newsize=size+oy->fill+4096; /* an extra page to be nice */
299
300 if(oy->data)
301 oy->data=(unsigned char *)_ogg_realloc(oy->data,newsize);
302 else
303 oy->data=(unsigned char *)_ogg_malloc(newsize);
304 oy->storage=newsize;
305 }
306
307 /* expose a segment at least as large as requested at the fill mark */
308 return((char *)oy->data+oy->fill);
309 }
310
311 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
312 if(oy->fill+bytes>oy->storage)return(-1);
313 oy->fill+=bytes;
314 return(0);
315 }
316
317 /* sync the stream. This is meant to be useful for finding page
318 boundaries.
319
320 return values for this:
321 -n) skipped n bytes
322 0) page not ready; more data (no bytes skipped)
323 n) page synced at current location; page length n bytes
324
325 */
326
327 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
328 unsigned char *page=oy->data+oy->returned;
329 unsigned char *next;
330 long bytes=oy->fill-oy->returned;
331
332 if(oy->headerbytes==0){
333 int headerbytes,i;
334 if(bytes<27)return(0); /* not enough for a header */
335
336 /* verify capture pattern */
337 if(memcmp(page,"OggS",4))goto sync_fail;
338
339 headerbytes=page[26]+27;
340 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
341
342 /* count up body length in the segment table */
343
344 for(i=0;i<page[26];i++)
345 oy->bodybytes+=page[27+i];
346 oy->headerbytes=headerbytes;
347 }
348
349 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
350
351 /* The whole test page is buffered. Verify the checksum */
352 {
353 /* Grab the checksum bytes, set the header field to zero */
354 char chksum[4];
355 ogg_page log;
356
357 memcpy(chksum,page+22,4);
358 memset(page+22,0,4);
359
360 /* set up a temp page struct and recompute the checksum */
361 log.header=page;
362 log.header_len=oy->headerbytes;
363 log.body=page+oy->headerbytes;
364 log.body_len=oy->bodybytes;
365 ogg_page_checksum_set(&log);
366
367 /* Compare */
368 if(memcmp(chksum,page+22,4)){
369 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
370 at all) */
371 /* replace the computed checksum with the one actually read in */
372 memcpy(page+22,chksum,4);
373
374 /* Bad checksum. Lose sync */
375 goto sync_fail;
376 }
377 }
378
379 /* yes, have a whole page all ready to go */
380 {
381 unsigned char *page=oy->data+oy->returned;
382 long bytes;
383
384 if(og){
385 og->header=page;
386 og->header_len=oy->headerbytes;
387 og->body=page+oy->headerbytes;
388 og->body_len=oy->bodybytes;
389 }
390
391 oy->unsynced=0;
392 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
393 oy->headerbytes=0;
394 oy->bodybytes=0;
395 return(bytes);
396 }
397
398 sync_fail:
399
400 oy->headerbytes=0;
401 oy->bodybytes=0;
402
403 /* search for possible capture */
404 next=(unsigned char *)memchr(page+1,'O',bytes-1);
405 if(!next)
406 next=oy->data+oy->fill;
407
408 oy->returned=next-oy->data;
409 return(-(next-page));
410 }
411
412 /* sync the stream and get a page. Keep trying until we find a page.
413 Supress 'sync errors' after reporting the first.
414
415 return values:
416 -1) recapture (hole in data)
417 0) need more data
418 1) page returned
419
420 Returns pointers into buffered data; invalidated by next call to
421 _stream, _clear, _init, or _buffer */
422
423 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
424
425 /* all we need to do is verify a page at the head of the stream
426 buffer. If it doesn't verify, we look for the next potential
427 frame */
428
429 while(1){
430 long ret=ogg_sync_pageseek(oy,og);
431 if(ret>0){
432 /* have a page */
433 return(1);
434 }
435 if(ret==0){
436 /* need more data */
437 return(0);
438 }
439
440 /* head did not start a synced page... skipped some bytes */
441 if(!oy->unsynced){
442 oy->unsynced=1;
443 return(-1);
444 }
445
446 /* loop. keep looking */
447
448 }
449 }
450
451 /* add the incoming page to the stream state; we decompose the page
452 into packet segments here as well. */
453
454 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
455 unsigned char *header=og->header;
456 unsigned char *body=og->body;
457 long bodysize=og->body_len;
458 int segptr=0;
459
460 int version=ogg_page_version(og);
461 int continued=ogg_page_continued(og);
462 int bos=ogg_page_bos(og);
463 int eos=ogg_page_eos(og);
464 ogg_int64_t granulepos=ogg_page_granulepos(og);
465 int serialno=ogg_page_serialno(og);
466 long pageno=ogg_page_pageno(og);
467 int segments=header[26];
468
469 /* clean up 'returned data' */
470 {
471 long lr=os->lacing_returned;
472 long br=os->body_returned;
473
474 /* body data */
475 if(br>8192){
476 os->body_fill-=br;
477 if(os->body_fill)
478 memmove(os->body_data,os->body_data+br,os->body_fill);
479 os->body_returned=0;
480 }
481
482 if(lr>8192){
483 /* segment table */
484 if(os->lacing_fill-lr){
485 memmove(os->lacing_vals,os->lacing_vals+lr,
486 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
487 memmove(os->granule_vals,os->granule_vals+lr,
488 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
489 }
490 os->lacing_fill-=lr;
491 os->lacing_packet-=lr;
492 os->lacing_returned=0;
493 }
494 }
495
496 /* check the serial number */
497 if(serialno!=os->serialno)return(-1);
498 if(version>0)return(-1);
499
500 _os_lacing_expand(os,segments+1);
501
502 /* are we in sequence? */
503 if(pageno!=os->pageno){
504 int i;
505
506 /* unroll previous partial packet (if any) */
507 for(i=os->lacing_packet;i<os->lacing_fill;i++)
508 os->body_fill-=os->lacing_vals[i]&0xff;
509 os->lacing_fill=os->lacing_packet;
510
511 /* make a note of dropped data in segment table */
512 if(os->pageno!=-1){
513 os->lacing_vals[os->lacing_fill++]=0x400;
514 os->lacing_packet++;
515 }
516
517 /* are we a 'continued packet' page? If so, we'll need to skip
518 some segments */
519 if(continued){
520 bos=0;
521 for(;segptr<segments;segptr++){
522 int val=header[27+segptr];
523 body+=val;
524 bodysize-=val;
525 if(val<255){
526 segptr++;
527 break;
528 }
529 }
530 }
531 }
532
533 if(bodysize){
534 _os_body_expand(os,bodysize);
535 memcpy(os->body_data+os->body_fill,body,bodysize);
536 os->body_fill+=bodysize;
537 }
538
539 {
540 int saved=-1;
541 while(segptr<segments){
542 int val=header[27+segptr];
543 os->lacing_vals[os->lacing_fill]=val;
544 os->granule_vals[os->lacing_fill]=-1;
545
546 if(bos){
547 os->lacing_vals[os->lacing_fill]|=0x100;
548 bos=0;
549 }
550
551 if(val<255)saved=os->lacing_fill;
552
553 os->lacing_fill++;
554 segptr++;
555
556 if(val<255)os->lacing_packet=os->lacing_fill;
557 }
558
559 /* set the granulepos on the last granuleval of the last full packet */
560 if(saved!=-1){
561 os->granule_vals[saved]=granulepos;
562 }
563
564 }
565
566 if(eos){
567 os->e_o_s=1;
568 if(os->lacing_fill>0)
569 os->lacing_vals[os->lacing_fill-1]|=0x200;
570 }
571
572 os->pageno=pageno+1;
573
574 return(0);
575 }
576
577 /* clear things to an initial state. Good to call, eg, before seeking */
578 int ogg_sync_reset(ogg_sync_state *oy){
579 oy->fill=0;
580 oy->returned=0;
581 oy->unsynced=0;
582 oy->headerbytes=0;
583 oy->bodybytes=0;
584 return(0);
585 }
586
587 int ogg_stream_reset(ogg_stream_state *os){
588 os->body_fill=0;
589 os->body_returned=0;
590
591 os->lacing_fill=0;
592 os->lacing_packet=0;
593 os->lacing_returned=0;
594
595 os->header_fill=0;
596
597 os->e_o_s=0;
598 os->b_o_s=0;
599 os->pageno=-1;
600 os->packetno=0;
601 os->granulepos=0;
602
603 return(0);
604 }
605
606 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
607
608 /* The last part of decode. We have the stream broken into packet
609 segments. Now we need to group them into packets (or return the
610 out of sync markers) */
611
612 int ptr=os->lacing_returned;
613
614 if(os->lacing_packet<=ptr)return(0);
615
616 if(os->lacing_vals[ptr]&0x400){
617 /* we need to tell the codec there's a gap; it might need to
618 handle previous packet dependencies. */
619 os->lacing_returned++;
620 os->packetno++;
621 return(-1);
622 }
623
624 if(!op && !adv)return(1); /* just using peek as an inexpensive way
625 to ask if there's a whole packet
626 waiting */
627
628 /* Gather the whole packet. We'll have no holes or a partial packet */
629 {
630 int size=os->lacing_vals[ptr]&0xff;
631 int bytes=size;
632 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
633 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
634
635 while(size==255){
636 int val=os->lacing_vals[++ptr];
637 size=val&0xff;
638 if(val&0x200)eos=0x200;
639 bytes+=size;
640 }
641
642 if(op){
643 op->e_o_s=eos;
644 op->b_o_s=bos;
645 op->packet=os->body_data+os->body_returned;
646 op->packetno=os->packetno;
647 op->granulepos=os->granule_vals[ptr];
648 op->bytes=bytes;
649 }
650
651 if(adv){
652 os->body_returned+=bytes;
653 os->lacing_returned=ptr+1;
654 os->packetno++;
655 }
656 }
657 return(1);
658 }
659
660 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
661 return _packetout(os,op,1);
662 }
663
664 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
665 return _packetout(os,op,0);
666 }
667
668 void ogg_packet_clear(ogg_packet *op) {
669 _ogg_free(op->packet);
670 memset(op, 0, sizeof(*op));
671 }
672