1 /********************************************************************
3 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
5 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
6 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
7 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
9 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
10 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
12 ********************************************************************
14 function: decode Ogg streams back into raw packets
16 note: The CRC code is directly derived from public domain code by
17 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
20 ********************************************************************/
22 #include "config-tremor.h"
28 /* A complete description of Ogg framing exists in docs/framing.html */
30 /* basic, centralized Ogg memory management based on linked lists of
31 references to refcounted memory buffers. References and buffers
32 are both recycled. Buffers are passed around and consumed in
35 static ogg_buffer_state
*ogg_buffer_create(void){
36 ogg_buffer_state
*bs
=_ogg_calloc(1,sizeof(*bs
));
40 /* destruction is 'lazy'; there may be memory references outstanding,
41 and yanking the buffer state out from underneath would be
42 antisocial. Dealloc what is currently unused and have
43 _release_one watch for the stragglers to come in. When they do,
44 finish destruction. */
46 /* call the helper while holding lock */
47 static void _ogg_buffer_destroy(ogg_buffer_state
*bs
){
53 bt
=bs
->unused_buffers
;
54 rt
=bs
->unused_references
;
59 if(b
->data
)_ogg_free(b
->data
);
68 bs
->unused_references
=0;
76 static void ogg_buffer_destroy(ogg_buffer_state
*bs
){
78 _ogg_buffer_destroy(bs
);
81 static ogg_buffer
*_fetch_buffer(ogg_buffer_state
*bs
,long bytes
){
85 /* do we have an unused buffer sitting in the pool? */
86 if(bs
->unused_buffers
){
87 ob
=bs
->unused_buffers
;
88 bs
->unused_buffers
=ob
->ptr
.next
;
90 /* if the unused buffer is too small, grow it */
92 ob
->data
=_ogg_realloc(ob
->data
,bytes
);
96 /* allocate a new buffer */
97 ob
=_ogg_malloc(sizeof(*ob
));
98 ob
->data
=_ogg_malloc(bytes
<16?16:bytes
);
107 STATICIRAM_NOT_MDCT ogg_reference
*_fetch_ref(ogg_buffer_state
*bs
)
108 ICODE_ATTR_TREMOR_NOT_MDCT
;
109 STATICIRAM_NOT_MDCT ogg_reference
*_fetch_ref(ogg_buffer_state
*bs
){
113 /* do we have an unused reference sitting in the pool? */
114 if(bs
->unused_references
){
115 or=bs
->unused_references
;
116 bs
->unused_references
=or->next
;
118 /* allocate a new reference */
119 or=_ogg_malloc(sizeof(*or));
128 /* fetch a reference pointing to a fresh, initially continguous buffer
129 of at least [bytes] length */
130 static ogg_reference
*ogg_buffer_alloc(ogg_buffer_state
*bs
,long bytes
){
131 ogg_buffer
*ob
=_fetch_buffer(bs
,bytes
);
132 ogg_reference
*or=_fetch_ref(bs
);
137 /* enlarge the data buffer in the current link */
138 static void ogg_buffer_realloc(ogg_reference
*or,long bytes
){
139 ogg_buffer
*ob
=or->buffer
;
141 /* if the unused buffer is too small, grow it */
143 ob
->data
=_ogg_realloc(ob
->data
,bytes
);
148 static void _ogg_buffer_mark_one(ogg_reference
*or){
149 or->buffer
->refcount
++;
152 /* increase the refcount of the buffers to which the reference points */
153 static void ogg_buffer_mark(ogg_reference
*or){
155 _ogg_buffer_mark_one(or);
160 /* duplicate a reference (pointing to the same actual buffer memory)
161 and increment buffer refcount. If the desired segment begins out
162 of range, NULL is returned; if the desired segment is simply zero
163 length, a zero length ref is returned. Partial range overlap
164 returns the overlap of the ranges */
165 static ogg_reference
*ogg_buffer_sub(ogg_reference
*or,long begin
,long length
){
166 ogg_reference
*ret
=0,*head
=0;
168 /* walk past any preceeding fragments we don't want */
169 while(or && begin
>=or->length
){
174 /* duplicate the reference chain; increment refcounts */
176 ogg_reference
*temp
=_fetch_ref(or->buffer
->ptr
.owner
);
182 head
->buffer
=or->buffer
;
183 head
->begin
=or->begin
+begin
;
185 if(head
->length
>or->length
-begin
)
186 head
->length
=or->length
-begin
;
189 length
-=head
->length
;
193 ogg_buffer_mark(ret
);
197 static ogg_reference
*ogg_buffer_dup(ogg_reference
*or){
198 ogg_reference
*ret
=0,*head
=0;
199 /* duplicate the reference chain; increment refcounts */
201 ogg_reference
*temp
=_fetch_ref(or->buffer
->ptr
.owner
);
207 head
->buffer
=or->buffer
;
208 head
->begin
=or->begin
;
209 head
->length
=or->length
;
213 ogg_buffer_mark(ret
);
217 /* split a reference into two references; 'return' is a reference to
218 the buffer preceeding pos and 'head'/'tail' are the buffer past the
219 split. If pos is at or past the end of the passed in segment,
220 'head/tail' are NULL */
221 static ogg_reference
*ogg_buffer_split(ogg_reference
**tail
,
222 ogg_reference
**head
,long pos
){
224 /* walk past any preceeding fragments to one of:
225 a) the exact boundary that seps two fragments
226 b) the fragment that needs split somewhere in the middle */
227 ogg_reference
*ret
=*tail
;
228 ogg_reference
*or=*tail
;
230 while(or && pos
>or->length
){
242 /* exact split, or off the end? */
251 /* off or at the end */
257 /* split within a fragment */
259 long beginB
=or->begin
+pos
;
260 long lengthB
=or->length
-pos
;
262 /* make a new reference to tail the second piece */
263 *tail
=_fetch_ref(or->buffer
->ptr
.owner
);
265 (*tail
)->buffer
=or->buffer
;
266 (*tail
)->begin
=beginB
;
267 (*tail
)->length
=lengthB
;
268 (*tail
)->next
=or->next
;
269 _ogg_buffer_mark_one(*tail
);
270 if(head
&& or==*head
)*head
=*tail
;
272 /* update the first piece */
281 static void ogg_buffer_release_one(ogg_reference
*or){
282 ogg_buffer
*ob
=or->buffer
;
283 ogg_buffer_state
*bs
=ob
->ptr
.owner
;
287 bs
->outstanding
--; /* for the returned buffer */
288 ob
->ptr
.next
=bs
->unused_buffers
;
289 bs
->unused_buffers
=ob
;
292 bs
->outstanding
--; /* for the returned reference */
293 or->next
=bs
->unused_references
;
294 bs
->unused_references
=or;
296 _ogg_buffer_destroy(bs
); /* lazy cleanup (if needed) */
300 /* release the references, decrease the refcounts of buffers to which
301 they point, release any buffers with a refcount that drops to zero */
302 static void ogg_buffer_release(ogg_reference
*or){
304 ogg_reference
*next
=or->next
;
305 ogg_buffer_release_one(or);
310 static ogg_reference
*ogg_buffer_pretruncate(ogg_reference
*or,long pos
){
311 /* release preceeding fragments we don't want */
312 while(or && pos
>=or->length
){
313 ogg_reference
*next
=or->next
;
315 ogg_buffer_release_one(or);
325 static ogg_reference
*ogg_buffer_walk(ogg_reference
*or){
333 /* *head is appended to the front end (head) of *tail; both continue to
334 be valid pointers, with *tail at the tail and *head at the head */
335 static ogg_reference
*ogg_buffer_cat(ogg_reference
*tail
, ogg_reference
*head
){
336 if(!tail
)return head
;
342 return ogg_buffer_walk(head
);
345 static void _positionB(oggbyte_buffer
*b
,int pos
){
347 /* start at beginning, scan forward */
350 b
->end
=b
->pos
+b
->ref
->length
;
351 b
->ptr
=b
->ref
->buffer
->data
+b
->ref
->begin
;
355 static void _positionF(oggbyte_buffer
*b
,int pos
){
356 /* scan forward for position */
358 /* just seek forward */
359 b
->pos
+=b
->ref
->length
;
361 b
->end
=b
->ref
->length
+b
->pos
;
362 b
->ptr
=b
->ref
->buffer
->data
+b
->ref
->begin
;
366 static int oggbyte_init(oggbyte_buffer
*b
,ogg_reference
*or){
367 memset(b
,0,sizeof(*b
));
369 b
->ref
=b
->baseref
=or;
371 b
->end
=b
->ref
->length
;
372 b
->ptr
=b
->ref
->buffer
->data
+b
->ref
->begin
;
378 static void oggbyte_set4(oggbyte_buffer
*b
,ogg_uint32_t val
,int pos
){
383 b
->ptr
[pos
-b
->pos
]=val
;
389 static unsigned char oggbyte_read1(oggbyte_buffer
*b
,int pos
){
392 return b
->ptr
[pos
-b
->pos
];
395 static ogg_uint32_t
oggbyte_read4(oggbyte_buffer
*b
,int pos
){
399 ret
=b
->ptr
[pos
-b
->pos
];
401 ret
|=b
->ptr
[pos
-b
->pos
]<<8;
403 ret
|=b
->ptr
[pos
-b
->pos
]<<16;
405 ret
|=b
->ptr
[pos
-b
->pos
]<<24;
409 static ogg_int64_t
oggbyte_read8(oggbyte_buffer
*b
,int pos
){
416 t
[i
]=b
->ptr
[pos
++ -b
->pos
];
420 ret
=b
->ptr
[pos
-b
->pos
];
428 /* Now we get to the actual framing code */
430 int ogg_page_version(ogg_page
*og
){
432 oggbyte_init(&ob
,og
->header
);
433 return oggbyte_read1(&ob
,4);
436 int ogg_page_continued(ogg_page
*og
){
438 oggbyte_init(&ob
,og
->header
);
439 return oggbyte_read1(&ob
,5)&0x01;
442 int ogg_page_bos(ogg_page
*og
){
444 oggbyte_init(&ob
,og
->header
);
445 return oggbyte_read1(&ob
,5)&0x02;
448 int ogg_page_eos(ogg_page
*og
){
450 oggbyte_init(&ob
,og
->header
);
451 return oggbyte_read1(&ob
,5)&0x04;
454 ogg_int64_t
ogg_page_granulepos(ogg_page
*og
){
456 oggbyte_init(&ob
,og
->header
);
457 return oggbyte_read8(&ob
,6);
460 ogg_uint32_t
ogg_page_serialno(ogg_page
*og
){
462 oggbyte_init(&ob
,og
->header
);
463 return oggbyte_read4(&ob
,14);
466 ogg_uint32_t
ogg_page_pageno(ogg_page
*og
){
468 oggbyte_init(&ob
,og
->header
);
469 return oggbyte_read4(&ob
,18);
472 /* Static CRC calculation table. See older code in CVS for dead
473 run-time initialization code. */
475 static const ogg_uint32_t crc_lookup
[256] ICONST_ATTR
= {
476 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
477 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
478 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
479 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
480 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
481 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
482 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
483 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
484 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
485 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
486 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
487 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
488 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
489 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
490 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
491 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
492 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
493 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
494 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
495 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
496 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
497 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
498 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
499 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
500 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
501 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
502 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
503 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
504 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
505 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
506 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
507 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
508 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
509 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
510 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
511 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
512 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
513 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
514 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
515 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
516 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
517 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
518 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
519 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
520 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
521 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
522 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
523 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
524 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
525 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
526 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
527 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
528 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
529 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
530 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
531 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
532 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
533 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
534 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
535 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
536 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
537 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
538 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
539 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
541 ogg_sync_state
*ogg_sync_create(void){
542 ogg_sync_state
*oy
=_ogg_calloc(1,sizeof(*oy
));
543 memset(oy
,0,sizeof(*oy
));
544 oy
->bufferpool
=ogg_buffer_create();
548 int ogg_sync_destroy(ogg_sync_state
*oy
){
551 ogg_buffer_destroy(oy
->bufferpool
);
552 memset(oy
,0,sizeof(*oy
));
558 unsigned char *ogg_sync_bufferin(ogg_sync_state
*oy
, long bytes
){
560 /* [allocate and] expose a buffer for data submission.
562 If there is no head fragment
563 allocate one and expose it
565 if the current head fragment has sufficient unused space
568 if the current head fragment is unused
571 allocate new fragment and expose it
574 /* base case; fifo uninitialized */
576 oy
->fifo_head
=oy
->fifo_tail
=ogg_buffer_alloc(oy
->bufferpool
,bytes
);
577 return oy
->fifo_head
->buffer
->data
;
580 /* space left in current fragment case */
581 if(oy
->fifo_head
->buffer
->size
-
582 oy
->fifo_head
->length
-
583 oy
->fifo_head
->begin
>= bytes
)
584 return oy
->fifo_head
->buffer
->data
+
585 oy
->fifo_head
->length
+oy
->fifo_head
->begin
;
587 /* current fragment is unused, but too small */
588 if(!oy
->fifo_head
->length
){
589 ogg_buffer_realloc(oy
->fifo_head
,bytes
);
590 return oy
->fifo_head
->buffer
->data
+oy
->fifo_head
->begin
;
593 /* current fragment used/full; get new fragment */
595 ogg_reference
*new=ogg_buffer_alloc(oy
->bufferpool
,bytes
);
596 oy
->fifo_head
->next
=new;
599 return oy
->fifo_head
->buffer
->data
;
602 int ogg_sync_wrote(ogg_sync_state
*oy
, long bytes
){
603 if(!oy
->fifo_head
)return OGG_EINVAL
;
604 if(oy
->fifo_head
->buffer
->size
-oy
->fifo_head
->length
-oy
->fifo_head
->begin
<
605 bytes
)return OGG_EINVAL
;
606 oy
->fifo_head
->length
+=bytes
;
607 oy
->fifo_fill
+=bytes
;
611 static ogg_uint32_t
_checksum(ogg_reference
*or, int bytes
){
612 ogg_uint32_t crc_reg
=0;
616 unsigned char *data
=or->buffer
->data
+or->begin
;
617 post
=(bytes
<or->length
?bytes
:or->length
);
619 crc_reg
=(crc_reg
<<8)^crc_lookup
[((crc_reg
>> 24)&0xff)^data
[j
]];
628 /* sync the stream. This is meant to be useful for finding page
631 return values for this:
633 0) page not ready; more data (no bytes skipped)
634 n) page synced at current location; page length n bytes
638 long ogg_sync_pageseek(ogg_sync_state
*oy
,ogg_page
*og
){
642 ogg_page_release(og
);
645 oggbyte_init(&page
,oy
->fifo_tail
);
647 if(oy
->headerbytes
==0){
648 if(bytes
<27)goto sync_out
; /* not enough for even a minimal header */
650 /* verify capture pattern */
651 if(oggbyte_read1(&page
,0)!=(int)'O' ||
652 oggbyte_read1(&page
,1)!=(int)'g' ||
653 oggbyte_read1(&page
,2)!=(int)'g' ||
654 oggbyte_read1(&page
,3)!=(int)'S' ) goto sync_fail
;
656 oy
->headerbytes
=oggbyte_read1(&page
,26)+27;
658 if(bytes
<oy
->headerbytes
)goto sync_out
; /* not enough for header +
660 if(oy
->bodybytes
==0){
662 /* count up body length in the segment table */
663 for(i
=0;i
<oy
->headerbytes
-27;i
++)
664 oy
->bodybytes
+=oggbyte_read1(&page
,27+i
);
667 if(oy
->bodybytes
+oy
->headerbytes
>bytes
)goto sync_out
;
669 /* we have what appears to be a complete page; last test: verify
672 ogg_uint32_t chksum
=oggbyte_read4(&page
,22);
673 oggbyte_set4(&page
,0,22);
675 /* Compare checksums; memory continues to be common access */
676 if(chksum
!=_checksum(oy
->fifo_tail
,oy
->bodybytes
+oy
->headerbytes
)){
678 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
679 at all). replace the computed checksum with the one actually
680 read in; remember all the memory is common access */
682 oggbyte_set4(&page
,chksum
,22);
685 oggbyte_set4(&page
,chksum
,22);
688 /* We have a page. Set up page return. */
690 /* set up page output */
691 og
->header
=ogg_buffer_split(&oy
->fifo_tail
,&oy
->fifo_head
,oy
->headerbytes
);
692 og
->header_len
=oy
->headerbytes
;
693 og
->body
=ogg_buffer_split(&oy
->fifo_tail
,&oy
->fifo_head
,oy
->bodybytes
);
694 og
->body_len
=oy
->bodybytes
;
698 ogg_buffer_pretruncate(oy
->fifo_tail
,oy
->headerbytes
+oy
->bodybytes
);
699 if(!oy
->fifo_tail
)oy
->fifo_head
=0;
702 ret
=oy
->headerbytes
+oy
->bodybytes
;
714 oy
->fifo_tail
=ogg_buffer_pretruncate(oy
->fifo_tail
,1);
717 /* search forward through fragments for possible capture */
718 while(oy
->fifo_tail
){
719 /* invariant: fifo_cursor points to a position in fifo_tail */
720 unsigned char *now
=oy
->fifo_tail
->buffer
->data
+oy
->fifo_tail
->begin
;
721 unsigned char *next
=memchr(now
, 'O', oy
->fifo_tail
->length
);
724 /* possible capture in this segment */
726 oy
->fifo_tail
=ogg_buffer_pretruncate(oy
->fifo_tail
,bytes
);
730 /* no capture. advance to next segment */
731 long bytes
=oy
->fifo_tail
->length
;
733 oy
->fifo_tail
=ogg_buffer_pretruncate(oy
->fifo_tail
,bytes
);
736 if(!oy
->fifo_tail
)oy
->fifo_head
=0;
743 /* clear things to an initial state. Good to call, eg, before seeking */
744 int ogg_sync_reset(ogg_sync_state
*oy
){
746 ogg_buffer_release(oy
->fifo_tail
);
757 ogg_stream_state
*ogg_stream_create(int serialno
){
758 ogg_stream_state
*os
=_ogg_calloc(1,sizeof(*os
));
759 os
->serialno
=serialno
;
764 int ogg_stream_destroy(ogg_stream_state
*os
){
766 ogg_buffer_release(os
->header_tail
);
767 ogg_buffer_release(os
->body_tail
);
768 memset(os
,0,sizeof(*os
));
775 #define FINFLAG 0x80000000UL
776 #define FINMASK 0x7fffffffUL
778 static void _next_lace(oggbyte_buffer
*ob
,ogg_stream_state
*os
){
779 /* search ahead one lace */
780 os
->body_fill_next
=0;
781 while(os
->laceptr
<os
->lacing_fill
){
782 int val
=oggbyte_read1(ob
,27+os
->laceptr
++);
783 os
->body_fill_next
+=val
;
785 os
->body_fill_next
|=FINFLAG
;
792 STATICIRAM_NOT_MDCT
void _span_queued_page(ogg_stream_state
*os
)
793 ICODE_ATTR_TREMOR_NOT_MDCT
;
794 STATICIRAM_NOT_MDCT
void _span_queued_page(ogg_stream_state
*os
){
795 while( !(os
->body_fill
&FINFLAG
) ){
797 if(!os
->header_tail
)break;
799 /* first flush out preceeding page header (if any). Body is
800 flushed as it's consumed, so that's not done here. */
802 if(os
->lacing_fill
>=0)
803 os
->header_tail
=ogg_buffer_pretruncate(os
->header_tail
,
809 if(!os
->header_tail
){
814 /* process/prepare next page, if any */
818 ogg_page og
; /* only for parsing header values */
819 og
.header
=os
->header_tail
; /* only for parsing header values */
820 pageno
=ogg_page_pageno(&og
);
822 oggbyte_init(&ob
,os
->header_tail
);
823 os
->lacing_fill
=oggbyte_read1(&ob
,26);
825 /* are we in sequence? */
826 if(pageno
!=os
->pageno
){
827 if(os
->pageno
==-1) /* indicates seek or reset */
828 os
->holeflag
=1; /* set for internal use */
830 os
->holeflag
=2; /* set for external reporting */
832 os
->body_tail
=ogg_buffer_pretruncate(os
->body_tail
,
834 if(os
->body_tail
==0)os
->body_head
=0;
839 if(ogg_page_continued(&og
)){
840 if(os
->body_fill
==0){
841 /* continued packet, but no preceeding data to continue */
842 /* dump the first partial packet on the page */
845 ogg_buffer_pretruncate(os
->body_tail
,os
->body_fill_next
&FINMASK
);
846 if(os
->body_tail
==0)os
->body_head
=0;
848 if(!os
->spanflag
&& !os
->holeflag
)os
->spanflag
=2;
852 /* preceeding data to continue, but not a continued page */
854 os
->body_tail
=ogg_buffer_pretruncate(os
->body_tail
,
856 if(os
->body_tail
==0)os
->body_head
=0;
860 if(!os
->spanflag
&& !os
->holeflag
)os
->spanflag
=2;
864 if(os
->laceptr
<os
->lacing_fill
){
865 os
->granulepos
=ogg_page_granulepos(&og
);
867 /* get current packet size & flag */
869 os
->body_fill
+=os
->body_fill_next
; /* addition handles the flag fine;
870 unsigned on purpose */
871 /* ...and next packet size & flag */
877 os
->e_o_s
=ogg_page_eos(&og
);
878 os
->b_o_s
=ogg_page_bos(&og
);
884 /* add the incoming page to the stream state; we decompose the page
885 into packet segments here as well. */
887 int ogg_stream_pagein(ogg_stream_state
*os
, ogg_page
*og
){
889 int serialno
=ogg_page_serialno(og
);
890 int version
=ogg_page_version(og
);
892 /* check the serial number */
893 if(serialno
!=os
->serialno
){
894 ogg_page_release(og
);
898 ogg_page_release(og
);
904 os
->body_tail
=og
->body
;
905 os
->body_head
=ogg_buffer_walk(og
->body
);
907 os
->body_head
=ogg_buffer_cat(os
->body_head
,og
->body
);
909 if(!os
->header_tail
){
910 os
->header_tail
=og
->header
;
911 os
->header_head
=ogg_buffer_walk(og
->header
);
914 os
->header_head
=ogg_buffer_cat(os
->header_head
,og
->header
);
917 memset(og
,0,sizeof(*og
));
921 int ogg_stream_reset(ogg_stream_state
*os
){
923 ogg_buffer_release(os
->header_tail
);
924 ogg_buffer_release(os
->body_tail
);
925 os
->header_tail
=os
->header_head
=0;
926 os
->body_tail
=os
->body_head
=0;
941 os
->body_fill_next
=0;
946 int ogg_stream_reset_serialno(ogg_stream_state
*os
,int serialno
){
947 ogg_stream_reset(os
);
948 os
->serialno
=serialno
;
952 STATICIRAM_NOT_MDCT
int _packetout(ogg_stream_state
*os
,ogg_packet
*op
,int adv
)
953 ICODE_ATTR_TREMOR_NOT_MDCT
;
954 STATICIRAM_NOT_MDCT
int _packetout(ogg_stream_state
*os
,ogg_packet
*op
,int adv
){
956 ogg_packet_release(op
);
957 _span_queued_page(os
);
960 int temp
=os
->holeflag
;
971 int temp
=os
->spanflag
;
982 if(!(os
->body_fill
&FINFLAG
)) return 0;
983 if(!op
&& !adv
)return 1; /* just using peek as an inexpensive way
984 to ask if there's a whole packet
988 if(os
->e_o_s
&& os
->body_fill_next
==0)
992 if( (os
->body_fill
&FINFLAG
) && !(os
->body_fill_next
&FINFLAG
) )
993 op
->granulepos
=os
->granulepos
;
996 op
->packetno
=os
->packetno
;
1001 oggbyte_init(&ob
,os
->header_tail
);
1003 /* split the body contents off */
1005 op
->packet
=ogg_buffer_split(&os
->body_tail
,&os
->body_head
,
1006 os
->body_fill
&FINMASK
);
1007 op
->bytes
=os
->body_fill
&FINMASK
;
1009 os
->body_tail
=ogg_buffer_pretruncate(os
->body_tail
,
1010 os
->body_fill
&FINMASK
);
1011 if(os
->body_tail
==0)os
->body_head
=0;
1014 /* update lacing pointers */
1015 os
->body_fill
=os
->body_fill_next
;
1019 op
->packet
=ogg_buffer_sub(os
->body_tail
,0,os
->body_fill
&FINMASK
);
1020 op
->bytes
=os
->body_fill
&FINMASK
;
1032 int ogg_stream_packetout(ogg_stream_state
*os
,ogg_packet
*op
)
1033 ICODE_ATTR_TREMOR_NOT_MDCT
;
1034 int ogg_stream_packetout(ogg_stream_state
*os
,ogg_packet
*op
){
1035 return _packetout(os
,op
,1);
1038 int ogg_stream_packetpeek(ogg_stream_state
*os
,ogg_packet
*op
)
1039 ICODE_ATTR_TREMOR_NOT_MDCT
;
1040 int ogg_stream_packetpeek(ogg_stream_state
*os
,ogg_packet
*op
){
1041 return _packetout(os
,op
,0);
1044 int ogg_packet_release(ogg_packet
*op
) {
1046 ogg_buffer_release(op
->packet
);
1047 memset(op
, 0, sizeof(*op
));
1052 int ogg_page_release(ogg_page
*og
) {
1054 ogg_buffer_release(og
->header
);
1055 ogg_buffer_release(og
->body
);
1056 memset(og
, 0, sizeof(*og
));
1061 void ogg_page_dup(ogg_page
*dup
,ogg_page
*orig
){
1062 dup
->header_len
=orig
->header_len
;
1063 dup
->body_len
=orig
->body_len
;
1064 dup
->header
=ogg_buffer_dup(orig
->header
);
1065 dup
->body
=ogg_buffer_dup(orig
->body
);